Hacker News new | past | comments | ask | show | jobs | submit login
We need less powerful languages (2015) (lukeplant.me.uk)
86 points by traverseda on Feb 1, 2023 | hide | past | favorite | 96 comments



I would argue similarly, we need more languages like Dhaal or SQL or systemd, which are explicitly not Turing-complete.

Most of the so-called "business logic" can be written in non-TC language.

Lately, I was thinking about about a kind of pentagon of things:

(1) Algorithms are primitives of data transformation, and they are written/debugged in TC languages.

(2) Data transformations (like ETL process or DB transaction) are written in non-TC language (like SQL), are composable, and use algorithms (1) as primitives.

(3) Platforms are primitives of execution resources, things like databases, application servers, client UI loops, etc. These are also implemented in TC languages.

(4) Computational resources (like I have this many application servers of this type that provide this much CPU and this much memory) are written in non-TC language that doesn't compose in terms of functions, but in terms of resource additivity. In other words, these languages can describe global constraints on platforms (3). Something like systemd comes to mind, but perhaps more expressive.

(5) Then there is a system-description language (composable but not TC) which marries the data transformations (2) and computational resources (4). It does say how data move through the system, and where each transformation gets executed. However, this language is not concerned with how each transformation gets executed (that's the job of (2) and (1)) nor with at which exactly piece of infrastructure they get executed on (that's the job of (4) and (3)).

The goal would be then to take language descriptions (5),(2) and (4) and compile it in terms of (1) and (3), i.e. what actual algorithms are executing on which actual platforms. (Hence the pentagon with nodes (1)-(2)-(5)-(4)-(3).)


> we need more languages like Dhaal or SQL or systemd, which are explicitly not Turing-complete.

Agreed 100%. First time I used Dhall a similar thought crossed my mind about it being an ideal specification language for most ETL pipelines and similar “business logic” work.

I feel like Spark was (in intent) an initial foray into this kind of solution with the data frames and SQL interface, but it falls short in number of ways and is way too attached to a single implementation (warts and all).

The idea of a “resource descriptor language” (4) is a very cool concept, and not one I’d thought of before. Would this be granular compute resources (x % of CPU and memory, a la Kubernetes resource limits) or more like terraform? Maybe I’m misunderstanding, but isn’t (5) less of a language, and more some kind of constraint-solver based on (2) and (4). That is, it attempts to find the “layout” and allocation of resources for the requirements (optimise for minimum hardware, optimise for maximum throughput, etc). Again, this could be me misunderstanding this stage though.


It was just a quick, rather undeveloped idea.

Regarding (2), I think categorical database schemas might be an answer. But it still pretty much theoretical.

I am not really sure about (4). I think it would be a mix of both, although the actual Terraform operations would be treated as primitives.

I think (5) doesn't have to be a constraint solver, it might be just a language where you marry the resources (and the way they scale, also described in (4)) with the actual computation, even if it was all explicitly specified. (Constraint solving it is another level.) Basically, (5) describes the final architecture of the system, while (2) specifies what needs to be computed and (4) specifies what resources are available to do any computation.


SQL is Turing complete thanks to recursive common table expressions.


We already have less powerful languages, like C. The results are underwhelming. We need powerful languages with the power harnessed and thus safer to use.

It's like saying that we only need chisels and knives instead of power tools. I'd say we need power tools with proper safety features, and thoughtfully built to make them efficient to use.

The particular case of Python is exactly about the lack of harnessing. The same reasons would apply to Perl even more, and equally to Smalltalk or Ruby, etc; cleanliness of the design is not the point. Any of these languages is basically play-doh. You can build anything from it. It will not be very strong, and it's a bit hard to make it into a precise shape. But it's supremely easy to quickly prototype anything in such a language. When you don' have a clear plan, constantly experiment in a REPL, and keep reworking your design several times a week, nothing beats a highly pliable, highly dynamic language like Python.

Then, of course, you have to ship it, and can't afford rewriting it.

There are hyper-powerful languages like C++ and Rust. They are much harder to wield, and C++ famously does away with many safety features for the sake of ultimate flexibility, while Rust goes to great lengths to ensure safety and efficiency at the same time. Rapid prototyping in them is not easy even for top experts.

There are relatively fine middle-ground languages, to my mind: say, Kotlin (or even plain modern Java), or Ocaml (maybe using the Reason syntax), and even Typescript where you can increase strictness gradually while allowing areas in the codebase still in magma state.

But Python, due to its very friendly and human-readabale syntax, won a lot of mindshare by being easy for a beginner, and also by having a nice set of very important libraries (many not written in Python). So we'll see a lot of software that could benefit from being written in a less play-doh-like language, but were started in Python, and will not be rewritten.

Python specifically tries to grow some safety / stability harness, in the form of optional typing and mypy, protocols, etc. It's better than nothing, but it's still far from allowing to write bulletproof code effortlessly.


> We already have less powerful languages, like C.

I don't think this is a good comparison. C is a systems language and operates at a completely different level of abstraction than Python. Also, it's very powerful. It might not have a lot of language features per se, when compared to something like Python, but production-grade C code is just as complex (probably more so) than production-grade Python code.

I generally agree with the rest of your comment. But saying that C is the "less powerful" language rubbed me wrong :)


I agree that C lets you more precisely control what a CPU does. By that definition of "powerful", I think the assembly language of that processor is the most powerful language.

But the cost with which you must put up is also large (the intricacies of the CPU, memory allocation, types and such breed complexity). Some tasks are not worth that cost.

For instance, you want to print "hi" to the console. A shell script saying "echo hi" is perfectly adequate. No need to declare a main function or import anything.

By defining "power" as this "efficiency" or "sparseness" or "brevity" measure, strictly looking at this example, C is less powerful than bash.

I tried to take literal code length per Rosetta code task as a very rough measure of "terseness" (the x-axis), and I'm curious what you think.

https://danuker.go.ro/programming-languages.html

In any case, my definition of "power" is close to the opposite of what it means in the OP article.


There is no great difference between any of them. They're all essentially procedural languages with various bells and whistles bolted on.

The list comprehension is about the only high level feature in python in my opinion and it's still quite underwhelming.


This comment completely misses the point. C is not less complex than Python, Ruby, or even Haskell. In fact, it's much more complex. Complexity is here is not about 'how easy is it to write something'. Complexity is rather 'can I express problems that are difficult to reason about'. It is impossible to express intractible problems in HTML. There are problems that simply cannot even be expressed in HTML. Contrast this to any of the turing complete languages, in which it is possible to express problems difficult to reason about. Python, ruby, julia, javascript, haskell, etc fall into this category. Now contrast this to the turing complete languages riddled with undefined behavior like C and C++.

Your complextiy is inverted.


I don’t think this notion of complexity is meaningful/well accepted. Languages have expressivity as a more-or-less accepted concept (in which C is very inexpressive, Haskell, Ruby etc. are very expressive), and language complexity as perhaps another, where the concepts of the language are taken into account. For example something like Idris with dependent types would be a quite complex language, while C may indeed be relatively simple. This is usually the inverse of expressivity.

You seem to talk about the complexity of a program when written in a specific language. Here, a more expressive language would fair better, at usually the cost of a more complex language as mentioned above. But as we all know, essential complexity (of a problem) is non-reducible.


Problems difficult to reason about are big problems, so a big html document is such a problem.


Nope. An html document is statically analyzable by simple tools. Html parsing is very easy. Html rendering difficult to code correctly but very straightforward. It is very easy to generate in bounded time the result of an html render.

It is impossible to do that with C, haskell, rust, etc.


An html engine is such a simple tool microsoft gave up making its own. C compilers available for a wide range of platforms is said to be due to simplicity of C.


Personally, I find rapid prototyping much faster in Rust than Python, and I don't think I'm a "top expert".


I loathe to say you must be doing something wrong. I mean objectively it really should not be the case! There is literally a ton more you have to write and do for the same thing in Rust. You get runtime safety and performance as a benefit, but those are not benefits in rapid prototyping.


When I've prototyped in Python I mostly find myself using tuples, dictionaries, and lists. Generally the dicts and lists contain homogenous types but occasionally heterogenous types but they're really "variants" (variations on a theme). Writing the same types of programs in Rust usually proved straightforward by (ab)using the same basic types and operations on them. For handling the occasional heterogenous collection case, an enum of related variants sufficed and it wasn't a much slower effort than prototyping in Python would have been.

I would expect someone with more Rust experience than me (which is not much) to be at least as fast as I am with Python in Rust, especially if they know the tooling better. At least for these kinds of tasks.


Python is much easier to follow in 2023 with its optional typing support and fantastic libraries like Pydantic that make it easy to use. We are deeply missing a statically typed scripting language.


The optional typing in Python is pretty mediocre, especially in comparison to something like Typescript that just does everything so much better. The types are pretty limited and not very ergonomic (especially when using generics or functions), and third party support is hit-and-miss. The worst thing, I think, is that the Python typing community are trying to solve lots of the problems with plugins rather than by improving the capabilities of the type system. This might produce better results in the short run, but in the long run it makes things more complicated, as for a given project I need to understand (a) how Python works, (b) how Python types work, and now (c) how each of the plugins installed in this project work and how they interact.

I really want to like typed Python, but it's a pale shadow of what it could be, and what it really needs to be if people want to use it to describe very dynamic Python programs.


Sometimes, not making mistakes can help your velocity more than it being quick to type out. It depends I think on what you're doing.


I'll give you that. And if someone is really in the 'zen' with a language, I can see them being quick on the draw. And it depends a lot on the project and deps. as well.


> There is literally a ton more you have to write and do for the same thing in Rust.

This is not true. Rust and python are about equivalent. Python is difficult to understand because the vast majority of library documentation is simply lists of examples, without any unifying theory. Languages like Rust and Haskell offer much more comprehensive documentation with obvious ways to fit things together based on a well-understood and rigidly specified compositional specification (types).


With rust you have to specify type, usually a container/reference type, and annotate lifetimes of everything you pass around. You literally do none of that in Python. You don't even declare variables. They are totally on the opposite ends of 'strictness'.


For rapid prototyping I (who you originally replied to) completely avoid lifetimes. If you think you have to "annotate lifetimes of everything you pass around", you should probably revisit Rust. This is simply not true.

I find type annotations to be a major benefit while prototyping - I know exactly what everything is, and can quickly refactor anything. The ability to use serde to deserialize/serialize into Rust structs is another huge benefit. Chaining iterators, collections, etc removes a lot of the boilerplate that I find myself doing in python.

I've also been using Rust as my primary programming language for 5+ years now, so I am definitely "in the zone"


I heartily disagree with this -- anything I've tried to prototype in Rust has resulted in much frustration over lifetimes, types, etc.


I suspect it has a lot to do with your familiarity and level of experience with Rust. Probably also how much you’ve written code in languages with similar features/idioms.

I also find Rust to be quicker for prototyping than Python. However, I find Java quicker than Rust.


Can you write a function in a REPL and run it instantly? Can you easily inspect intermediate results?

In this regard I love Haskell's REPL mode, it's really productive for prototyping. It has a worse discoverability / autocompletion story than Python REPL though.


The only time I've ever needed a REPL is if I'm working with a badly architected codebase such that I don't know the shapes of my inputs. It's otherwise pretty easy to reason about well-architected code without needing to run it.


A lot of Lisp development is (or can be) REPL-based, Clojure(script) especially, but that's almost a whole paradigm in and of itself.


Having spent a lot of time writing both Clojure and Rust professionally, I think a lot of the benefit you get from a REPL is making up for the lack of a good type system and good IDE support. I also find that the support Rust has for unit tests partially makes up for the lack of a REPL.

Clojure has a bunch of other benefits over Rust when it comes to quick prototyping though.


For me the most interesting and non-obvious property of the code is how the whole thing interacts in the long run, but you can't possibly figure that out with REPL as preparation of inputs would be immense.


In Haskell, you always know the shape of the input, so this completely misses the point of what the commenter above is trying to say.


I think the kind of powerful the article talks about would pretty explicitly apply to C, as it is turing complete and lets you manage lots of stuff explicitly


Scala 3 feels like python++... sticking with the quiet syntax it feels very pythonic.


Indeed, including the ecosystem break between Scala 2 and 3. /s


Python++ sounds like it would be absolutely terrible.


Python with:

-types -modules -better encapsulation -compiled speed out of the box -more concise syntax for writing classes -real support for OO and functional programming


I look at it from the opposite angle.

I want a language that starts as simple and powerful, with simple and easy to use building blocks, that then builds simple abstractions on top of them, ideally allowing me to too.

I'm tired of languages that start simple and weak, then bolt shit after shit on top until you need a phd in FuckedLanguage before you can really understand how to use it.

If you're constantly surprised by undiscoverable expressivity features in your language, this is a good a sign your language is, at its core, both weak and complex - a hilarious combination that most languages are rapidly chasing to keep the "modern" label.


My sense is that the simple building blocks are more trouble than they’re worth.

The main example I look at is call/cc in Scheme. It’s simple, it’s elegant, and it can be used to build all sorts of things like exceptions, coroutines, and backtracking. However, if you build all sorts of abstractions with it, the abstractions will interact with each other in unexpected ways. It also “contaminates” your library code and makes it hard to write certain higher-order functions—if your library function is not a leaf function, it might call call/cc, and call/cc might return multiple times.

I’d say call/cc is powerful like dynamite is powerful. I don’t want it in my toolbox.


I'm not sure "powerful" is the right term.

What actually seems to be needed is more consistency in usage. Opinionated conventions on how to properly use something.

I don't think it's a problem of a language to be universal and generic and usable in many different ways and usage scenarios.

But a project probably should not randomly mix and match all available language features - but follow a best practice approach that makes sense for the project. Constrain itself to a certain subset of language features.

The language still can offer features that aren't used for this project - but might be useful for another project.

It can't be the job of the language to stop programmers from using (or abusing) any language features. Use things inappropriately, or use stuff that isn't a good fit for the problem it's used to solve.

There's always going to be multiple different ways to implement something, and it has to be the responsibility of the programmer, to choose a solution that's a good fit.

Trying to make it impossible to use any non-optimal approach on a language level, isn't going to ever work out.

No matter how restricted and patronizing you make your language - there's always gonna be some programmer who uses something inappropriately, and then blames the language for it.


If I never hear the word "opinionated" again in the context of software engineering, ever in my life, that'd be nice.


@BulgarianIdiot

It is a (more or less) technical term that carries a (more or less) specific meaning with regards to software design.

See:

* https://stackoverflow.com/questions/802050/what-is-opinionat...

* https://softwareengineering.stackexchange.com/questions/1218...


Believe me, I know what it means.

And it's not a technical term, but a MARKETING term. An obnoxious and misleading one.

So, I know for example the sentence after you said it contradicts it: "generic and usable in many different ways and usage scenarios". I know DHH first used it, and he named his product "on Rails" precisely because he wanted to make non-developers and beginners feel empowered that they're in the driving seat, while actually not driving at all and running on rails.

Opinionated software is training wheels (or rails). It can't be flexible or general purpose. It constrains you, so that when you don't know what you're doing, you still end up doing something. Children love this, and non-professionals also love it. Experienced professional developers hate it.

It's not fun for professional developers to be told what to do, because they're in the business of they telling computers what to do. And they know libraries can be easy to use and flexible without being "opinionated".

DSLs have their place. But they're not general purpose, it's a contradiction.

And I don't like the term "opinionated" because aside from the smug arrogance with which it's often said around the RoR community, it lies about what it is. It's not "opinionated" - every software is created with opinion, it's impossible for it not to have one. But what the term really means is "constrained". This would suck for marketing though, and DHH is great at marketing, so he came up with that BS instead.

PS: let me also remind you what this word means as an English word: "characterized by conceited assertiveness and dogmatism."


I see a lot of professional developers that really need to be told exactly “what to do”.

They usually mix up what “general purpose” means for business vs comp sci theory.

For business general purpose means “it is easy to add database fields, read, write, do some calculation in specific context”.

For developers it means “it is easy to manipulate data, switch database engine, switch presentation technology”.

If you use rails you deliver business value and don’t care about what-ifs. That is what professionals do.

So I have a different opinion on what it means to be professional. For me it is to deliver business outcome as fast as possible.

Please stop if you want to write high horse “quality” response because it still is business outcomes with high quality I write about.


You basically described it as if the only business value to be had in software is making a CRUD app. I won't even correct you, I know an overwhelming amount of developers who keep churning out the same CRUD app over and over. With small differences in schema, validation, business rules here and there.

It's a life, I don't judge it.

But it's also shoddy engineering, wasteful, redundant, and eventually this class of applications will disappear, replaced by one of a few winning content management platforms which do CRUD even better than RoR does, and more. RoR's opinionated approach, aside from constraining you so don't make something stupid, it also constrains you INTO doing quite a lot of stupid things.

Everyone has the confidence they're good at their job. But my experience is I've not seen anyone I really respect in this industry, who enjoys RoR's architectural choices.

See, the trouble with being opinionated, is that others also have opinions.


I see this argument as that structural engineers are making their own steel by hand.

Unfortunately that is not the way complex structures are built.

Real mechanical or structural engineers use mostly off the shelf components or pre-made parts unless they run into really specific cases.

That is why my stance is that frameworks and especially opinionated ones are the future.

Mostly because IMO content management platforms are too rigid and I am against those just as IMO opinionated frameworks are giving best tradeoff between “making my own steel from scratch” and “this is the thing you cannot change”.

There is whole space for CRUD apps as there are still many companies doing stuff on paper. We can argue about AI or fancy algorithms all day but there is whole world that doesn’t even care.


The way "you see my argument" is like someone who just learned what a strawman is, and was very excited to try it out.

The issue at hand is architecture, which engineers are very much interested in, and not underlying infrastructure implementation details, which would fall closer to the category of "raw materials".

Despite that, in the real world engineers have been concerned even with the shape of the sand particles forming their building's foundation, as it impacts the structural integrity of the entire project (actual case study in Dubai).

You find CMS-es too rigid. I find CMS-es can be more flexible than RoR, which I find too rigid, UNLESS you fork it and break the framework constraints, which is what Twitter did early on, BTW, so they can evolve the app.

But it depends what you call a CMS. A person well versed in CRUD apps, seems to think of a CMS as a premade CRUD app, just bunch of forms with a few fields and a WYSIWYG HTML editor for the page body. But that's primitive, and barely scratching the surface.

I wonder if you're familiar with Drupal's node architecture. I don't like Drupal, but it's popular, so it can be a subject of discussion. The Emacs buffer architecture is also relevant, despite we don't often think of Emacs as a CMS.


I fail to see the contradiction in my post.

I clearly wrote that a language shall NOT be opinionated, shall NOT be constrained, that it should not tell the developer what to do.

I wrote the developers should use their own opinion, set their own constraints, specific for the project they are working on.

Language "generic and usable in many different ways and usage scenarios". But actual usage within a single project according to the opinionated convention of the project.


Most programmers aren't metaprogramming, to them expressiveness isn't a big issue like it is for programmers making frameworks or languages. Making languages less expressive to make the life of framework programmers easier but at the cost of all the other programmers isn't a good trade-off most of the time.


No, lack of powerful tools in a language is not limited to library authors.

If authors can not use powerful tools, they cannot create powerful libraries for other developers to use. Everybody is then pushed down to the low expressiveness level. Case in point: Golang until recently, Java before version 5. Copy-paste programming is as prone to bugs as stringly-typed programming.

If there needs to be a strict separation between powerful tools and easy tools, using two different languages works well enough. Many game engines allow level designers write small Lua scripts, for instance. Or the whole Visual Basic thing which allows to glue together powerful COM components. Also, nearly every templating language allows for simple data manipulation (iteration, filters) while not being Turing-complete.

(That works until the users of the simple glue language require enough features for the glue language to become a principal tools for developing increasingly complex things, and we're in square one. Could have started with a proper language...)


Static types for example, it is one of the few things where the trade-off seems to be worth it, so I agree there are times where the improvement of tools can improve productivity more than expressability of the core language.

But those things are already widely popular, someone saying "we need less powerful languages" means they want even more than that, I'm not aware of any things that aren't currently popular that would improve these things by a lot.


A language that plays with types fast and loose is strictly more "powerful" in the sense that it accepts an attempts to execute more programs than a language with a stringent type system.

Natural language is the most powerful (kind of) language we have, because using it we can generate narrower and stricter languages (mathematics, for instance) and communicate their semantics to fellow humans.

But natural language can express a lot of things that are imprecise, like "huh?" or "well, you know...", or, say, profanities. So a somehow less powerful language, with some restrictions requiring politeness and clarity, is easier to understand. That's the point of the original article, broadly.

That's what I mean by "harnessing" the power. Restricting the language by simplifying it, switching to baby-speak, is what I'd like to avoid: while less powerful and not allowing for many potentially dangerous constructs, it remains imprecise, but loses the ability to express complex things concisely.


> A language that plays with types fast and loose is strictly more "powerful" in the sense that it accepts an attempts to execute more programs than a language with a stringent type system.

Not really though. “Dynamic typing” is really just having a single type for everything. Is quite easy to express in a language with variants. Of course, you don’t usually write code like that in a typed language because then your giving up the value of the type system.


> Golang until recently

But some of the most powerful cloud tooling out there was and is written in Go, and not just recently.

I think Go is a perfect example of the simplicity that can make some very complex software happen.


Mostly because it is what the ecosystem expects, not due to Go by itself.

Just like some other ecosystems expect C, JavaScript or PHP, and they aren't getting any design prices.

Go is a perfect example of how a not so great language, with the right killer use case and corporate sponsorship, gets wide adoption.


Before Go I used to program mainly in C++ which is kind of the worst language in terms of simplicity, so I might be biased. I simply don't know any other simple languages. I have only C C++, Go, Matlab/Octave and Python to compare to (if one wouldn't count Bash and awk). I mainly develop HPC Code.

Based on my expirience I must completely disagree. The language go itself together with its tooling, i.e. compiler , debugger and module system makes it very appealing to write well-written and well-maintaned programs of large size in go. It is the combination of the simplicity of go together with gos property of being a "batteries included" language.

In particular, I have noticed it is much easier for inexpirienced programmers to write high-qhality Code in go than in C.


They would have the same experience with Modula-2, Object Pascal, Delphi, or even Go's predecessors Oberon-2 and Limbo, with the difference that all of them had better tooling for GUI development 20+ years ago.

Faster compile times, debugger, IDE, code formating on save, proper modules, choice of static or dynamic loading,... all there.

Go ties to Google made it have better fortune in the market than those languages.


Well, that “not so great language” is very much an opinion.


An opinion shared by plenty of people.


> … to [most programmers] expressiveness isn't a big issue…

> Making languages less expressive […] at the cost of all the other programmers

Apologies, I’m reading a contradiction here. Help me out?


I meant issue as in problem. They enjoy having an expressive language since it makes it easier for them to work. They don't get much benefits from having a less expressive language where metaprogramming is easier.


Ah - I read “not an issue” as “they are not concerned with.” Thanks for setting me right. :-)


After 20 years of Python being my main language, I switched to Lua last year, and it felt great.

I just felt Python's feature set was becoming too boated, and reading other people's code was becoming too much of a cognitive drain, because others don't tend to subset the language in the same way that I would subset it to keep complexity to a minimum.

Also, the larger feature set of Python means that code written in Python doesn't move between environments as easily. With Lua, I can rely on hobbyist implementations running on top of Java (KeraLua/Luna), .NET (NeoLua), JavaScript (fengari), or native (the original PUC-Lua), where the latter in turn has bindings to other languages (like Python). With Python there has been the same amount of appetite to do these things (Jython, IronPython, various JS-based pythons like Transcrypt, etc.) but they just never achieve actual compatibility with CPython for practical intents and purposes.


I've never met anyone who used lua having experienced other languages without growing to hate it. What's an example of good code in lua, that you would enjoy working on?


I really like being able to easily statically link libraries into the lua interpreter. Spawn a process using libuv and wrap it in a native coroutine to get concurrent execution with fewer failure modes than normal. Embed sqlite and get a friendly repl over your database. Find some utility written in lua and it's similarly easy to embed.

I replaced python with it for misc code generator and admin tasks for that reason. Instead of whatever pip is called these days and global installation conflict nonsense, I can clone a single .c from github that contains lua and all the libraries I've found useful so far.

Mostly it just gets out of your way. Compiler feedback isn't wonderful when you get something wrong but it's adequate. Some conventions are a bit weird but it's fine. Lexical closures, garbage collection and native coroutines make up for them.


How many people do you know who used lua, having experienced other languages, and who did grow to hate it?

What are the properties of the language that they do hate, specifically?

As I've said, my own code is mostly in Lua these days, and I am enjoying working on it. It's closed-source, so I can't point you to it.


I'd be happy to have less focus on the textual symbols someday. Preferably without diving completely away from them into common graphical programming languages.

This is largely doable in any modern environment. Dr Racket, for example, can do fun things. https://docs.racket-lang.org/teachpack/2htdpimage.html Emacs can largely do the same.

What I would love, is an overall system that brought all of these together such that I can have images that are type checked for size or other necessary items by the build to do the next step. Instead, we have forced ourselves into text only. Everywhere. Why can't we have a visual view of what we want the UI to be that is cross linked to the code in a build/check step?


This article is missing the point. It's not just any "powerfulness" that we need to drop.

Languages evolve by limiting expressiveness in ways that increase composability.

The desired direction is one that increases composability, without sacrificing any other valuable properties (like performance).


I was curious about Unity, Godot lately. These "ecosystems" with built in IDE with animation trees, sprite trees, scripting languages make me a little nauseous.

My experience has been that often you have an idea you want to bring to life, programmatically, design-wise, but then you find hurdle after hurdle in trying to shoehorn your idea to make it work in these prefab environments. Eventually you succumb and write the same games everyone else is writing — sigh.

I think I am agreeing. It seems "composability" and "powerful" don't often go hand in hand.


Because these tools are built with non-programmers in mind. We're not talking about people who are not good at programming. We're talking about people who straight up refuse to read/write even the simplest code, because 1) they're afraid of code 2) they're hired as artists/designers/animators and believe code is never mentioned out of their job description.


Not sure about that. The benefit of something like a dumb `MANIFEST.in` file is that it can have many implementations, and many different optimizations, while being absolutely certain that the result logic is the same. Any time you add powerfulness/expressiveness, you limit the ways it can be parsed/refactored/executed/whatever.


Go is waving its hand from one of the desks in the back


Not sure if that is good or bad. The fact that you need to write a util function just to find a value in a slice is hilarious.


I recently gave a talk[0] to data engineers that is an extension of this idea. The conclusion I came to after years of considering this, the Blub paradox and various other sources, is that we should use more languages.

In the talk I mention Gary Miller, who is working on formalizing the tradeoff between expressiveness (as defined by jumps in the language hierarchy) and decidabilities. The TL;DR is that as you jump up the language hierarchy you lose more decidabilities. A decidability is a question that can be answered with a yes/no. For example: "does this program halt?" is a decidability.

Interestingly this also shows a difference between lambda calculi and universal turing machines. When you go from lambda calculi to UTMs, you lose equational reasoning (but depending on how you define an encoding function, you may also gain intensionality). This of course has some implications, which is pretty much a can of worms that nobody wants to touch (i.e. whether the Church-Turing hypothesis is true)

[0]: https://www.youtube.com/watch?v=KOuwZEtHZ_U


There’s a good talk called “ Constraints liberate, liberties constrain” https://youtu.be/GqmsQeSzMdw


I've been doing some zig and I really like how reusable is every little bit of code I write. I do not know if it is because of it's simplicity but I am quite productive with it.


There’s always rust if you want the compiler to tell you you’re not allowed to do something you were intending to do.


"If we submit ourselves to law, Alex, even to the loss of freedoms -- the freedom to indirect through an invalid pointer, for instance -- we may discover new freedoms yet unknown to us." --Abraham Lincoln, Lincoln (2012) (paraphrased)


This is so good, I'm stealing it. Daniel Day Lewis didn't realise he was a C type language on a PDP type architecture.


This is a bad take on a common problem with higher level languages. The burden will always be on the programmer to be responsible for selecting the best approach to implementing any solution while keeping in mind the additional workload they might be inflicting on the tools, system, or subsequent maintainers. The language, at best, can be considered at fault for providing poor documentation and bad examples for use cases (Java comes to mind: Somewhere Oracle's docs suggest defining 15+ line callback function within the argument list for the function that registers it.) which would contribute to the problem. It is possible the issues the author has pointed out instead are related to how easy it might be for an inexperienced developer to utilize the language improperly. Perl is notorious for this and it is a major complaint for everyone who has had to deal with someone else's abomination of a solution. Thus, it is common knowledge for Perl users to familiarize themselves with Conway's book 'Perl Best Practices' in order to a avoid causing grief for both your peers and antecessors.


Yes! I liked the original C because of that. So did Linus: https://www.youtube.com/watch?v=CYvJPra7Ebk

I remember this great talk Growing a Language by Guy Steele, totally on point, about Java... I liked Java: https://www.youtube.com/watch?v=_ahvzDzKdB0

I even liked the original C++ when it came out, and used it (although needing to do >> > was a bit silly). But then it jumped the shark with C++0x and thereafter. Concepts. Lamdas. Time travel. Quantum mechanics. Even Bjarne Stroustrup quit and is like "whaaa"

In this interview with Dennis Ritchie, James Gosling, Bjarne Stourstrup, the latter is the most verbose. And it shows in the C++ features hehe.

When everyone knows the 10 features the language has, teams can work together without a language lawyer and tricky "look ma no hands" code

This is what makes games like Chess great, as opposed to, say, Yu Gi Oh: https://www.youtube.com/watch?v=Wr13DYngSqE&t=4m30s


> When everyone knows the 10 features the language has

You have to be careful here because people will give you/expect emergent behavior to pick up the slack, and then you get a language that has barely any syntax or semantics and all of the functionality comes from stringing a bunch of NewSpeak-looking bullshit together into a system that would make Rube Goldberg suicidal.

As simple as possible, but no simpler.


Haha, brainfuck is simple and only has five features that everyone knows but...there's going to be a decent number of patterns you'll have to memorize.


As someone who's spent a thousand hours or so thinking about the board game Go, I'm quite familiar with the idea of simple rules with an explosion of consequences.

Unfortunately I'm also familiar with the consequences in software. Fractal code sounds like it might be cool until you have to edit it, especially if it's someone else's. This is the domain of madmen.


The web became successful because of the constrained formats of URL's, HTTP and HTML. This allowed linking between uncoordinated parties and it allowed indexing and searching. In contrast, powerful executable "black box" objects have been suggested as a better alternative to the constraints of the web, and Java applets and MS Silverlight were implementations of this idea. But they never solved the basic problems if linking and searching. Even JavaScript-heavy sites have trouble with supporting indexing.


In a way, type-systems are less powerful non-turing-complete languages that are guaranteed to halt, thus can be checked at compile-time.

I think we need powerful but easy-to-restrict languages. Can you mark that function as pure, as not safe? that kind of thing.


Hmm. People are talking about languages like C?

I presumed (and even after reading, though not in detail) that this was more in the space of how some games are done, with C for the low level stuff and Lua for game logic, which I think is a good idea.


Disclaimer: this essay of a comment is sort of an ad for my ideas.

At the time this article came out, I had been designing a language for 2-3 years. I'm still designing it now, so I have more than 10 years experience.

The author is right and wrong. The W3C principle is right and wrong. Paul Graham is right and wrong.

The author and W3C are right in that the less power you have, the better for understanding, analysis, and even optimization/performance. Paul Graham is right that you need power.

I only realized this recently after working on a build system, which might be the most hated type of software. As I designed mine, I wanted to do it right, to avoid the mistakes.

The biggest mistake, and one common to nearly every build system was not providing the user enough power.

The common opinion about building software is that it shouldn't be that hard. Most of the time, that's correct. But when it is hard, there is nothing that will work except raw power. When you need it, truly need it, literally nothing else will do, by definition.

This leads to a quandary because by the time a project runs into a situation where building is hard, the build system is deeply entrenched. This means that changing the build system would be difficult and time-consuming for little perceived benefit. Instead, users find ways around a build system's lack of power (usually by writing a script; after all, a script is powerful) and moan about how the build system is a problem.

I agree with them: such hamstrung build systems are problems.

But at the same time, an all-powerful build system would be complicated to use, right?

Spoiler: no, but to do it right takes actual design and user experience work instead of just coding.

But let's assume it is too complicated to use. What can we do? We need the power, but the power makes it too complicated. Should we just throw up our hands and accept that the complexity is inherent, or should we hamstring the build system and hope we don't need the power?

Absolutely not. Would we do that with our programming languages? No, so removing the power is not an option.

Most of the time.

What if we could remove the power some of the time? Let's say it's a config option we put into the build file. Maybe that option can be one of several things:

1. Only targets and commands, like a pure POSIX make Makefile.

2. Like the above, but add conditionals, like `if` statements.

3. Like both of the above, but add constrained `for` loops.

4. Screw it, add `while` loops and make it Turing-complete.

5. Let's go Hole Hawg [1] and add metaprogramming!

Some projects will never leave level 1. Some will never leave level 2. Most will never leave level 3. Most of the remaining few will never leave level 4. But for those that need it, level 5 still exists! And more importantly, so does level 4.

This means that the projects that don't need power won't use it and can have all of the advantages of a less-powerful language. It also means that the other projects won't curse their build system. Everyone's happy!

(As a sidenote: implementing this idea is easy; the build system just needs to not allow certain "keywords" in each setting. In fact, you could make it even more granular by allowing users to forbid individual keywords!)

This is an extension of a comment I wrote recently. [2] I replied to someone who asked if Guy Steele was right when he said to restrict the grammar of your language.

My answer: he was, unless you need power. The more powerful your language, the more likely that an LR(1) grammar is not sufficient for it, to the point that for the most powerful of languages, only an all-powerful Turing-complete parser can parse them.

There is no substitute for power. But use as little as possible.

So yes, we need less powerful languages. We also need more powerful ones.

Perhaps what we really need is a language whose power you can tune to your needs. (Shameless plug: stay tuned!)

[1]: Read the "Hole Hawg" section of "In the Beginning Was the Command-Line" by Neal Stephenson. https://web.archive.org/web/20180218045352/http://www.crypto...

[2]: https://news.ycombinator.com/item?id=34416730


Define "need".


Nothing less powerful will work, so that power is necessary.

There are many things you can do without full Turing-completeness, but when you must do something that requires it, there is no other alternative.


You have clearly thought about this quite a bit; you expounded at length in your original comment, which if I had to guess only glances upon the totality of your reasoning to present a summary of it here.

Can you elaborate on why in your use case moar power is a requirement? Basically, fleshing out what would go in the "Need" section of the NABC model (and a partial preview of "Competitors"):

- <https://candost.blog/how-to-stop-endless-discussions/>

- <https://news.ycombinator.com/item?id=25623388>

Is it possible that the need is really just perceived and not actual, e.g. in the vein of programmers who demand the use of features in dynamic languages for things where they don't truly need that power <https://doi.org/10.1007/s10664-012-9203-2>?


> You have clearly thought about this quite a bit; you expounded at length in your original comment, which if I had to guess only glances upon the totality of your reasoning to present a summary of it here.

Correct. And thank you for the compliment.

And also great questions.

> Can you elaborate on why in your use case moar power is a requirement? Basically, fleshing out what would go in the "Need" section of the NABC model (and a partial preview of "Competitors")

So in my use case, more power is not needed. However, when you have a million users, there will be a user with a use case that requires that power. That is, unfortunately, the curse of generality.

As an example, most people think that full Turing-completeness is not necessary for a build system. At least one example I know of shows this to be false: processing TeX and LaTeX. This is because the process involves doing the layout; resolving links, footnotes, etc.; redoing the layout for the changes; redoing the resolution; redoing the layout; etc. This continues until a fixed point.

This iteration until a fixed point means that you can't use set iteration; you have to use a while loop. And a non-Turing-complete language simply cannot implement a while loop, by definition. If it did, it would be Turing-complete, in the sense that it could compute anything that any other Turing-complete language could. You could try to add a while loop to a non-Turing-complete language and keep it non-Turing-complete, but it wouldn't be anymore because the very existence of while loops makes a language Turing-complete.

This gets into the theory of computation (about the only time my Bachelor's in Computer Science is useful), but suffice it to say that if you need a while loop, you need a full Turing-complete language, and Turing-completeness technically make the most powerful kind of language.

(The metaprogramming doesn't really add power according to the theory of computation, but it does compress the program required, in that less code is necessary, which makes the program easier to hold in one's head. I think this is what Paul Graham was preaching for when he claimed that Lisp macros were more powerful. But there is also the possibility of the language placing artificial limitations while still being technically Turing-complete. Metaprogramming is meant to remove those artificial limitations.)

> Is it possible that the need is really just perceived and not actual, e.g. in the vein of programmers who demand the use of features in dynamic languages for things where they don't truly need that power?

Most of the time, yes, it will just be programmers that think they need the power, but they don't. I totally agree with that.

But there will be a time or two when the programmer really does need that power, and it had better be there.


Many compiler devs want the most complex language as possible, because it increase exponentialy developer/vendor lock-in.


That is misattributed malice.

Firstly language devs are some of the most pro tiny languages people out there, it's the users that ask for the kitchen sink (though not the same kitchen sink as their neighbour)

Secondly people doing something because they like it want to continue working on said thing?! What a surprise.

This is not malice


I do attribute that to malice by default, until proven otherwise.

This is my opinion, pleasant or not, this is not on a whim.


Can you name one language that this is true for?

Also, this looks like a clear violation of Hanlon's razor: never attribute to malice that which is adequately explained by stupidity.

Not that I'm calling compiler devs stupid, but like languages (and systems overall) do tend towards increased complexity over time. This is the default trend no matter the subject. It takes clear, agreed-upon goals and hard work to keep that from happening.


As I said this is not on a whim.

llvm/gcc devs do not realise that there is an issue with those compilers reaching a complexity and size fairly qualified as absurd and grotesque. Since it has been roughly 2 decades, I am finished to believe those devs are merely blinded by an accute lack of experience, that's why for me those devs are actually malicious for developer/vendor lock-in, that on top of the other big issue which is planned obsolescence (mostly syntax and compiler extensions). This is so accute that the other alternative, since I now exclude any accute lack of experience, would be to start questioning their sanity, and I think we are dealing with evil, not medical pathology.

I am very serious about this.




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: