(My comment is slightly off-topic to the article but on-topic to the title.)
I’m hoping more recent developments, like WASM or Graal, provide a route for more flexibility when selecting languages. It’s nice to see Rust slowly become a serious choice for web development. Most of the time JS is fine, but it’s good to have the option to pull out a stricter low-level language when needed.
What comes close is:
#! /usr/bin/env elixir
Mix.install([:jason])
defmodule JsonPrettyPrinter do
def get_stdin_data do
:stdio
|> IO.read(:all)
|> Jason.decode()
|> case do
{:ok, json_data} -> json_data
_ -> raise "Invalid JSON payload was provided"
end
end
end
JsonPrettyPrinter.get_stdin_data()
|> JsonPrettyPrinter.pretty_print_json()
|> IO.puts()Also often, the language doesn't live isolated from its implementation (compiler or interpreter). While theory looks at languages via its semantics, in practice as the OP notes it is about the quality of the implementation and what can be reasonably done with the language.
A recent [1] case is Julia. I think it has hit a kind of sweet spot for language design where new performant code tends to get written in Julia rather than in some other language and bound to it. At its core, it is a simple "call functions, passing data in and getting results out" kind of language, but what the functions ("methods") mean and how the compiler does just-ahead-of-time compilation with deep type specialized code means you can write high level code that optimizes very well. Those mechanics operate under the hood though, which makes for a pleasant programming experience ... and there are loads of cutting edge packages being written in Julia. It is less interesting to look at Julia as "just the language".
[1] recent in programming languages is perhaps anything <= 15 years? .. because it takes time to discover a language's potential.
years ago a senior developer close to me said "when screening interviews, if i see rails i throw the resume in the trash"
so ironic how trivial/stupid these language-based judgements are
People, on the other hand, work with ideas, metaphors, expressions of intent, etc. If a language/library makes the communication of those things easier/better/faster; if it can be "written down" clearly, and "read" clearly by a person, then does it really matter into which taxonomic category it fits? We pick horses for courses. That seems about right.
If Rails works for you, is complementary with what you want to achieve, is an accelerator, and is generally well-understood by the people with whom you work, then use it. Alternatively, if the answer to all the previous is Stanza then go with that. There's less "right" and "wrong" in those decisions than there is "advance", or "struggle". It sounds trite. But, use what works. If something doesn't work make something that does, iff that's the most efficient approach.
I think about programming/design as languages/translation in a lot of ways: its languages all the way down.
The work matters too of course. Frequently used functions should be categorically bagged into libs and if the lib is used often enough some of it's functionality should be baked into the language. If languages require something often enough the language layer above should provide it and if things are frequently needed close to the metal it should be baked in hardware. Possibly as a co-processor and then as part of the cpu. We should even have a similar process moving things in the other direction. I cant wait for the day when floating-point arithmetic becomes a library complete with a community of people who still think it's wonderful. Like a football channel to cleanly contain that kind of undesirable materials. Some libraries/modules/frameworks should also be replaced by competent developers. We don't want a leftpad community.
It's true, you couldn't really do Express in Java, at least not back then.
I follow new language developments with keen interest, but few of them will ever reach the level of maturity to be considered serious candidates for adoption. It's also risky to adopt a language that you cannot easily hire developers for, for example.
Libraries are great, but there is only so much they can address, and that depends on the language, too, as the article correctly points out. And there are two kinds of libries: tool libraries and frameworks. Someone once said it nicely: "Frameworks are like Hollywood - 'You don't call us, we call you!'". Frameworks often require you to submit to their control flow rather the other way round; that's why I prefer tool libraries.
At the extremes, we call these paradigms. Functional languages, Object Oriented languages, Array languages, etc. But every language exists to make some subset of "shapes" of solutions easier to read and write. Elixir encourages you to describe your programs as a distributed system of programs each running a series of transformations to data, thanks to its pipeline system, and to push your branching to function-call level with its pattern-matching multiple dispatch.
Java encourages you to write your application as a collection of things, that know stuff and do stuff, including telling other things to do stuff based on things they know.
C and Go encourage you to write your programs as an ordered series of atomic tasks for the computer to complete.
SQL has you describe what you want your output to look like.
Etc, etc. There are inherent trade offs between languages, because what you make inelegant to express or even inexpressible carries value, too.
Many DSLs can be bolted onto an existing language with support for compiler extensions. This approach offers more flexibility, but often leads to fragmentation and poor interoperability in the language ecosystem.
There is third approach, established by a group in Minnesota [1], which is to design languages and tools which are modular and extensible from the get-go, so that extensions are more interoperable. They do research on how to make this work using attribute grammars.
If the host language has a sufficiently expressive type system, you can often get away with writing a fluent API [2] or type safe embedded DSL. But designing languages and type systems with good support for meta-programming is also an active area of research. [3, 4]
If none of these options work, the last resort is to start from tabula rasa and write your own parser, compiler, and developer tools. This offers the most flexibility, but requires an enormous amount of engineering, and generally is not recommended in 2026.
[2]: https://arxiv.org/pdf/2211.01473
There’s a time in my life where I designed languages and wrote compilers. One type of language I’ve always thought about that could be made more approachable to non technical users is an outline-liked language with English like syntaxes and being a DSL, the shape of the outline would be very much fixed and on a guardrail, and can’t express arbitrary instructions like normal programming languages, but an escape hatch (to more expressive language) for advanced users can be provided. An area where this DSL can be used would be common portal admin app generation and workflow automation.
That said, with the advent of AI assistants, I’m not sure if there is still room for my DSL idea.
Why yes, it can and has been done: https://www.dreamsongs.com/Files/ECOOP.pdf
The structure of a language matters to the ease and feel of its use, despite even being logically identical. One parallel would be the syntactic benefits of something like Hintikka’s independence-friendly logic vs first order logic, even if they are equivalent.
The sentiment shared is that we should sacrifice benefits to the next generation to make our own lives easier. This is a common sentiment, but a sad one. The goal should be a natural language based programming language, that everyone can use, along side a technical programming language that makes unambiguous the interface between the language and the machine.
Everyone seems to endorse their happy medium, and those languages are also perfectly fine.
They talk about the programmer which doesn't know neither cares about the language stuff. So what is Spring lacking from that perspective?
I’ve been experimenting with a small defeasible-logic core (argumentation semantics + priorities + conflict detection) that stays stable, while most of the real meaning lives in extension points. https://github.com/canto-lang/canto-lang
There are lots of libraries already. Instead of rewriting them in every language why make them available to every language.
Yes, I know it would be difficult and in some cases impossible.
Close! The purpose of a general-purpose programming language is to enable the creation of powerful and easy-to-use languages, but often just libraries.
But aren't Rails, Laravel and Django a bit similar? At least for the people not directly involved in coding.
We already have it. It's an obscure little language called C++. Tise interested in those kinds of extensions to a language should look into Herb Sutter's experiments with cppfront: https://hsutter.github.io/cppfront/welcome/overview/
But, if you squint, great API design is a bit like embedded domain specific language design as well.
I think there's room for both.
It looks that somebody listened. We now have 3 GTK libraries in a system, a lot of graphics libraries (cairo, etc) 3d libraries (Mesa, vulkan). It is a mess.
Although that in itself might be a hint to change language and write your library there, instead of inventing a new one.
yet at the same time, clojurists love the idea of doing lots of dsl libraries..
the key is that not all worlds enable the same kinds of libraries.
- and runs 50 times faster than c, c++, rust and zig
- comes with a standard library covering 50000 use cases
- has direct integrations with drivers to every major database, crm, analytics provider, key value store, queue systems
> At this point, the right question to ask would be, well can you write a static-typing library for Scheme that then automatically checks your code for type errors? And the current answer, for now and for the foreseeable future, is no. No mainstream language today allows you to write a library to extend its type system.
The author seems to provide a counter example themselves(?):
> Racket and Shen provide mechanisms for extending their type systems...
I wonder if this is as clear-cut as the author is making it out to be. Coalton, which is effectively a library (and language) for Common Lisp, seems like it basically does this. Maybe that's not exactly what the author is referring to, because it is essentially a new language on top of Lisp using its meta-programming facilities, as opposed to merely extending the type system. Still, it can be used as a library right alongside Lisp code, so I think it's in the same spirit of of the first question of writing a "static-typing library that automatically checks your code" in a dynamic language.
Standard scheme may or may not be able to do this, but most Scheme implementations have unhygienic macros like CL's too, so I'd assume something similar would be possible. The fact that that these tend to be extensions from implementation designers might align with the article's point though. Also somewhat to the author's point, Coalton does rely strongly on CL's underlying type system, for which there's no real equivalent in Scheme. It also relies on implementation-specific optimizations alongside that.
For what it's worth you can (and indeed people have) written object systems in Scheme, despite the language not having one, though they tend not to be performant, which is likely another point towards using/writing a different language. CL also tends to allow fairly deep extension of its object system through the Meta-object Protocol.
I guess my point is that in my (probably biased) opinion, Lisps, or other languages with very strong meta-programming facilities, are pretty close to the language longed for in "Perhaps one day we'll have such a language." They aren't a silver bullet, of course. CL has no easy way to write performant coroutines/continuations, for example, even given all its extensibility. Scheme has no real type system, etc. etc.
I don't think any of this invalidates the articles points, I'm just not sure I agree with the absolutes.
Ruby got a hype phase with regards to rails. It then dropped. A lot.
TIOBE, while it is in general crap, is somewhat accurate when you plot things over time:
https://www.tiobe.com/tiobe-index/ruby/
So, ruby peaked with rails between 2006 to 2009 or so, give or take. Then the decline phase set in, and now it is unfortunately also crawling behind perl into extinction. This is very unfortunate - I still use ruby almost daily as the ultimate glue language. But this can not be denied now that ruby is following the extinction path perl already had going some years before.
I was using ruby before rails was created and ruby covers all my web-needs. I had a web-framework in PHP, used it for about three years, ported it into ruby and expanded it massively in the last 20 years or so (well, almost 20 years). I retired from rubygems.org when RubyCentral got crazy in 2024 (and even crazier in 2025 with the mass purge of developers). So, one difference here is that the friend he talks about is using a specific framework. He probably no longer uses ruby nor rails. I use ruby because the language is very well designed and covers (most of my) use cases; the rest I may sprinkle down with java. So whether rails exists or not, makes zero difference to me. Actually without rails it would be better, because people using ruby would be using it because of ... ruby. Even if there are then fewer users. I still think this is better than those who will jump ship anyway because they only use ruby due to rails. These guys are not like in the same boat. They have use cases for getting work done via rails, designing websites, infrastructure related to websites, user-interaction and so forth. But they don't really use ruby as such. Their use case is quite limited. I think this is one of the biggest problems here. It in part explains why ruby dropped down a lot (there are many reasons for this, python being so successful is in my opinion the biggest reason, but the other smaller reasons also add up - that also includes the laughable joke that is documentation in the whole ruby ecosystem. That's inexcusable - note, I am not saying documentation must be perfect, but please look at opal, ruby-wasm or rack - the documentation there is virtually NOT EXISTING.)
> The vast majority of programmers are non-experts, like himself
No, I think he is an expert - just in a specific niche and field. Not all experts know everything equally well.
> Subtle language features like first-class functions, and object systems, are lost on them because they don't really use them anyway.
I don't think this is true. Some language features are very useful. Ruby's blocks for instance. They are probably one of the top three win-win features ruby offers.
> Computer scientists should really be spending their time developing new libraries rather than inventing new programming languages.
I also disagree here. I would, however had, say, that new languages should be well-designed. Many new languages suck. Old languages also suck. Designing a great language is very hard. If it is just a toy or research language then this is fine, but once a language is meant to be "real", it really needs to have compelling use cases and be great in many areas including documentation.
> These features are simply not available in all other languages. Java's meta-programming features, for example, are just not powerful enough to implement a system like ActiveRecords. Rails is only possible because of Ruby.
That's also incorrect. You can create any DSL as you like in Java too. Ruby just makes this a lot easier out of the box. Plus, you can also have great websites without rails.
> Ruby on Rails was designed to make it possible to build websites without understanding type theory, or memory management, or object-oriented design patterns.
Ok so ... why would this not be possible in Java? Why would he have to write Java code for a library to be used in this regard?
> Ruby on Rails provides a concise way for expressing: do this when the button is clicked
But you have the same in many other languages and frameworks too. I mean this is how PHP was started initially.
> The "do this" part is implemented in Ruby as a first-class function. How would it be implemented in languages like Java which don't support them?
Write a solid DSL.
> The programming language directly shapes the design of its libraries.
If this were true, why would GTK have glib+vala? I mean, they could just rely on C directly, right?
Besides, ruby is just a wrapper over C really.
> The more powerful the language, the easier the libraries are to use.
That part is true. A better designed language makes for better libraries or a chance to have better libraries. I noticed this when I compared my PHP code to my ruby code. I am not a good programmer, but my ruby code is much better on every level than the equivalent PHP code. Fewer lines too. While this also has to do with experience, at the end of the day PHP is simply a much worse language than Ruby is. At some point I decided I don't want to invest into languages that suck when I could be using better languages instead. That is also why I stopped writing shell scripts - it is just a waste of time having them.
Rails is also, by the way, fairly well documented. So I am not saying all in ruby has horrible documentation of course.
With that said, the divergence in comments on this very insightful and well written article will soon provide an unusually clear means of determining who is commenting on the title and who is commenting on the article.
E.g. node says "oh no, you need a library to write tests!" and now that means that you have to have a testing framework built into your runtime. And of course it's just another library, really, that competes with the original one, but this one is blessed with standards so it has a monopolistic advantage that will deter further innovation.
All programming languages are equivalent meaning their level of expressiveness is the same, it's not an opinion it's a fact. Each language comes with its runtime and its peculiarities but potentially you can always make any feature that another language runtime has with any language, even though probably not with the same performance and efficiency has been that feature native to the runtime itself.
So there are no "more powerful languages" just runtimes that allow you to hide away some stuff considered stable enough that they become some kind of primitive for the programmer, now we may have different opinions on what elegant code is, but personally I'd like to avoid code that directly (i.e. no kind of abstraction) relies on runtime features and instead express clearly my intention in code, but I recognize the productivity gains.
There is however something wrong with releasing your new language! In most cases you should show it off to close friends, or your professor, and then burn it and all the source. Sure you might be better than the current language, but you won't be enough better as to be worth it. (even if the language is notoriously bad C++ where it is easy to be better - you won't be enough better as to be worth it).
If you want a better language there are two good options: switch to a different one that already exists; or make your language better. There are lots of great choices for languages out there if you want to switch. If the language you are thinking of doesn't have an active community of people working on making it better, it probably isn't a good choice.
Whichever language you choose though, libraries are the hard part. There are a lot of bad libraries, we need someone to write a better one - but only if one doesn't exist! For the great libraries out there, most need someone to contribute.
A large part of libraries is the consistent interface. Often there is a great libFoo and libBar, but their APIs are not consistent and so we need a libBarWithFooStyleInterface, and/or libFooWithBarStyleInterface. Better yet, we need everyone to come together and agree on how the interface should be and then make both use that new standard - cleaning Augean stables with a toothbrush seems like an easier task. Of course in the real world there a hundreds of libraries each with a great interface that is not consistent with the others.