I would love to see programming as a dialogue between user and computer (programmer and compiler). For example:
Compiler would infer the types, and the programmer would read it and say, oh, I agree with this type, but I disagree with this type, that's perhaps wrong, this should be rather that type. Then the compiler would infer types again, based on programmer's incremental input.
Data structure selection. Programmer would say I want a sequence here. The compiler would say, I chose a linked list representation. The programmer would look over it, and disagree, saying, you should put this into an array. And compiler could say, look, based on measurements, array will save this much space but list will be this much faster.
Code understanding. Programmer should be able to say just, I don't know what happens here, and the compiler would include some debug code to show more information at that point.
Or take refactoring. Programmer would write some code, computer would refactor it to simplify it. Then programmer would look over it, and say, no, I rather want this, and don't touch it, and he would perhaps write some other code. The compiler would refactor again...
But all this requires that there is syntactically distinct way (so that perhaps editor could selectively hide it) to specify these remarks in the code, both for computer and programmer. So each of them should have a special kind of markup that would be updated at each turn of the discussion. Because you don't want to just overwrite what the other side has just said; both are good opinions (which complement each other - human understands the purpose of the code but the computer can understand the inner details much better). So, to conclude - I wish future programming language would include some framework like this.
Programming in Lean, Agda, and Idris have been quite a revelation in terms of interactive type system exploration. Granted, they can be flakey at times (Lean especially), but it's a tantalizing glimpse at what could be around the corner. Hazel[1] is also a pretty exciting look at advancing the idea of 'programming with holes', as is Isomorph[2]. Lots of exciting things around the corner!
> Programmer would say I want a sequence here. The compiler would say, I chose a linked list representation. The programmer would look over it, and disagree, saying, you should put this into an array.
To some extent, this is the promise of object-oriented programming, that in this particular instance has failed a bit in mainstream languages. It's true that in, say, Java, you have to massively refactor your code to switch between arrays and linked lists, because you use different syntax ([] vs. method calls) to access elements. It could be a bit better in C++ due to operator overloading; you could hide your actual container type behind a typedef, and as long as both container type A and container type B support the same operations with [] that you actually use, you can freely switch between them.
In Smalltalk, every container class derives from a single Collection class, and they have very very similar APIs. There you can, to a large extent, just program against the Collection API and not care much about the actual type of collection you have in your hand. You still have to choose one! The compiler won't do it for you, not in the way you envision. But the idea is that if you program against the generic API, then profile/benchmark your code, it should suffice to change a single line of the program to try a different representation to compare against it. (Of course some things won't work. You can't index into a set.)
Other dynamic languages should be similar, Python for example. But I think you have to work harder to achieve full genericity.
The types line is what some people do with Haskell, Idris. I do personally favor writing the large-scale types beforehand, because that gives the compiler a chance of saying "look, you program is wrong", what is way more useful than "hey, your program has this type". Besides, abstract-type driven programming is an incredibly good methodology where it's applicable.
On code understanding, what makes it better than the programmer inserting the debug statements themselves? It saves some misunderstanding from the computer's part.
On refactoring, some IDEs do that. I'm on the fence about its usefulness.
Thanks, I will respond to other people here as well.
I know a bit of Haskell and want to look at Idris, someday.
My point was, there should be a clean (best if even syntactic) separation between code itself (i.e. what should actually be done) and its properties (like types). Also, because there are two points of view about the properties (human and computer), this separation needs to be there twice (so for example, each type could be specified by computer and by human). I haven't seen a system that would do it, on a systematic level in the programming language. I only gave examples to show where it could be used.
You mean that types should reside on different files, and be inputed by different means?
Now I get the entire programming-compiler conversation. It is interesting. I can see some potential there. Yet, I shrug when I think about all the sparse metadata that I will have to check once I discover a low level bug (there is a reason I'm not programming in Smalltalk).
Somehow the best place for all that stuff to live is right there at the source code. That means the compiler (IDE) should be editing your files, so it better have a great integration with your version control system.
> Somehow the best place for all that stuff to live is right there at the source code.
That's what I am saying, and that's why it has to be syntactically distinct.
Also it needs to be clear what was input by computer and what was input by human, that's the second distinction. Because of how the conversation works. You don't want computer to erase human input, but the result also has to be logically sound. So you need to know both inputs for the comparison and synthesis, which happens at each conversation turn, both human's and computer's.
And that's what "type holes" and similar systems lack - they only record the result of the synthesis, not the two different opinions. Which is IMHO wrong.
I've been thinking a lot about nearly these exact same things. We desperately need better ways to deal with derived textual data. Why do we make the programmer guess which data structure will work best for a particular task, when we could easily try it each way and record the performance, and pick the best? A big part of the reason must be that we have no good strategy for storing that data and making that choice in an ongoing and living way, inside of a code repository. We suck at dealing with derived data on the meta layer above our programming languages.
Email me at glmitchell[at]gmail if you want to chat more about this.
I am curious if you've tried IntelliJ with Java or Kotlin, with the various mod cons applied? Because it's quite similar to what you're asking for.
Kotlin does type inference. You can see what the inferred type is if you enable inline type hints. It's not a part of the source code, but it looks as if it is (modulo styling). As you work with the code you can see the inferred type change in real time.
OK, data structure selection, it won't help you pick between a linked list and an array. That said, I'm not sure that feature would bring much benefit to most programs. You almost always want arrays.
Code understanding: if you're unsure what's going on at a particular point, you can just add a breakpoint and run the program. You can then explore the contents of the program, evaluate arbitrary expressions, you can add "evaluation breakpoints" that print out the values of those expressions without stopping the app (on the fly ad hoc logging, in effect), you can investigate how the code you're looking at relates to other code, what the data flows are, what the location in the type hierarchies are, etc. There's a lot of ways to look at the program.
Refactoring; this is the point I went down this train of thought. Because a modern advanced IDE like IntelliJ can do this sort of thing already. It can do things like spot code duplication and fix it for you by extracting a method, in real time, with a single keypress triggered by subtle visual hints like a soft wavy underline. It can convert code between imperative for-loops and functional pipelines of map/filter/fold/etc, in both directions. It can identify and automatically delete unused variables, function parameters, object properties and so on. "Simple" is somewhat in the eye of the beholder, but it's a pretty close realisation of what you seem to be asking for.
The dialogue is not had through markup in the code but rather, through the IDE giving its suggestions using visual hints, and the user starting an interaction through a keypress that brings up a menu of suggestion options ("intentions"), which may in turn lead to more options and so on.
> Compiler would infer the types, and the programmer would read it and say, oh, I agree with this type, but I disagree with this type, that's perhaps wrong, this should be rather that type. Then the compiler would infer types again, based on programmer's incremental input.
This is possible today, at least in Haskell. (and I'd guess in OCaml too ... surely also Scala?)
Your proposal for adaptive data structure selection based on benchmarking is intriguing!
Compiler would infer the types, and the programmer would read it and say, oh, I agree with this type, but I disagree with this type, that's perhaps wrong, this should be rather that type. Then the compiler would infer types again, based on programmer's incremental input.
Data structure selection. Programmer would say I want a sequence here. The compiler would say, I chose a linked list representation. The programmer would look over it, and disagree, saying, you should put this into an array. And compiler could say, look, based on measurements, array will save this much space but list will be this much faster.
Code understanding. Programmer should be able to say just, I don't know what happens here, and the compiler would include some debug code to show more information at that point.
Or take refactoring. Programmer would write some code, computer would refactor it to simplify it. Then programmer would look over it, and say, no, I rather want this, and don't touch it, and he would perhaps write some other code. The compiler would refactor again...
But all this requires that there is syntactically distinct way (so that perhaps editor could selectively hide it) to specify these remarks in the code, both for computer and programmer. So each of them should have a special kind of markup that would be updated at each turn of the discussion. Because you don't want to just overwrite what the other side has just said; both are good opinions (which complement each other - human understands the purpose of the code but the computer can understand the inner details much better). So, to conclude - I wish future programming language would include some framework like this.