3 ms·
>If the primary representation of every programming language was data, [...]. When the programmer wants to modify code, render it into a textual representation.
by jasode 10y ago
>If the primary representation of every programming language was data, [...]. When the programmer wants to modify code, render it into a textual representation. When they’re done, parse it back into nice, inspectable data.
I see several problems with this:
1) human behaviors: you want the ultimate "Source Of Truth" to be the code-as-data structure instead of the text but programmers would eventually just shift the SOT to the "rendered text" because it's easier to work with. Friction for editing is a big deal. A similar behavior happens with database Stored Procedures where programmers use external "schemachanges.sql", "tabletrigger.sql", etc for source code revision control. The db engine's "source of truth" of that code is an internal blob but that's not visible to Git/emacs/vi/Notepad++/etc.
2) work-in-progress code is often broken and can't be parsed: E.g. the parser stops at a missing semicolon or unbalanced quote and therefore, you end up storing a large unparsed string for text with parsing errors. If you have a 500 LOC source file where the first 20 lines was parsed but the last 480 was not, you might as well have left all 500 lines in the "rendered" text as the SOT. The ideals of maintaining a perfect round-trip from code-as-data --> code-as-text --> code-as-data ... is an illusion in this case.
Based on current macro trends of compilers exposing their parsing engine (e.g. clang, C# Roslyn), it looks like programmers would rather use "parsing as a library API to process normal text" rather than "code-stored-as-parsed-data to be rendered to text for editing".
- cormacrelf 10y ago> it looks like programmers would rather use "parsing as a library API to process normal text" Yeah. That code is stored as text hasn't turned out to be that much of a problem, when parsing it is usually quite cheap. Rust's `cargo check` (parse + type check + borrow check basically) runs in under a second even for large codebases. For ease of implementing editing/refactoring features, the author seems to want a standardised, poly-lingual storage representation for code. That sounds like... text. There is little else in common between all languages. The winning abstraction so far isn't the storage format, it's something like Language-Server which lives above a parser/semi-compiler and just works with symbols and filenames/line numbers/char spans. These are pretty much common to all languages. If you wanted all the benefits described, like one-line renaming operations in your SCM, you'd need to completely normalise the storage format into relational data structures. This would only really work for static languages, and would open you up to a heap of distributed systems problems: What is the true representation of a particular symbol? What if we both commit two symbols with the same ID, or two IDs for the same symbol? Nobody wants to need transaction support and SQL constraints for a file in Git. And think of how a one-line change like this: // main.rs + pub fn gimme_seven() -> Option<i32> { Some(7) } would add some entries in database tables all over the place: // symbols.json + { "kind": "function", "id", "d3c42d4d-9df6-43a0-97a0-147fe8e52a2d", "name": 'gimme_seven' ... }, // main.json // { exports: [ ... + { "id": "d3c42d4d-9df6-43a0-97a0-147fe8e52a2d", "visibility", "public" } Using fully-denormalised text is the only reason SCM works in the first place. Programmers suffer boundless pain just trying to get computer-generated (usually XML) config files to play nice in shared repositories, and I'd never wish the same upon anyone trying to write actual code.