And then I want to put rich things into my comments section like graphics and tables and such. And I don't want to have to write table-like Markdown or a shorthand that converts into graphics. I want all the WYSIWYG of Word or PowerPoint or Inkscape just right there feeling 100% natural and native.
Jupyter is pretty darn close to this. And I like it a lot. But I feel like I'm giving up a lot to make a notebook. I want this in a much more heavy lifting format.
WYSIWG is what you get, but not what you want. Anyone who has done serious work in Word, or some other WYSIWG editor has got to the point where the document becomes FUBAR, and you have to copy the plain text, and start again with a new document.
That is not acceptable for a programming environment. Copy an paste is the enemy of correctness.
I'm sorry but, speaking from experience, that is just not true in all cases. Granted, it takes a certain kind of methodic work (and more know-how of the tool than would be reasonable) to work around many of the problems but if you put in the time to learn, Word (and similar software) is more than adequate for large-scale editing work.
It's no wonder the absolute majority of people use it; the learn how to avoid the problems (or live with them) and there is near zero incentive to personally switch. The majority of the onus is paid by the next batch of people who have to learn it.
I'll also agree that it's not what I want for comments and that better models exist for 90% of all text-editing tasks out there. But it does work
Things I've seen fail with Word in my career that would be unacceptable for programming:
- Relatively simple docs being eaten alive, as described in grandparent comment, after several dozen authors make small edits over the course of a few weeks.
- Complete change-tracking disasters when attempting to merge concurrent edits to different parts of a document by several authors.
- Docs where the WYSIWYG behavior completely changed when opened 5-10 years later by newer versions of Word. Attempting to import/export/save as to rescue it involves much of the same cut-paste and hand recovery described previously.
- Docs destroyed by international collaboration, where different locales of each editor seem to accumulate contradictions in the saved document over time.
- Inconsistent WYSIWYG between Word on Windows and Word on Mac OS.
I don't think it is responsible to promote a programming language that does not have a tooling-independent and platform-independent textual representation that carries ALL program semantics as manipulable, printable character sequences. That promotes disposable code and prevents real programming in the large.
(edited to try to rescue bullet list)
Nothing stops you from allowing the user to access the document itself to clean up the automatically-created mess.
It should be more like the XML/visual editing modes of .Net platform UIs.
'canonical view' is raw markdown/tex/whatever with text-editing controls. WYSIWYG view is presentation style with rich text editing controls.
this paradigm could carry over to the code itself with projections omitting/adding type annotations, comments, in-lined documentation, maybe even selectively expanding/eliding parts of the code itself i.e. orthogonal aspects like logging
Sorry. Code is code, that's what your job entails and you can't make programming into something it isn't.
You could replace the subject of your comment with, say, "automatic garbage collection", and it would have been equally true ("that's just what your job entails!"), right up until GC made its way into the first mainstream languages, and it very quickly became a tool used by almost everybody.
Holdouts remain in the high performance, embedded, and deterministic areas of software.
The idea is older than structured programming, older than the C programming language, older than the idea of object-orientation. It's probably even older than McCarthy's LISP.
Safe to say that if it hadn't caught on during this time, then it never will.
It's easy to be parochial about this when Unix like environments force everyone into a lowest common denominator of text streams, but don't take the limitations and bad ideas of Unix as laws of the universe.
Summarizing the list of non-text mode programming languages in general use that people have mentioned in this thread:
I don't remember how or if people kept the shadow comments lined up with code (I was only there for one summer in high school), but you could extend the editor with ease, so...
Traditionally a block was 64x16 I think (1KB).
I used noweb at a previous employer, and it certainly was difficult to argue with the results; beautiful, readable documentation that existed as a first-class product, alongside the code it was describing. The quality of the software we generated was the highest I've ever seen in terms of things like deadlines and budgets and bugs and testing.
Why would this require a new language? And why would it require a new editor?
For one thing, at a certain scale, code and documentation are examined in a browser more often than in an editor.
Your requirements seem too focused on insignificant details and not enough on the big picture.
Compiliation for an editor (partial/incremental) is a very different beast from "normal" compilation, and any compiler that is first completed for regular compilation and then tries to address tooling as an afterthought, will ultimately never be useful in tools.
I realize writing a new compiler is hard enough in itself, but projects like the Roslyn poject shows it's at least feasible to make a compiler-as-a-service with both regular compilation and tooling in mind.
I completely agree. A few things I think would help with this:
1) Provide a standard "machine readable" concrete syntax for the language, alongside any "human readable" syntax. S-expressions would work well for this; if someone prefers JSON or XML then I won't argue. The implementation (compiler or interpreter) should have a mode which converts the human syntax to the machine syntax. The compiler/interpreter should handle inputs in either format. This avoids tools having to parse human-readable formats (or worse, run arbitrary preprocessors, etc.), and makes it easier to feed auto-generated or modified code into the system (e.g. for type checking, etc.). Machine-readable formats are also be more robust, since everything's delimited in a standard way, so unknown things (e.g. new language constructs) won't mess up the parsing of everything else, making tooling easier (e.g. linting, documentation generators, etc.). Note that Lisps and Schemes have this already, by virtue of using a machine-readable language as their human-readable language. Others can maybe just serialise their parser's output (as long as it's concrete, not abstract).
2) Allow arbitrary metadata to be attached to pieces of the syntax tree (in both formats). This can be used for comments, but also for source location (e.g. if it's been translated from the human-readable format, or maybe even transpiled from something else). The parent's desire for graphics, etc. in comments could be handled by such annotations, since they're data not just ignored bytes, so they could have e.g. entire Scribble documents attached. Tooling can use this for any data they like, e.g. hints for static analysers, dependency information, required language version/features, blame information, optimisation hints, etc. I think Clojure already allows this, but I've not used Clojure.
3) Keep context/configuration close to the code, or at least allow it to be. For example, if the meaning of some code changes depending on language version, it should be possible to specify the language version as part of that code. That way, tooling is able to obtain and use that information. This could use the annotations from (2). The worst case is when crucial information (like language version, or which arbitrary program to run as a preprocessor, etc.) is kept in some external configuration file, in an arbitrary location, in some bespoke file format, such that no other tooling can make sense of the code (I'm looking at you Cabal!). Even if we want separate config files, the tools which handle them should be able to resolve and propagate that information into the code, e.g. we could ask `tool annotate src/foo.lang` to get a copy of `src/foo.lang` which any relevant context/metadata from the config file appended as a file header. IDEs can use this to get more info about the files they're editing, and propagate that info into the snippets they send into the implementation for type-checking, etc.
to top it off, it had the potential for that already since its inception. so not exactly a new paradigm
I don't like init functions; an object should know from its inception the basic things it needs to in order to function, and I think it's a great miss there is no real way to force this.
Sorry, I should've been clearer there. I meant constructors.
> can you give an example of how an init function is used to do something that an object should already know?
The only way to instantiate a new version of an object in Pharo is with the new message to the class, for example with
aDate := Date new
aDate := Date year: 2015 month: 12 day: 31
However, the method 'new' can still be used (there is no access modifiers in Pharo), so it's still possible to call an object without ensuring it's initialized properly. I have yet to find a good way around this.
Implement the class's new method with an implementation that just throws an UnsupportedOperation exception?
and yes i agree, it should be possible to prevent the creation of uninitialized objects.
There's a thing for everyone, but that dystopian stuff you are describing here I cannot fathom even in my worst nightmares. The text file is a very powerful abstraction for programming and I hope it will never day.
It could take literate programming  to the next level. Existing tools like docco  can output beautiful documentation  with comments set alongside code. The language/editor described above would allow us to input code in the same side-by-side format.
Literary Programming, Programming was the first, Literary was the second.
the main purpose of the Code comment area markup method is to live Preview directly in the Code Editor Preview panel without exporting or any preprocessing.
Just add a line comment character of the programming language before each line of Markdown.
In the comments of code, you can draw flowcharts, tasklist, display data visualizations, etc.
The method is to add extension instructions in any programming language comment area:
manual eval code, live eval code, print result, display data visualization and other directives
When previewing or converting a format, you only need to simply preprocess: delete line comment characters with regular expressions, example: sed 's/^;//' x.clj
line comment character of Clojure(Lisp) is ;
line comment characters of the current file type can be obtained from the editor's API.
when we edit the code, we can preview the effect in real time. Editing literary code has a live preview panel like most markdown editors.
fast, live, simple, no interference.
It don't break the syntax of any programming language, you can compile directly. comment area markup method can be applied to any programming language and any markup (including Org,rst, asciidoc, etc.), which is the greatest advantage.
you only need a single line code to delete line comment characters using regular expressions, then you can use any Markdown parse or converter.
Support any code editor that supports Markdwon Live preview, allowing the source code of any programming language to become rich text in real time. In the code's comment area, You can use the markdown to draw flowcharts, tables, task lists, and display images on the live preview panel, enhance the readability of your code.
If you extend the Markdwon tag, you can implement the eval code, print result, display data visualization and other instruction tags, to achieve live programming, live test.
When writing (reading or refactoring) code files, It can modify and live preview directly in the editor without exporting or any preprocessing.
Reliable. Maximum code accuracy is guaranteed, and markup language errors do not affect the code.
It hasn't interfere anyone to read the code. Markdown is simple, so if it doesn’t have syntax highlighting, it doesn’t have much effect on writing and reading. And having a gray comment area doesn’t affect reading code, especially for people who don’t understand the markup language. Strict distinction between markdown and code, and gray comment area can reduce the amount of information in the source code file, conducive to reading code.
This specific bit reminds me of the elegant UX implemented in Typora. 
Check out Luna
If you haven’t tried a literate programming language, you might like it. You basically write a document with figures, etc. it is, with bits of executable code.
BTW, most of my coding in my last job was in Jupiter notebooks (to use Cloud GPU compute). Really not too bad for short ML scripts when you can still put slow changing library code you write in separate files. That said, not a great environment. I prefer configuring ITerm2 or xterm so I can get matplotlib plots to appear inline in SSH sessions.
Block oriented Forths used to use "shadow blocks" for documentation. You had a block that was code, and a fixed offset to a corresponding block that was documentation, with a keybinding to switch between them.
Various tidbits of this have been done in Smalltalk (of course).
But if you have already invested in a world of tool chains that assume ASCII or Unicode text streams as source code representation, then it's hard to get out of it.
Your comment also reminded me of Godot's editor and gdscript. It's fairly domain specific(though the editor is actually a godot game). Everything's designed to work with gdscript. The language and the editor are designed to work seamlessly together in much the way you describe.
Seriously, read the original "Design Principles Behind Smalltalk"  and it still sounds very fresh, even radical today.
They have a pretty friendly community too.
It's a dealbreaker if everybody working on the same project has to use the same editor.
Development practices that seem suboptimal for the individual are often optimal for teams. And teams develop all the major pieces of software we use.
I've seen that demo from JetBrains MPS, looks good. Hopefully it gets wide usage.
Then what you need is just a git blame(?) to visualize the current code section's comments.
Would this work?
Plus, you would end up in a conflict between recording history and recording the present. What happens if you replace a complex method call across a codebase? The comments should explain the call, but the commit message needs to record how the call changed, and why - which you probably don't care about when coding.
I do believe a lot of code would benefit from better built-in documentation, which it essentially is.
I Will think about this some more
Swift Playgrounds has rich comments, but they are still inlined with code.
I don't think people these days try to understand what are the building blocks of languages and computation.
I'd wager the true next generation programming languages will be ultra minimalistic languages, retaining only the essentials while not losing on legibility.
Lisp for example is still not minimal as it has 'special forms', ie. hacks to make conditionals work. The unintiutive prefix notation also doesn't help.
Also not many languages allow people to explore true powers of deeper stack modifications by delimited continuations. Using them the users would be able to create their own looping and threading constructs as well as custom exceptions and iterator mechanisms and effect handlers.
It's important to realize that the economic incentives for truly innovative languages are bleak. The academia is stuck in incrementalism. Private sector wouldn't pay for it and the benefits would only be collected by cloud vendors, adding yet another trillions to their valuations.
The concept of a "programmable" programming language is intuitively appealing, but in practice turns out to not be so helpful for actually shipping software. Everybody builds their own, incompatible versions of common utilities. This is why languages like Lisp or Forth are great for exploratory hacking with small teams but are very rarely used these days for larger scale development and lag far behind more mainstream languages in tooling.
What you really want is a tasteful "omakase" language design that gives you a carefully selected menu of building blocks that average developers can use to be productive. Languages like Kotlin and Swift are a good example of this. They cherry pick a lot of the good ideas from academic functional programming without going down the Scala/Haskell rabbit hole. Golang takes this to an extreme by providing native typed containers without exposing generics to the programmer.
The success of a language these days depends at least as much on the library ecosystem and tooling as it does on the language itself.
This has also been my observation, and that of many actual Lisp hackers I talked to. It also mirrors the experience the developers of Smalltalk documented: at first they had ultimate flexibility, every object could in effect re-define the language completely. Not so good.
On the other hand, we also seem to be stuck a bit in a local maximum of expressiveness that, to many including myself, seems obviously not expressive enough.
What if ... the idea of a programmable programming language is actually good, but the implementations have not been as useful as we thought?
I think what is missing is a good meta-model and a good "language library", for want of a better term.
With most programmable programming languages, you are basically given the "it can do everything, now have fun" treatment. So everyone has some fun, implements "their own, incompatible versions of common utilities" then realises this isn't quite as useful as it was thought to be and gives up.
Going back to OO, I would claim that most OO "languages" by themselves are somewhat useless. What makes them incredibly useful is their class libraries. It is of course the languages that make these class libraries possible, but that's a second-order effect.
In fact, Smalltalkers have the saying "Talk small, but carry a big class library" (repurposing "speak softly and carry a big stick, you will go far.").
For me, the most useful meta-model is the analysis of software into components, connectors and styles that the software architecture people came up with. It appears to capture most of the variations in how we build software and has a useful, empirically built taxonomy.
In this meta-model, the connectors pretty much define styles, so the "language library" I mentioned above becomes a "connector library" in actual usable artefacts. Interestingly, existing languages seem to be describable as a set of connectors, and the connectors are very much related, so this does seem to solve the problem of lack of guidance.
What production teams focus on instead tends to be the meat and potatoes aspects of libraries, documentation, build time, and debug time. A new user of Rust who writes C-like code can still benefit; they'll have to learn some things while fighting the borrow checker, and they may not have exactly the libraries they need(which can often be the showstopper) but their debug time will go down and their builds are likely to get simpler, if not faster.
It is true that we could use more syntax that explicitly deals with concurrency, but that's also the thing that we have little agreement on.
And incompatible implementations are not really exclusive to metaprogramming either. Pytorch, Tensorflow, Numpy and the Python standard libraries are not compatible by default, each has to deliberately create (or not) tools to convert from one type to the other (or build entirely on top of the other).
You can argue about the Lisp Curse, in which having a lower entry barrier to make your own tool makes it easier for each create it's own "perfect" one (which is flawed/lacking to everyone else), while languages in which the sunk cost is higher would make people gravitate towards something already created and improve it with their own use case. That's definitely true, but since that's something cultural then it can probably be handled in some way (for example deciding global common interfaces for interoperability, blessed packages for each domain and the most popular extensions of the language being promoted as official language feature after enough deliberation).
I know that if I had a few more hours a day I would try to write yet another of these things.
(Where is my cross-platform, OSX-Linux-Windows one-file text editor that just has smart indent and syntax highlighting for python?)
I know people are gonna protest this suggestion vociferously, but Emacs ticks all these boxes (except that it works for multiple files), with almost no configuration. Admittedly, getting auto-completion to work cross-platform for various languages is still quite tricky.
Just use vim? I mean, if the complexity of the projects you work with require access to a single file you might as well use _any_ editor that supports automated syntax highlights.
This is a fashionable idea, but I don't like it. Minimalistic languages rely on encodings, which are always far more expensive than using native features. Minimalism is fine in theoretical/academic settings -- fewer proofs to worry about -- but it's not great when performance matters.
which is easier for me personally, because the calls to the libraries are generally very much in keeping with the core language syntax, whereas the decorations can be very much a framework specific deviation. I can generally easily identify calls to libraries, whereas I cannot guess easily at the consequence of a particular decoration I have never encountered before.
* Moving towards representing code on disk as an abstract syntax tree, and anyone can edit with whatever syntax they prefer. Syntax becomes virtually irrelevant.
* The above point opens the possibility to represent code as visual graphs (even to code within virtual reality). Graphs and visual programming are useful, but to be able to toggle between textual and graph representation gives you the best of both worlds.
* Smarter compilers. For example: easy to use compile time constraints. Think about the ability to specifiy something like the minimum value an integer can be set to. This could allow the compiler to produce compile time errors for things like index out of bound errors, with zero runtime overhead. More complex constraints could be user defined. The mindset of programming could move to thinking about how you can do as much as possible at compile time.
* The ability to embed documentation alongside code. For most codebases the ability to understand the code is part of value of the code. Comments don't go far enough, particularly when working with visual concepts. Being able to embed readily accessible documention within the code could help dramatically.
This is probably a big mistake. Code must communicate ideas. Communication requires a shared language. A language has syntax, not just semantics. A given semantics has only a few natural expressions as syntax.
Can't pair program, can't program during a talk or a stream, etc. without that shared language.
If anything, we should be looking at the reverse of what you said: reading code is more important than ever due to the scale of programs, so we should be looking into creating the most readable language ever.
Edit: I think overloadable and definable operators can be very useful (like Haskell, OCaml), and that's probably as much syntactic flexibility as we need. Even this can be abused though.
I remember being very concerned about the performance of some Ocaml code that was overriding (* *) until I realised what it was doing :)
Not sure how to type that on HN!
Since I started using prettier with JS I hate switching to a language that doesn’t have it.
The actual representation of code is just as important as the AST in many cases. If it wasn’t then we would all just code in lisp.
This is probably a fiction for any reasonably complex language. Being able to view a C program in S-expression form doesn't solve any real open problems in software engineering, but it certainly creates some new ones.
I will do that now, thank you for reminding me of it again!
I can understand why there is such a focus on productivity, but I think it's awful for the industry when it's our number 1 priority. Productivity is meaningless if the thing that you are producing is of poor quality.
It's why we make web apps out of 500 npm dependencies when a native app would be faster and preferred by the user. It's why we use languages where we don't have to "fight against the type system" because we prefer writing code faster to writing correct code.
Again, I understand perfectly why this is the case. It just kinda makes me sad that we treat ourselves as garden hoses spewing out as much code as possible without as much thought into making a better product.
There's free food everywhere and we're complaining it's not gourmet.
Users almost universaly don't care. This also applies to businesses, C-levels and managers. However, while they don't care it affects them indirectly as they end up using bloated sub-optimal software possibly with bugs and sometimes significantly slower than in could be. It then affects their productivity as well.
My point is that one could at least try educating the non-IT decision makers why it's important. My team has successfuly convinced the CEO that 2 month long refactoring project is really important and that while it won't directly affect the functionality it will increase productivity of the our team in future by making the team more productive and allowing for faster implementation of new features in the future. From my experience the "technical debt" metaphor is great for explaining such things to business oriented people. That metaphor is usefull because it is compatible with other debt related metaphors, like interest rate or refinancing. We could explain extra time needed to implement stuff in non-refactored bloated codebase as an interest-rate.
Also, the use of car-related analogies is quite effective.
My point is that while users don't care about the technological intricacies, the effects can be explained by the use of metaphors and concepts that they know well.
People are used to very shitty software; non-tech people are just swearing at their screen but in a way like 'we cannot do anything about it anyway'. Almost all sites and apps are broken in many ways without even looking at usability/UX (a lot of time seems to be put in frontend and blingbling while the backend/logic is horribly broken in many ways).
Developers meaning in some circles; I know many corporate / enterprise devs that really pride themselves on committing (if they have version management.....) and producing as many lines of code as possible. Usually Java or C# or VB#.
That there are many alternative forms of computation, and that the inability to represent that form of computation in the host language leads to complexity and code bloat.
* constraint programming, logical, spatial, temporal
* lazy evaluation
* back tracking, memoization
* programming by example
* failure tolerant
Unfortunately it seems like most working programmers are deeply suspicious of new paradigms for producing programs. Understandably so, since all the "visual programming" tools up until now have been either teaching toys or unusable disasters, but I think we're limiting ourselves tremendously.
But it may not be possible to arrive at my glorious imagined future incrementally. It may take some genius just sitting down and working on this for years and producing a completely finished system to convince people of its capability.
Sorry this is a bit lofty and light on specifics. It's more a feeling that I have that it would be ridiculous if programming in 2100 looked the same as it does now, and not something I've thought about deeply.
Which makes you wonder why every single attempt to do this makes easy things trivial and everything else difficult to impossible.
Programming languages are (usually) tools created to help get things done. They're not (usually) there to make your life harder, or to force you to learn something. So why does it seem like that's the starting assumption to every alternative proposed?
(NOTE: If your scope is limited, it makes sense. Unreal Engine 4's Shader Blueprints are great, not only is the scope limited but the visual approach allows you to preview each step at a glance.)
I think part of it is, despite widespread acceptance of puns, most people seem to think English (or any other widely spoken language) is a lot less ambiguous than it really is.
There's a reason legal documents are the way they are as well. Granted in that field there is sometimes incentive to obfuscate your meaning, but I still don't think that's the reason for most of the difficulty in outsiders easily reading and writing legalese.
The fact of the matter is, expressing logic (or music) in words is hard. The more detailed you need to be, the harder it gets. That's why the example of making a sandwich comes up so often in introductions to programming. If people can't express in their native language how to do something they do every day, in an unambiguous enough manner for a "computer" to perform the action, that speaks to a deeper problem than the representation being too hard.
: It's not a great example, because the instructor usually is going to maliciously try to find any logic hole they can, making it feel more like a hazing ritual than a lesson to be learned. But it does come up a lot for a reason.
So maybe we'll be programming in a medium other than text, but I sure hope that's not the main advance that's made.
I'm also very fond of visual languages, so much so that I started collecting and cataloging all the noteworthy examples of them I came across in my research travels: https://github.com/ivanreese/visual-programming-codex
Yes, the vast majority of visual languages are uninspired and underdeveloped. But the same is true of text languages — look at Pascal or xBase or C++ templates.
Yes, it's possible to make a terrible mess in a visual language. But the same is true of text languages — we had to learn the hard way not to goto, not to do TCL style string-based metaprogramming.
When we think of the greatness of text languages, we're thinking of Idris and APL and Racket, not the Java you see on The Daily WTF.
When we think of visual languages, we should look for similar examples of greatness (modern Max/MSP is not a bad place to start), and not indulge in Blueprints From Hell schadenfreude.
- It's very close to the computer's "native language"; a raw series of bytes on disk can be stored and processed efficiently, and are analogous to the binary form, which has to be a series of bytes
- It's visually compact, so you can view a large amount of complexity per screen space
- It can be created and edited purely by keyboard. I'm not an anti-mouse zealot - I often use it when I'm going back and tweaking code - but nobody can deny that the keyboard is a faster and more direct way of getting new ideas out of your head and into the computer
I also think there's value in being able to get down to the baseline and see the "raw stuff" that makes up a program. Being able to see that full definition with no layers of indirection, even if you always use layers of indirection when actually working on it.
None of these are insurmountable, but I think they'd have to all be addressed by any true graphical replacement for textual code. Personally my vote is for a more fully graphical editor that still operates on textual code underneath, which can still be read by humans on its own.
I started introductory work in circuit design via a visual interface. You could drag and drop components, size them, connect them, and so on. I had to do quite a lot of work on the layout for even simple designs to appear comprehensible. There were just so many relationships, and crossing wires is so problematic that it's hard to provide high level detail or low level detail. You graduate to connecting things by names, then to a description language which is purely in terms of names.
Programming visualization struggles to remain comprehensible in view of the full complexity of the underlying system. I took a single variable, and tracked every function which interacted with this variable based on read or write relationships across a single (fairly top level) function call. The graph that I generated from this fundamental tree-like structure was unusably complex. After collapsing nodes appropriately, I could explore the graph to get some understanding, but no one that I shared this with understood how to use it. I don't know if this is argument for visual representations (since I used it to explore these relationships) or against.
Nevertheless, I see no reason why we need to draw such a distinction between a text-based specification and a visual one. We certainly can design a language-visual dual which is trivially isomorphic, so getting that system hardly requires a paradigm shift.
You give people a language which is very close to english, like Python, which is accessible to an even larger audience.
Thousands of packages get written just to make it even closer to english, even more plug-and-play.
At the level of Haskell, their comfy syntax means you need to understand the logical implications of literally everything you write. At the level of Python, their comfy syntax sacrifices control over performance. Both good syntax, both problematic.
I'm beginning to think you can't have your cake and eat it too when it comes to languages. Maybe you'd even want to make the argument that it's a good thing that languages are inaccessible to most people.
And considering blueprints spit out C++ once compiled, I'd take my chance with BP!
APL did away with English-like text and was moderately successful, but the high learning curve inhibited popularity.
What is missing are functional and descriptive languages.
No explicit loops? "heavily leverage parallelism, yet completely hide it"? lazy evaluation? This sound like functional languages.
"Example: An Interactive Graphical Application." describes HTML+CSS exactly.
I understand author really loves Datalog, but omission of other languages makes the message less effective.
I agree with your general comment, but this statement seems a bit optimistic on the functional languages side. Lazy-evaluation? Haskell does it, but most other functional languages don't.
Heavily leverage parallelism but hide it - this is often touted as an advantage of pure functional languages, but from what I've heard, in practice it has never panned out, at least if I'm interpreting it correctly as automatic parallelization. Turns out, while the compiler can prove it would be safe to do so, a lot of the time it would massively hurt performance, and the compiler can't tell when that is the case or not.
So, even in a language like Haskell, you still have to explicitly parallelize code, think about chunking etc. And if we stray from pure parallelism and into concurrency, all of the problems of having to do explicit synchronization come back, you just have less to worry about with no(/less) shared state.
Funny thing, one langauge that does 'leverage parallelism, but hide it' is x86_64 assembly, where the processor automatically executes (parts of) assembly instructions in parallel, based on data dependencies and available compute ports.
I suspect that future programming languages will either be garbage-collected or will have something like Rust's borrow checker. Nobody needs a new language with dangling pointers and buffer overflows. C++ is trying to retrofit ownership semantics, which is good, but has major backwards compatibility problems.
Indentation and code layout will be automatic. Either in the editor, or something like "go fmt". Nobody is going to put up with the indentation and the delimiters being out of sync.
Also, the ultra long lines of functional programming have to be laid out in some standard way to be readable.
Does each language really have to have its own build and packaging system?
- Tiered abstraction levels. I want to write high-level functional code when I can, which expands to more complex code under the hood. When I want to I can instead manually expand the logic, perhaps the only time I need to code imperatively. Think a project today that has high level haskell or python code but implements bits in C where necessary. For the highest level bits, things like formal verification, safe concurrency, code contracts etc should be much simpler to use. For the low level bits, I'd just take responsibility for correctness (memory safety, formal correctness, concurrency) myself (like "unsafe" in Rust/C#). Perhaps the number of abstraction levels should be more than 2.
- Integration of tools: 1) Today a compiler, editor and VCS are 3 different tools, and their lowest common denominator today is text files. I'd like to see a system that version controls a syntax tree for a whole project, and allows semantic diffing. A build server could trivially do incremental builds, moving a symbol doesn't break history, reliably running only impacted tests for a 10h test suite is possible. This doesn't necessarily mean everything needs to be one big tool - but the lowest common denominator of tools could move from UTF-8 files to a binary representation of the whole syntax tree. Having a more complex binary representation would have drawbacks but also other benefits like trivial inclusion of a picture in a comment that can be previewed with a mouse hover in the editor, or displayed inline. 2) Better integration with documentation and issue tracking. Same as the AST representation: we need to be able to link documentation, pictures, links to issues etc from code in a way that doesn't rot if we change directory paths, issue trackers and so on. A broken link to a document in a comment should be a build error like any other error.
The right way to behave in each situation based off of the input, the state of the system, or failures encountered is determined by history and by many people.
A language that makes my job easier solves problems like:
1. Help me describe my system as straightforwardly as the above description
2. Prevent me from neglecting to handle failure and reduce the work to specify how to handle failure
3. Prevent me from introducing logic errors. e.g. concurrency without synchronization, or passing an int where a string is expected.
3a. Help me verify that my solution does what I expect.
4. Make it easy to accumulate data and pass information through various interfaces.
5. Make it easy to extend behavior without modifying existing code.
Given that we probably spend 95% of our time plumbing information, handling failure, and reducing logic errors, an order of magnitude of productivity increase is realistic. Choosing an algorithm or data structure is less than five percent of time allocated.
Rich Hickey and Clojure seems to focus on people like me. Rust seems to focus on another subset of the challenges I face. One of the useful ideas I've encountered is that coding is a specification design process rather than a manufacturing process. We start with an ambiguous description and specify behavior in increasing detail until a computer can work with it. The article suggests that we can subordinate some of this detail to the compiler. The details that it chooses to subordinate aren't the details that disrupt my productivity.
The article assumes that as we get more productive at programming our time will be dominated by tests. While that's probably true, I would consider it important in this future world to minimize what tests need to be run and written. We do this today in Ocaml by making some classes of inconsistency inexpressible. We do this today in Rust by making some kinds of failure inexpressible.
This sounds like a dream for data analysis.
I've been typing programs for so many years I think we've gone as far as we could go with text, auto complete, live compilers, hot reload etc.
It wouldn't be that uncomfortable seeing a developer spends most of time reading / analysing and, god forbid, the open office would allow it (!@#$%^ noise): THINKING.
Here is a thought, want to make the future of programming languages? Remove distractions.
How will you search for specific things in a codebase (where did I assign this variable again?) without text?
Have you ever tried running "diff" on "graphical/flowchart" code?
It could theoretically be easier for the tools to identify exactly what changed and present that information rather than superfluous stuff like whitespace changes.
I believe that diff tools could be better if they operate on some format that represents the meaning of the code, not the details of how it's written. New tools would have to be written, so it's largely a matter of pragmatism and momentum that prevents such a thing.
FYI I googled "WebMethods Flow merge tools" and one of the more useful discussions actually featured you from 3 years ago expressing similar sentiment: https://news.ycombinator.com/item?id=12106945
Honestly - I would be happy to use a graphical (or any other alternative to traditional) language.
I was reasonably enthusiastic when I started working with webMethods and some things I like a lot.
But honestly I cannot say it scales well beyond simple transformations / mapping tasks.
and yes the diffing on Blueprints is very good, again, in UE4.
Outside of rails, ruby is pretty unpopular.
That said, I think the biggest way a language can help is by having a great library. Code I don't have to write is a huge productivity boost. An outstanding example (for its day) was the Java library. It was like Barbie - it had everything. And it was organized (and documented) well enough that you could find what you needed pretty easily.
For the language itself, I don't have any great answers. But I observe that many of the comments here focus on syntax. Syntax matters, but don't forget that semantics matter also.
I am doing 10×. It's possible.
Every class / any construct gets a test stub. The compiler collects information during debugging on test data and how the elements of the applications are connected and expands tests based on this information.
I think the non-professional programmer is a bigger market. That is, the person who uses spreadsheets or writes some simple scripts.
Another issue is readability by non-professionals. Executives may not need to write business rules but they ought to be able to understand them enough to sign off on their correctness.
I wouldn't use it to get the eigenvalues of a matrix though.
.. and I've tried to resist answering it and letting the question ferment instead.
Furthermore, I believe we'll start seeing an increase in tooling around languages, and a focus on reducing iteration latency. Traditionally, REPLs/live editing have been mostly associated with higher level languages, but there's no reason that those things could not be applied to low level languages as well.
Finally, while I think that there will be always be room for both simpler and complex languages, the market for simple languages is somewhat underserved right now, so we'll start seeing more of those in the nearby future.
Disclosure: I'm the author of Muon, which is a new programming language that tries to embody these principles: https://github.com/nickmqb/muon
It's strange to me that in this era of 32+ core machines, the language model is still single-threaded by default with (often significant) extra effort required to execute multiple bits of code simultaneously. Not to mention languages like python which restrict you to a single CPU core.
And I hope the interfaces for these languages won't require the use of a glowing screen and a sadistic keyboard. I'd rather like it for computers to disappear into the background. I'd like to reason about my programs in a physical space where I can freely walk around, write on a note pad, draw on a chalk board, converse, and re-arrange the room to my liking. I quite dislike how I've developed astigmatism, am at high risk for RSI, and probably other health ailments because we can't think of a computing environment better than what we have right now... just with more pixels, pop ups, nags, swishy animations, etc.
OTOH, saying "this must be true" and letting the compiler work it out sounds a lot like logic programming.
The second best is machine-checkable proofs, like types.
The fallback is tests. Sometimes the first two can't be applied.
Program Synthesis is Possible https://www.cs.cornell.edu/~asampson/blog/minisynth.html
And I'd like to see tools that can extract value and improve efficiency by searching paths-not-explored and comparing them with the current knowledge state.
It's easy to forget that code is a means to an end, not an end in itself, and there may be other ways to reach those ends.
IMO there's been too little work done in CS on robust knowledge engineering - as opposed to lambda calculus-inspired algebraic manipulation.
ML is catching up a little, but a lot more may be possible.
I'm just hoping that someone at compile time will be told "warning: function will take 2M cores to sort an arbitrary list within 20 ms"
For problems that can't fit in this subset, it will need concepts for coordination and reasoning about the state/consistency of the systems involved.
Concurrency and mobility/distribution are the big problems that programming languages have yet to satisfactorily solve. We have data structures and limited models that help with these problems (eg. CRDTs), but it would be a huge productivity boost to put these abstractions right in the language so you can read, write and reason about programs more easily.
Sort of like Django today but it will intelligently connect the plumbing for you.
For example you’d just select/say, “add a user authentication system to this app” and it would figure out and guess at the best way to do that.
Or “get me something to store the data users enter on this new form” and it would have some smarts to store it in a way that makes sense for your purposes.
You could always drill into what the system creates for you and change things but hopefully most of the time it comes up with something reasonable.
Who is there to back it? In this era, it has to be one of the big techs out there. Unless they somehow find that educating their 10s of thousands engineers to a new language, and changing their infra accordingly is worthy cost comparing to the benefits the language brings, I didn't see how this would happen really.
- languages for physicists
- languages for game developers
- languages for business apps
- languages for mobile apps
These domains turn out - IMHO - to have vastly different needs and are better served by specialist tools. Some of them textually, some of them visually (game design: Unreal's blueprint).
What if I just <whack>...okay, maybe I'll try something else.
Sure, there are exotics like languages for code golfing and domain specific languages, but overall things stayed pretty familiar.
All the comments here are along the lines of "I want a faster horse".
Anything less and you may as well be using JCL on punched cards. $END
Higher level abstractions allow the programmer to do more with fewer instructions. The closest we've got to that right now is monadic programming in Haskell (and other languages with first-class support for monads). They allow encapsulation of common patterns (if/then/else, exception handling, state management, environment passing, list processing, etc.). But it would be naive to think we're done.
Anybody who works on web-applications over a long time will realise we've run out of luck with our current languages. Code-bases that only grow and projects that never end. I work on a code-base of 15 million+ lines of code, and the language gives very little help in terms of managing that. Especially when the monolith gets broken up into services.
* Abstraction from the network to easily support distributed applications. Erlang has its actor system, which is the closest to this, I think. The standard criticism is that because networks can fail you can't build a one-size fits all system. Looking at the actor model it's clearly possible to build something that fits most common use-cases for distributed applications.
* Abstraction from error handling
* Abstraction from complex control flows over time - i.e. code where one line runs, then the next line might run 6 months later
* Abstraction from threads:
- No mutable data
- Built in support for synchronisation, coordination, and resolution. For example, types that support vector-clocks transparently, or the ability to have locally synchronised versions of something on a server, etc.
* Improved type systems that allow for easy type-driven development, so the compiler is enforcing the business rules of the system. Languages with dependent type systems are closest to this, but still often feel quite clunky. Perhaps even ban the use of types like int, string, etc. directly - you can only alias them into new-types like: Metres, PersonName, etc. so you're forced into using stronger types (although someone would probably just alias `int` to `Int` to get around it).
* Adaptive type systems that can describe a network of services. They would fail to compile if you send the wrong message to a service, and fail to compile if, a service which should be available, isn't.
* Something that's as simple to understand as Python for new devs.
* No null
* OO to die in a fire
I've personally had to build all the stuff above to facilitate the scale of our system - and by scale, I mean scale of code-base; any language that makes this stuff transparent and picks good safe default behaviours will speed up the process of writing new code and maintaining old code.
One thing that's of note when each paradigm comes along is how there's a mass of devs from the old paradigm that say "that's not real programming"; I think we'll only be at the next paradigm when we have that moment.
Just (as in 'only') change the (internal) representation of source code from character sequences to something that doesn't need a complex parsing process. In other words, eliminating the concept of syntax from language design, while keeping other language properties intact (could even use e.g. an LLVM back-end), allowing whoever desires it to write their own editors etc. as always.
(This is different from eliminating text: IMO, the visualization should remain primarily text. I say to eliminate syntax in the sense that the text 'visualization' no longer has a connection with semantics, nor any grammatical constraints.)
The reason I say 'just' change that: there are other systems structured to render AST-like structures (rather than parsing), but they are integrated with particular software systems. We need a general purpose alternate format with a similar independence of any project that 'character sequences' have for current source code.
I have a proposal for one that's very simple and general: represent languages as graphs of language constructs, and represent particular programs as paths through a language graph. More details at .
Making this substitution we can: throw out parsing, allow easy customization of language appearance (including things that would traditionally fall under 'syntax'), have much easier access to language insight (source representation is directly in terms of a language definition), give far easier to access to experimenting with language UX ideas, and more.
I'd love to hear thoughtful feedback on this. I will likely invest a solid amount of time/effort into building a prototype before long, so if someone can spot a potential weakness that I've missed, I'd be forever grateful.
(That said, please attempt at least a small amount of charity in reading: I wrote this in 2015 and most all I've gotten is people replying, "visual programming doesn't work" —even though it's expressly not advocating visual programming. I believe I really am talking about something fairly new here: and I am more than willing to listen if I'm mistaken. I have too many projects already; I have no need for this to work out. I just haven't been able to disprove it as... not being what it appears to be, and so I've felt an obligation to see it through for a long time.)
If you want some intelligent counterpoint, here is a post by the designer of Rust on why text is a good representation for programs:
Always Bet On Text https://graydon2.dreamwidth.org/193447.html
As someone who's working on a programming language, and has implemented a few DSLs and many parsers, I tend to agree with him.
Parsing is a pain in the ass, but I think it can made easier. The difference between text and structured data is "just" parsing, so I don't feel that switching to structured data can be a real paradigm shift. If there was a paradigm shift to be found, then it would have been implemented already by converting text to structured data, and operating on that data.
And this of course already happens in dozens of IDEs, and that's great, but it already happened. And while I have seen people be fantastically productive in IDEs, a lot of the best programmers I've seen also use emacs/vim.
But your ideas do seem more fleshed out than most, and I think that developing a prototype is the only way to make them more concrete, and more clearly see the benefits and costs. I do think there are benefits to making structured data the primary format -- I just think they are outweighed by the costs. Graydon's post outlined a bunch of things you lose if you abandon text.
Parsing every language uniquely is a lot of work. But it is doable and more or less "done". After that you have a whole bunch of other problems to solve (i.e. all the other things an IDE or debugger does), and that's where the real work is.
You can get rid of parsing by making structured data the primary format rather than the secondary format. But then you introduce a whole host of other problems. For example, how do you 'git merge'? You can't even collaborate anymore because merging is a textual algorithm. You would have to write a new merge algorithm for every single programming language, because each one has its own structured data format.
So basically you get a slight benefit by removing text, in exchange for a huge cost.
BTW here are some posts I've written about parsing:
Again, parsing is a pain in the ass, but I believe it can be made easier, and it's not a bottleneck in any case.
In my mind, the biggest bottlenecks in programming are:
1) Understanding the problem well enough to formulate the solution, whether it's in a programming language, math, or a visual syntax.
2) "Size is code's worst enemy". Many programming languages are inappropriate to express the problems they are solving. The code becomes unmanageably large pretty quickly. A million lines of C++ code is not a great way to express a solution to anything, yet it's the state of the art for vital projects like LLVM and Clang, Word, Photoshop, etc.
Both of these are 1000x bigger problems than parsing IMO. I'm not trying to criticize your specific idea, but I have heard the general idea to "get rid of text" several times, including more than once on this thread ... so that's my general rebuttal, if you're interested in a reasoned critique.
I agree it’s not the bottleneck to programming languages overall, but it is the bottleneck to the HCI/UX component of language design.
Edit: the git merge problem can be resolved by having a canonical text representation or doing a structure diff instead.
As for the rest of your response, you’re basically saying you didn’t take the time to get a basic understanding of my proposal, and you think other problems are more important than the specific one I’m addressing. I’m not sure how that could lead to a fruitful discussion.
I will take a look at the post about benefits of text though, so thanks for that. (Apologies if my frustration is coming out here, it’s just that I have had many responses—most much worse than yours—basically saying, “I didn’t read what you wrote but you should consider X instead.”)
It makes a lot of sense to decouple parsing from the rest of the compiler, if only purely from an engineering standpoint.
Editors, IDEs and other tools (transpilers, linters, formatters) already have to reimplement the parser, or at least hook into some API. Having them interact directly with the AST is a huge bonus. Sure, you'd have to rewrite your diffing algorithm to use a tree, but it seems minor compared to the cool things we'd get.
As long as you have a sane AST specification (the HARDEST part, IMO) you'd be able to have teams with people working in a Python-like syntax, others working with a LISP-like syntax, and so on, as long as internal semantics are the same (again, the hardest part).
Instead of having thousands of crappy compilers we'd have pluggable parsers emitting ASTs. This is much better for experimenting with Developer Experience and trying out new things.
Even the typing system could be decoupled: adding a borrow checker or dependent types wouldn't require writing a new language or forking an existing one, so they would be reusable, as long as the AST supports it. Running a linter during a compilation process would also be trivial.
And we would be able to reuse optimizations, code generation, interpreters.
We complain so much about "vendor lock in" but this has potential to remove the language lock-in that we have. Sure, we'd still be able to get locked-in to frameworks and libraries, but that's something to solve another time.
OT: I actually had a similar experience back in the 2000s when we had to convert a large VB.NET codebase to C#: we used the first crappy "convert VB.NET to C#" site we could find online and it did the job amazingly well. Fun times.
That extends to probably about half of the linked paper, as well, though I daresay it fares better than most I've seen.
I think we've mostly mined out the thoughts of the past, running on machines essentially simulating the machines of the past. All the bright ideas people had fifty years ago but had no prayer of getting to work on the hardware of the time has had time to be tried out. While I'm sure there is some path dependency in our current best practices, I personally think it's easy to overestimate it. There's a lot of languages running around, and if something was really 10 times better, I think we'd notice.
I think the next step up is going to require new thoughts, mostly driven by taking a fresh look at the hardware we have now and reconsidering the way we currently lay down a ~1970s paradigm on top of whatever hardware we get. It may also require some new hardware to be developed, as we stall out at current clock speeds. I don't know exactly what it will look like, but, well, first of all I see multiple languages, not one grand one, but languages like...
... something natively built to deal with hetereogeneous execution on GPU, CPU, slow-but-efficient-CPU, FPGA, and so on.
... something that successfully wraps up the sort of work that Haskell has been pioneering and moves us beyond working with ints and strings to something higher; an integrated view of functors and other higher structures, probably wrapped up behind friendly names, and using that to work with parallelism appropriately. There's a sense in which it's weird that it's 2019 and I'm still getting slabs of 32 bits to hold numbers, and the semantics of this hasn't hardly changed.
... Rust arguably already fits in here, but more efforts to pull down work done on the fringes of safety into something that people can actually use to build high-performance, yet safe, systems. These languages may not be 10x development speed improvements at the local level, but they can accelerate large projects by making a lot of things safe to do that right now are terrifying on a large code base. In general I still feel there's a lot of work to be done in the field of large programs. A lot of up-and-coming programming languages are still way too focused on making individual lines powerful, because that's cool, or because it's easy to evaluate how a new proposed feature does or does not make a 3-statement snippet now become one, but neglect how to make big programs hold together safely and without the whole thing calcifying to the point you can't move it forward as time goes on.
... as a specific case, languages or libraries designed to deal with the burgeoning field of "what can we safely do over a network", via CRDTs, lattices, and other safe mechanisms, integrated into the entire language's outlook rather than being a bodged-on addition.
... languages like Jai that detach the operational semantics of a data type from its storage, so that I can create an array of structs and just tell that array to actually be a struct of arrays, and maybe compress the array data if I'm willing to guarantee I'm always going to go sequentially across this array, etc., or tell it my access pattern so it can store the array optimally, using our modern hardware more efficiently than pretending it's still 1970 and memory accesses are all the same cost. Maybe throw in some cache awareness, or a pervasive cache-obliviousness, again at the language level if possible.
One thing I do not see, for what it's worth, is an increase in the declarative nature of programming languages. I don't particularly believe in declarative languages anyhow, but a lot of these things involve giving the programmers the ability to say more than current languages let them say, not less.
Many of these can work together harmoniously; safety, "something something CRDTs lattices", and data structures that integrate higher-order safety characteristics like functor and monad probably all go together pretty well. A language to address heterogeneity in computation might just work well on a network computer, too.