The queryable expression thing is something I struggle with all the time in Rust. It's especially bad in that language because (unlike in e.g. Java or C#) there is no way to view the Debug representation of your types in the debugger, you just get the raw memory layout which adds a huge barrier to 'what is going on with this code?' and requires you to dig around through countless nested layers to understand it.
I also find this super annoying. In C++ land, Microsoft solves this problem by having "natvis" [0] files which allows you to have custom representations of complex & deeply nested objects. Unfortunately, most third-party debuggers don't support it. And like you said, any non-trivial program in Rust is basically not parsible without digger though 50 layers of nested abstractions.
What I'd really like is an IDE that functions on objects of code and not text files, and diffs and merges thar similarly operate on the syntax tree of the code and not on whether there's an extra newline or not.
Like, code formatting, that's just an implementation detail. Why can't there be a thing to let two people edit the same repo with different formatting preferences without it causing merge conflicts?
Maybe you're already aware of it, but there is difftastic [0], which is a syntax aware diff tool that can also be used with git. Its understanding of syntax is based on treesitter, so it works for most languages. Although I haven't tried, I think most IDEs should also be able to use it.
I think treesitter is getting us closer to this goal. Many programming modes in emacs now support treesitter, allowing syntax-aware movement operations, code folding, etc. Even where modes haven’t been set up, you can call “treesit-explore” I think for any language for which you have a grammar available and get an outline of the nodes.
Hopefully we’ll continue to see adoption in this space, as it makes it much easier to add syntax highlighting and other basic support for new languages, and it makes it so that any new functionality that operates via treesitter should work with minimal modification for any language.
This is essentially the concept of a "text object" from Vim. Historically, it was somewhat challenging to actually define text objects with the richness of behavior one might want, but now with Tree Sitter and LSP you can have this pretty much for any language or file format.
related to this: I want structural editing for non-lisp languages so I don't have to deal with measly lines of code, but with entire trees and branches.
I feel that the problem is not text but language design. A great language should be close to a pareto optimum for both human and machine legibility. Most languages are optimized for human familiarity, which is definitely not the most machine readable format and probably not the most human readable (in a platonic sense).
Being more specific, most languages, in my opinion, are far too permissive with whitespace and use too many keywords. The former leads to there being no canonical form of the program text and results in reliance on external formatting tools, when the compiler could be just automatically enforcing canonical formatting rules. The latter makes it hard to distinguish between types of words, which is why it is almost necessary to rely on syntax highlighting.
If each program has a unique canonical form, it would be very hard to beat text based diffing on that form. Lisp is quite good from the diffing perspective but weaker on human legibility (for most humans).
Tooling that enforces strict whitespace/formatting rules is a huge pet peeve of mine. It breaks my iteration flow because I have to stop thinking at whatever abstraction layer I'm working at to deal with the minutiae of formatting. I dislike automatic reformats as well, for much the same reason I hate webpages that jump around after loading. Just let me see the code I'm writing without it whizzing off onto adjacent lines because I'm going back and forth over column limits.
The helix editor [1] allows you to navigate and select code objects, I use Alt-o all the time which expand the current selection to the parent syntax node. As mentioned by sibling comments, there are also a bunch of diff tools that are syntax aware instead of operating on plain text. All of these are backed by tree-sitter.
Hmmm, these are kind of boring? I've seen colored comments a few times, embedding images is also possible in Dr Racket and on TempleOS I'm pretty sure.
Where's all the fun stuff? Debugger features are neat, but outside of this these features just seem tiny and cute and not too exciting.
Even stronger support for structured Treesitter-based editing? (See eg. Helix), proper multicursor support (Helix), both already seem like black magic to me compared to what came before.
I frequently use it when I need to make some structural changes to consistent code (block replace function name x, add trailing commas, etc). Not sure what more power I am missing.
One of the most powerful features of eg Helix is the ability to very smoothly and easily filter inside your existing selections, or to split them.
I think the focus here is on "selections", as opposed to just "cursors".
So for example, you can select all occurrences of X (say, usage of some global variable), then say "for each of these selections, select the whole function", and then say "select the name of the function".
And bam, this is a (somewhat artificial and forced example), but you assembled a list of all functions with a specific property in a few button presses without ever leaving your editor. This is very close to stuff I do all the time in Helix. This is a godsend when it comes to manipulating (for example) a huge array of JSON data.
Maybe this is all obvious to you, but this seems like the kind of thing that probably still feels like black magic to a lot of programmers, and which certainly hasn't reached all editors yet (most are not focusing on selection editing as a first-class usecase).
All of this stuff makes me go 'that should be possible in Emacs', with the exception of colouring tagged comments, which I think is possible in Emacs. I think that ghost/replay thing is possible using Sly and iterating through objects is possible in Slime and Sly.
I often use `hi-lock-symbol-at-point` and related functions for colouring stuff ephemerally, you can persist them if you find something that you need all the time. Extensive guide at https://www.masteringemacs.org/article/highlighting-by-word-... (and of course many packages that expand on this).
iimage-mode does the image thing
Let me know when you implement commit masks in magit, that sounds handy :-)
In addition, Vim does it by default for many filetypes. And it's easy to add for ones that don't. Other editors/IDEs probably also have it – overall I'd say it's a common feature.
I use "Todo Tree" in VS Code which is one of my mandatory extensions wherever I go. Super useful for not only tag highlighting, but as a general bookmark system inside the codebase.
Your IDE likely supports changelists, Jetbrains by default or VSCode through an extension. I always create a changeList for local which doesn't get committed and even persists across branch switching, and as it's still partially in your git view I'd argue it doesn't hit the authors problem of forgetting the changes you made locally.
these are already done or boring (colors comment tags both emacs and nvim do), depend on language spec (images in comments would really depend on the lang spec), depend on language runtime spec and debug info (searching through memory for some struct, replay), or just see lame or do not apply to most languages (commit mask - this might be partially doable at the git level).
I believe Commit Masks are actually a bad practice.
I am huge fan of having a EC2 machine in AWS and using VSCode remote SSH or anything similar for development. There are so many differences between cloud and local, that you either embrace it (develop in EC2) or try to wrap it into one more layer or abstraction (hello Docker) and still fail.
This is harder than it seems. However I have seen vscode users use `rr` recordings to even step backwards from a breakpoint. But it is gdb-based (i.e. not very platform independent) and is not displayed in a "ghost" like manner which would be neat. I think the first step is for runtimes to get better at recording replays.
I often do it somewhat in Java code, by dropping the current frame/stack, and then going into it again fresh. As long as most code is written without sideeffects, it's very powerful for fast iteration combined with hot swapping code changes.
After three decades in software development I can happily say that I can’t remember the last time I was stuck chasing data in some abstraction hellhole. It’ll never seize to amaze me just how much self-flagellation OOP enjoyers are willing to endure. I’m not sure I’ve ever even seen an abstraction chain go as deep aw the example in the article. Maybe in one of the projects I sometimes review when I do my side gig as an external examiner for CS students. Don’t get me wrong, I spent almost 5 years with the debugging tools in Visual Studio enterprise or whatever the ludicrously expensive version was called 10 years ago. These days I’m typically rocking some sort of console print while I hack away in nick with almost no debugging tools like a total psychopath. The main thing that has changed for me is that I almost never do abstractions, because, well, because you’re going to spend: “ intense hour-long debugging session only to realize you KNOW that some piece of data exists SOMEWHERE IN MEMORY”.
That being said, a lot of people are going to disagree very passionately with what the very opinionated paragraph I just wrote. So I think it’s fair to point out that I actually think the author brings up some very good points that IDE makers should take notice of. Well maybe not the TODO part… If IDE’s should do anything about TODO comments it shouldn’t be giving them a different colour, no, it should refusing to save them.
It seems you have a very different idea of what abstractions are than I.
Abstractions as i know them are everywhere. Even little kids use them all the time. Grouping 7 digits and tagging them with the type "phone number", "number" or even "set" is an act of abstraction.
Any type of data that you want to represent anything, needs a structure. Structures are abstractions.
That said, i find using prints as a debugging tool often very handy. Especially when you want to see the effective order and nesting of sequences (for example communication protocols in action)
I also don’t like OOP, but what does that have to do with digging through a large data abstraction? Sometimes it’s unavoidable, and the problem your solving naturally lends itself to a recursive data structure that ends up being very deep (basically any kind of tree data structure). A query language would be great for that, and trees are very common in all code, regardless of paradigm.
The Ghost/Replay might have security implications. Often the objects in memory might contain sensitive information (secrets or just customer data). During a debugging session you are likely aware of that. But IDE saving the data beyond your control increases the risk for a leak.
Similarly what they called Commit Masks seems like an invitation for putting passwords into source code, which is a bad idea. Even if done just to check things real quick.
I would like an IDE that saves files in a consistent format but displays the code in whatever style the user prefers. This shouldn’t be hard to do and would help version control a lot.
There's no reason we even have to work on "files". An IDE should be able to show you a module, or function, or call tree, or data dependency graph, anything!
There's so much to be improved in this area.
The only feature in this dimension I've seen is jetbrains injected language editor, where you can edit a string as it's own language thingy.
Mature IDE's already customize the presentation of things like annotations or comments, inject inline hints, and provide alternate editors for things like XML, markdown, or established UI description formats, etc
Imagine you like two spaces and I like four spaces for indents. With the above idea we both get what we want, locally you see two spaces and I see four, and there's no diff for indents whenever one of us edits a file. Similarly for any other formatting preference.
Spaces are just an example to demonstrate the idea. You could apply the same logic to braces, whether curlies are on their own line or not, whether there are spaces between some delimiters or not etc. The idea is that specific formatting doesn't matter, anyone could use their own personal preference because the AST behind it is the same.
That could be hacked together via some git hooks in theory, like, apply code formatter with your preferences on checkout, apply shared code formatter on checkin. But it's probably more complicated than that.
Saving files as syntax trees instead of code files / ASCII might also do that, but that's a level of abstraction nobody is ready for yet, because you need a tool that can translate to readable code everywhere. It kinda reminds me of EXI, a proposed XML transfer protocol that wouldn't bother translating the document to a readable text format but just transfer as binary, a set of 'events' like the SAX parser approach to achieve much more efficient transfer. I don't believe it ever took off though, it was conceived when JSON quickly became more popular. It was only mentioned once on HN [0] 13 years ago, with one point and zero comments.
A while ago I talked with someone who was working on clang-format and they said they tried this (at Google, I think) and the results were not good: they found people write different code depending on the format. For example, code written to fit in 120 columns but then formatted to 80 columns will look worse than code written for 80 columns, due to minor variations in verbosity and variable names and what not.
I notice this myself a bit when I switch from a fullsize monitor to a laptop screen.
I was thinking about the commit mask thing recently but imagining it as a part of Git, or an extension.The project I'm on at the moment is a big legacy codebase that requires a bunch of dev-only code changes for:
- functionality (setting API urls; forcing certain screens to appear; overriding config values that come back from an XHR)
- quality of life (skipping delays; turning sounds off)
It would be great to be able to toggle and mix and match these patches locally without risking committing them. A combination of stashes and branches kind of works, but the ergonomics isn't great, especially when there are conflicts.
I do this all the time in IntelliJ/JetBrains based IDEs, using the "changelist" functionality. I have "shelved" different patches I can bring forward, and they each appear in their own changelist. When committing it's from the main changelist, so never accidentally included.
When I make some change for local dev only, I always press the "diff markings" in the margins of the file, and there select that it should go to my "local dev" changelist and not be a part of main.
This is a bit similar to git -p, but the devex is much smoother.
Future IDEs will be IDEs that (will try to) understand what the code and developer is trying to do. Clippy, but more like a smart and fast butler who only needs half a word to understand where you want to go.
My feeling is that such feature will whipe away a big chunk of existing and today's desired features.
There needs to pe a standard that all editors understand. Propriatory answers like emacs don't count as some of us do not have the same editor religion.
Personally, I use markdown for comment content, not that IDEs do much with it, at least Markdown supports images with the `` syntax.
I think I've seen some tree-sitter grammars actually define injections such that their comment are rendered with markdown (but now I can't figure out where I saw that, maybe one of the Zed specific ones).
Kind of surprised speed isn't listed in here or caching.
It annoys me to no end when auto-complete stops working as it waits on rust-analyzer to finish. Like you had a completed run before; just use that information while you re-compute it!
To make sure i don't push temporary local changes to production, I used to have a github workflow that rejected code that contained the word "TODO" or "console.log". This way, i could add TODO comments that actually need to be done before deploying. Now i'm usign github less but my deploy script does the check, and you can probably make a pre-commit hook with this, or pre-push
Commit masks remind me of that time I couldn't run a Java app because it assumed a specific classpath order, but the classpath order is random on each boot, and my randomized classpath makes the app crash.
I've also seen some development teams rely way too much on IDE plugins to get anything done. Horrible software architecture with a 45 minute start-up time, I shit you not. They paid a shitload of money on software licenses for a special JVM/IDE plugin combo that allows them to hotswap almost everything to avoid ever having to restart the app during development.
Oh, it's also pretty much impossible to launch the development version of the app with a stock IDE due to the sheer amount of runtime code modifications from IDE plugins the development version depends on. Great times.
Could you elaborate on the class path order issue?
I can think of pathologic cases where multiple jars contain the same class but only one version is the right one, but how can something like that happen in practice?
A custom modding framework that patches code at runtime to dodge legal issues of binary patching, or more accurately shift the legal issues from us to end consumers. Companies don't pursue end consumers for things like that, or so I heard. Either way, problem was that the modding framework and the app itself shared a couple of libraries. Our modding framework used features of newer versions of libraries, features that the app with outdated libraries didn't have. Sometimes, the class path order put older versions of libraries first, causing the modding framework to use a class, function, etc. that doesn't exist in that version of the library yet. This rarely was an issue since most libraries didn't change much from version to version, but the class path lottery did have a few uncommon combos that made the app crash until you restart your computer.
58 comments
[ 3.0 ms ] story [ 115 ms ] thread[0]: https://learn.microsoft.com/en-us/visualstudio/debugger/crea...
Like, code formatting, that's just an implementation detail. Why can't there be a thing to let two people edit the same repo with different formatting preferences without it causing merge conflicts?
We really lost so much when we moved away from s-expressions in favor of... whatever adhoc stuff we do right now.
[0] https://difftastic.wilfred.me.uk/
Hopefully we’ll continue to see adoption in this space, as it makes it much easier to add syntax highlighting and other basic support for new languages, and it makes it so that any new functionality that operates via treesitter should work with minimal modification for any language.
something like this for Python: https://shaunlebron.github.io/parinfer/
Being more specific, most languages, in my opinion, are far too permissive with whitespace and use too many keywords. The former leads to there being no canonical form of the program text and results in reliance on external formatting tools, when the compiler could be just automatically enforcing canonical formatting rules. The latter makes it hard to distinguish between types of words, which is why it is almost necessary to rely on syntax highlighting.
If each program has a unique canonical form, it would be very hard to beat text based diffing on that form. Lisp is quite good from the diffing perspective but weaker on human legibility (for most humans).
Wasn't that one of the original ideas behind Light Table?
[1]: https://helix-editor.com/
Where's all the fun stuff? Debugger features are neat, but outside of this these features just seem tiny and cute and not too exciting.
Even stronger support for structured Treesitter-based editing? (See eg. Helix), proper multicursor support (Helix), both already seem like black magic to me compared to what came before.
I frequently use it when I need to make some structural changes to consistent code (block replace function name x, add trailing commas, etc). Not sure what more power I am missing.
I think the focus here is on "selections", as opposed to just "cursors".
So for example, you can select all occurrences of X (say, usage of some global variable), then say "for each of these selections, select the whole function", and then say "select the name of the function".
And bam, this is a (somewhat artificial and forced example), but you assembled a list of all functions with a specific property in a few button presses without ever leaving your editor. This is very close to stuff I do all the time in Helix. This is a godsend when it comes to manipulating (for example) a huge array of JSON data.
Maybe this is all obvious to you, but this seems like the kind of thing that probably still feels like black magic to a lot of programmers, and which certainly hasn't reached all editors yet (most are not focusing on selection editing as a first-class usecase).
iimage-mode does the image thing
Let me know when you implement commit masks in magit, that sounds handy :-)
He mentions Jetbrains let you do this. I do it in vscode using the TODO Highlight extension.
[0]: https://marketplace.visualstudio.com/items?itemName=Gruntfug...
The rest. Sure, fine. Don't really care.
I am huge fan of having a EC2 machine in AWS and using VSCode remote SSH or anything similar for development. There are so many differences between cloud and local, that you either embrace it (develop in EC2) or try to wrap it into one more layer or abstraction (hello Docker) and still fail.
This is harder than it seems. However I have seen vscode users use `rr` recordings to even step backwards from a breakpoint. But it is gdb-based (i.e. not very platform independent) and is not displayed in a "ghost" like manner which would be neat. I think the first step is for runtimes to get better at recording replays.
That being said, a lot of people are going to disagree very passionately with what the very opinionated paragraph I just wrote. So I think it’s fair to point out that I actually think the author brings up some very good points that IDE makers should take notice of. Well maybe not the TODO part… If IDE’s should do anything about TODO comments it shouldn’t be giving them a different colour, no, it should refusing to save them.
Abstractions as i know them are everywhere. Even little kids use them all the time. Grouping 7 digits and tagging them with the type "phone number", "number" or even "set" is an act of abstraction.
Any type of data that you want to represent anything, needs a structure. Structures are abstractions.
That said, i find using prints as a debugging tool often very handy. Especially when you want to see the effective order and nesting of sequences (for example communication protocols in action)
Similarly what they called Commit Masks seems like an invitation for putting passwords into source code, which is a bad idea. Even if done just to check things real quick.
There's no reason we even have to work on "files". An IDE should be able to show you a module, or function, or call tree, or data dependency graph, anything!
There's so much to be improved in this area.
The only feature in this dimension I've seen is jetbrains injected language editor, where you can edit a string as it's own language thingy.
Mature IDE's already customize the presentation of things like annotations or comments, inject inline hints, and provide alternate editors for things like XML, markdown, or established UI description formats, etc
Saving files as syntax trees instead of code files / ASCII might also do that, but that's a level of abstraction nobody is ready for yet, because you need a tool that can translate to readable code everywhere. It kinda reminds me of EXI, a proposed XML transfer protocol that wouldn't bother translating the document to a readable text format but just transfer as binary, a set of 'events' like the SAX parser approach to achieve much more efficient transfer. I don't believe it ever took off though, it was conceived when JSON quickly became more popular. It was only mentioned once on HN [0] 13 years ago, with one point and zero comments.
[0] https://news.ycombinator.com/item?id=2312746
I notice this myself a bit when I switch from a fullsize monitor to a laptop screen.
- functionality (setting API urls; forcing certain screens to appear; overriding config values that come back from an XHR)
- quality of life (skipping delays; turning sounds off)
It would be great to be able to toggle and mix and match these patches locally without risking committing them. A combination of stashes and branches kind of works, but the ergonomics isn't great, especially when there are conflicts.
When I make some change for local dev only, I always press the "diff markings" in the margins of the file, and there select that it should go to my "local dev" changelist and not be a part of main.
This is a bit similar to git -p, but the devex is much smoother.
My feeling is that such feature will whipe away a big chunk of existing and today's desired features.
I think I've seen some tree-sitter grammars actually define injections such that their comment are rendered with markdown (but now I can't figure out where I saw that, maybe one of the Zed specific ones).
It annoys me to no end when auto-complete stops working as it waits on rust-analyzer to finish. Like you had a completed run before; just use that information while you re-compute it!
I've also seen some development teams rely way too much on IDE plugins to get anything done. Horrible software architecture with a 45 minute start-up time, I shit you not. They paid a shitload of money on software licenses for a special JVM/IDE plugin combo that allows them to hotswap almost everything to avoid ever having to restart the app during development.
Oh, it's also pretty much impossible to launch the development version of the app with a stock IDE due to the sheer amount of runtime code modifications from IDE plugins the development version depends on. Great times.
I can think of pathologic cases where multiple jars contain the same class but only one version is the right one, but how can something like that happen in practice?
Vmax? Yeah that sounds kinda cool actually.