“Stop Designing Languages. Write Libraries Instead” (2016)

2026-01-0712:29279278lbstanza.org

Patrick S. Li - May 29, 2016I had a friend tell me recently that all programming languages seem very similar to each other. They all have variables, and arrays, a few loop constructs, functions, and…

Patrick S. Li - May 29, 2016

I had a friend tell me recently that all programming languages seem very similar to each other. They all have variables, and arrays, a few loop constructs, functions, and some arithmetic constructs. Sure, some languages have fancier features like first-class functions or coroutines, but he doesn't consider himself an expert programmer anyway and doesn't use those features.

What really makes a programming language productive for him, he says, are the libraries it comes with. For example, he got into programming by using the popular Ruby on Rails web framework. There is no way that he could have written a full database-driven web stack by himself, nor is he interested in doing so. But thanks to Ruby on Rails, he doesn't have to! So he said that he has no particular opinion about the Ruby programming language, but he absolutely loves Rails. The vast majority of programmers are non-experts, like himself, and the largest gains in productivity for non-experts come from having a wide spectrum of easy-to-use libraries. Subtle language features like first-class functions, and object systems, are lost on them because they don't really use them anyway. Computer scientists should really be spending their time developing new libraries rather than inventing new programming languages.

My friend's opinion about programming languages is a common one, and I have heard it repeatedly from experts and non-experts alike. Being a language designer myself, I, of course, don't share this opinion. Here is what I consider to be the purpose of a general-purpose programming language.

To start off, I would say that my friend's opinion is completely correct, just incomplete. The greatest productivity gains are indeed the result of having a wide spectrum of libraries. Ruby on Rails is a fantastic framework, and it has enabled thousands (if not millions) of non-experts to build sophisticated websites quickly. So the natural question then is, why isn't there now a Rails framework for every programming language?

Some languages that are semantically similar to Ruby do have their own web frameworks. Python, for example, has Django. But as of now, there is still no decent web framework for Java that is as easy to use as Ruby on Rails. Why is that? Are Java developers just not as competent as Ruby programmers? If David Hansson could design and develop Rails by himself, why can't a group of programmers just copy the design to Java? What makes this even more embarrassing is the fact that Java initially marketed itself as the web programming language, because of its applet technology. To emphasize this point, let me add that there is no good web framework for C either, and it is unlikely that there ever will be. Let me assure you that it's not because C programmers are worse than Ruby programmers.

Economics is not the reason either. The Tiobe index lists Java and C as the most widely used programming languages today, with Ruby coming in eighth place. There are many times more Java and C programmers than there are Ruby programmers. If someone would just write Java on Rails their framework would have many times more users than Ruby on Rails, and it would instantly propel him to internet fame and fortune.

So it's not because of incompetency. Nor is it because of economics. So why else wouldn't someone port Ruby on Rails to Java? Well, simply, because they can't.

If you're a knowledgeable Ruby programmer and you take a deep look through an introductory Rails tutorial, you'll notice that pretty much all of the Ruby language features come into play in some way. Rail's ActiveRecords library makes pervasive use of Ruby's meta-programming features. Rail's template system heavily relies upon Ruby's runtime evaluation features. To make your website respond to a user click, you subclass ApplicationController and reuse pre-coded functionality by importing various mixins. Events are handled often by attaching a call back in the form of a first-class function to some widget. Casual website designers can safely completely ignore the concepts of types and memory deallocation because Ruby is dynamically-typed and garbage-collected. 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.

So, completely unbeknownst to my friend, he is actually making heavy use of all those subtle language features that he claimed he never cared about. And this is intentional! Ruby on Rails was designed to make it possible to build websites without understanding type theory, or memory management, or object-oriented design patterns. Rails allow website designers to focus on designing websites, not managing their software infrastructure. My friend is enjoying all the benefits of Ruby without even knowing it, and that's the whole point.

Taking a step back, the concept of packaging code into easy-to-use libraries is not new. It's been around even in the days when programs were stored on punched paper tape. There are still vast libraries of assembly code containing useful subroutines. And every programming language ever designed provided some way for common functionality to be reused. To me, this is the primary purpose of a general-purpose programming language, to enable the creation of a wide spectrum of easy-to-use libraries.

The design of the programming language directly determines what sort of libraries you can write and how easy they are to use in the end. In the C language, the only major feature provided for enabling reuse is the ability to declare and call functions. So guess what? The majority of C libraries are basically large collections of functions. Ruby on Rails provides a concise way for expressing: do this when the button is clicked. 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? Well, the behaviour of first-class functions can be mocked by defining a new event handler class with a single perform_action method and then passing an instance of this class to the button object. So guess what? Using a Java library typically entails declaring a humongous number of handler classes. The programming language directly shapes the design of its libraries.

In the early days of software, collections of functions were sufficient in allowing us to code reusable components. A lot of early software was numerical in nature, and there was a library function for every numerical algorithm you would want to run. Numbers go in. Numbers come out. Functions were perfectly adequate for this. Unix and C were also designed in a time when the majority of computing happens in batch mode. You prepare some input data, call a function or run a program, and you get some output data back. But computing has changed radically since the 70's. Nowadays, most interesting programs are interactive. When a user clicks a button, it should do something. It was rare to want to extend the functionality of a library of the 70's. The library provides a collection of useful functions. If one of them does what you want, then use it. If not, then write your own. But with the advent of interactive software, the need for extensible libraries became apparent. Programmers wanted GUI libraries that allowed them to say: when a user clicks a button, please run my code. Java (and C++) provides a limited method for extending an existing library's functionality through its subclassing mechanism. So using a Java library often consists of subclassing a number of magical classes and then overriding a number of magical methods. This style of library became so pervasive at one point that we even gave them a new name. They're called frameworks.

I surmise that probably many general purpose programming languages were originally designed because of the author's inability to write a good library for the language that he was using at the time. The initial impetus that got me thinking about designing Stanza, for example, came out of my frustrations with trying to write an easy-to-use game programming library in Java. To handle concurrency, traditional game programming frameworks required sprite behaviours to be programmed using a state machine model. But that's not how we intuitively think about sprites in our heads. Intuitively, we think about a character's behaviour as consisting of a sequence of steps. For example, first the character jumps, and then after he lands he looks to his left and then his right for the nearest enemy. If he sees one then he goes to attack it, otherwise he jumps again. He does this three times, and if he doesn't see an enemy after three jumps, then he takes a short nap. Transforming this sequence of steps into a state machine is an incredibly tedious and error-prone process, and most importantly, feels repetitive. It felt like I was doing the same thing again and again. So the natural question is, can I just make this state machine transformation a library and re-use it? It turns out I couldn't, not in Java at least. The language feature that I needed was some sort of coroutine or continuation mechanism. After some research I found that the Scheme language supports continuations, so the Scheme version of my game programming library was much easier to use than the Java version.

Because of its support for continuations, the Scheme version of my game library does not require users to write their sprite behaviour as state machines. But it wasn't better than the Java version in every way. Most importantly, the Java version was statically typed and so the compiler automatically caught many of your mistakes for you. The Scheme version didn't have this ability and thus debugging my games took a bit longer. 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. Stanza doesn't either. It just attempts to provide one that is useful for a wider audience.

Since the purpose of general-purpose programming languages are to enable the creation of powerful libraries, this means that different languages can also be characterized by what features they provide that cannot be written as libraries. Stanza provides an optional type system, garbage collection, and a multimethod based object system. But if you don't like Stanza's object system, there is no way to write your own. This is one of the main directions of programming language research. Can we design a language so expressive that library writers can easily write the most appropriate object system, or most appropriate type system, to fit their application? Perhaps one day we'll have such a language. Racket and Shen provide mechanisms for extending their type systems and research on meta-object protocols were attempts at designing extensible object systems. So languages are differentiated by what types of libraries you can write in them and what types of libraries you can't.

In summary, the purpose of a general-purpose programming language is to enable the creation of powerful and easy-to-use libraries. The more powerful the language, the easier the libraries are to use. Code that makes use of a perfectly tuned library should read almost like a set of instructions for a coworker. So the next time you come across a particularly elegant library, know that many decades of language research has gone into making that possible. If you're curious about specifically which language features a library makes use of, then you can dig deeper, explore, and appreciate the thought that went into its implementation. If you're not curious about all this subtle language stuff, you can safely ignore it all and get on with your work. That's the whole point.


Read the original article

Comments

  • By jmmcd 2026-01-0714:0516 reply

    The best example of all is Prolog. It is always held up as the paradigmatic representative of logic programming, a rare language paradigm. But it doesn't need to be a language. It is really a collection of algorithms which should be a library in every language, together with a nice convention for expressing Prolog things in that language's syntax.

    (My comment is slightly off-topic to the article but on-topic to the title.)

    • By bux93 2026-01-0716:273 reply

      The main thing about prolog isn't the algorithms. In fact, the actual depth-first search isn't even part of the standard.

      The nice thing about prolog is that you write logical rules, and they can get used in whatever order and direction that is needed. By direction, I mean that if you define "a grandparent is the parent of a parent", you can now use that rule not just to evaluate whether one person is a parent (or to find all grandparents) but also to conclude that if you know someone is a grandparent, and they are the parent of some one, then that person is someone's parent. Ok, it can also do recursion, so if you define an ancestor as a parent or the parent of an ancestor it will recurse all the way up the family tree. Neat.

      You could write some kind of runtime that takes c code and brute-forces its way from outputs to inputs, except that regular imperative code allows for all kinds of things that make this impossible (e.g. side-effects). So then, you'd be limited to some subset, essentially ending up with a domain specific language again, albeit with the same syntax as your regular code, rather than those silly :- symbols (although LISP looks much sillier than prolog IMHO).

      What the article is getting at is that if you use some features specific to a language, it's hard to embed your code as a library in another language. But is it? I mean, DLLs don't need to be written in the same language, there's stuff like JNI, and famously there's stuff like pytorch and tensorflow that runs CUDA code from python.

      • By DonHopkins 2026-01-0814:02

        >The nice thing about prolog is that you write logical rules, and they can get used in whatever order and direction that is needed.

        This generalizes!

        Prolog: declare relations. Engine figures out how to satisfy them. Bidirectional -- same rules answer "is X a grandparent?" and "find all grandparents."

        LLMs do something similar but fuzzier. Declare intent. Model figures out how to satisfy it. No parse -> AST -> evaluate. Just: understand, act.

        @tannhaeuser is right that Prolog's power comes from what the engine does -- variables that "range over potential values," WAM optimization, automatic pruning. You can't get that from a library bolted onto an imperative language. The execution model is different.

        Same argument applies to LLMs. You can't library your way into semantic understanding. The model IS the execution model. Skills aren't code the LLM runs -- they're context that shapes how it thinks.

        Prolog showed that declarative beats imperative for problems where you can formalize the rules. LLMs extend that to problems where you can't.

        I've been playing with and testing this: Directories of YAML files as a world model -- The Sims meets TinyMUD -- with the LLM as the inference engine. Seven architectural extensions to Anthropic Skills. 50+ skills. 33 turns of a card game, 10 characters, one LLM call. No round trips. It just works.

        https://github.com/SimHacker/moollm/blob/main/designs/stanza...

        https://github.com/SimHacker/moollm/tree/main/skills

      • By xigoi 2026-01-089:181 reply

        > By direction, I mean that if you define "a grandparent is the parent of a parent", you can now use that rule not just to evaluate whether one person is a parent (or to find all grandparents) but also to conclude that if you know someone is a grandparent, and they are the parent of some one, then that person is someone's parent.

        Not necessarily.

        • By f1shy 2026-01-0811:121 reply

          Could you please expand? Because I have the same state of knowledge of the previous poster. I would like to learn if I'm wrong.

          • By xigoi 2026-01-0811:44

            Someone who is a grandparent may also have other children who do not have children.

      • By eternityforest 2026-01-0721:30

        Debugging rarely works correctly between languages, and features like "find all references" usually break too. Maybe that's not an issue with Prolog because a C logic solver would also be hard to debug, but it's a problem with many template languages.

    • By tannhaeuser 2026-01-0717:362 reply

      The syntax of Prolog is basically a subset of the language of First Order Logic (sans quantifiers and function symbols), it doesn't get any more minimal than that. What's special in Prolog compared to imperative languages including functional languages is that variables aren't "assigned" but implicitly range over potential values until satisfying the context, like in math formulas for sets. Yes you can express that awkwardly with tons of type annotations and DSL conventions so that you never have to leave your favourite programming language. But then there's the problem of a Prolog "engine" doing quite a bit more than what could be reasonably assumed behind a synchronous library call, such as working with a compact solution space representation and/or value factoring, parallel execution environment, automatic value pruning and propagation, etc.

      The integration of a Prolog backend into a mainstream stack is typically achieved via Prolog code generation (and also code generation via LLMs) or as a "service" on the Prolog side, considering Prolog also has excellent support for parsing DSLs or request/responses of any type; as in, you can implement a JSON parser in a single line of code actually.

      As they say, if Prolog fits your application, it fits really well, like with planning, constraint solving, theorem proving, verification/combinatoric test case enumeration, pricing models, legal/strategic case differentiation, complex configuration and the like, the latter merely leveraging the modularity of logic clauses in composing complex programs using independent units.

      So I don't know how much you've worked hands on with Prolog, but I think you actually managed to pick about one of the worst rather than best examples ;)

      • By hyperhello 2026-01-085:381 reply

        You can implement a JSON parser in a single line of code in C, but why?

        • By pjmlp 2026-01-0813:16

          To win an entry at IOCCC.

      • By derangedHorse 2026-01-083:522 reply

        > So I don't know how much you've worked hands on with Prolog, but I think you actually managed to pick about one of the worst rather than best examples ;)

        Seems more like an interesting research project than something I'd ever deploy in an application serving millions of users

        • By iamevn 2026-01-085:09

          I can't speak to any sort of scalability but I can definitely say that not everything needs to be built for millions of users. There's plenty of utility in tools you use to help even a single person (even yourself!)

        • By acuozzo 2026-01-086:19

          > Seems more like an interesting research project

          You mean like the kinds of problems digital computing was originally invented to solve?

          You know that still exists, right? There are many people using computers to advance the state of Mathematics & related subjects.

    • By RHSeeger 2026-01-0715:213 reply

      By that same logic, we don't need object oriented features in a language, because we have closures and can get the same functionality with a library.

      Sometimes, having a language with a distinct syntax is nicer.

      • By HelloNurse 2026-01-0715:49

        Typically, what's nicer is the absence of other features that interfere with the important ones.

        For example, Prolog isn't a general purpose functional or imperative language: you can assert, retract and query facts in the automatically managed database, risking only incorrect formulas, inefficiencies and non-monotonicity accidents, but not express functions, types, loops, etc. which could have far more general bugs.

      • By vjerancrnjak 2026-01-0716:071 reply

        I like how classes escape closures but then dependency injection frameworks have to work around that because now it is hard to think of construction as passing arguments to functions in the correct order.

        I am so glad LLMs eliminate all of that and just call functions in the right order.

        • By marcosdumay 2026-01-0719:111 reply

          > I am so glad LLMs eliminate all of that

          When LLMs do something, it's always because everybody was already doing it.

          The noise you see online about it exists exactly because most people don't understand and can't use DI.

          • By vjerancrnjak 2026-01-0719:392 reply

            No, LLMs like NextJS style injection as much as anyone.

            There is nothing magical about topological sort and calling constructors in the right order, which is all DI is.

            I dislike it a lot, it is exactly like any other construct that allows you to throw code at anything in a way that sucks (Haskell lens, optics, monad transformers).

            It allows people to granularize the whole codebase to the point where you can’t do much about it. For most, they should just stick with functions, no one can build 100 levels deep function callstacks without it being cumbersome, but DI makes it a breeze.

            • By almosthere 2026-01-085:22

              I fell out of love with Java not because of the language, but because it got tied up with DI. Don't get me wrong, the allure of DI is really neat. Make all sort of interfaces and just call the function and it can be implemented by dozens of things. Perfect for a lot of use-cases. But then reality hits, and you eventually realize how complex the entire codebase is because it's pattern 1, pattern 2, p3, p4, etc... People are so obsessed with GoF patterns that they're not getting anything done other than spending the first month on a beautiful API.

              Then I got into Python and people were building useful server APIs in a day.

              Both have their place, but I think the problem with the first route is that EVERYTHING ends up with Spring or CDI and complexity overload even if only 1 thing will ever be "implemented".

            • By marcosdumay 2026-01-0817:17

              > There is nothing magical about topological sort and calling constructors in the right order, which is all DI is.

              Lol... That's exactly the kind of thing we call "magic" in software development.

              Anyway, if your framework is entirely based on DI, everybody that uses the framework will use DI, and the LLMs will generate code for it that uses DI. That does not contest my point in any way.

      • By f1shy 2026-01-0811:18

        Absolutely. In the same direction as some people I've heard along the lines of "Anything you can do with language X, can be done with assembler, just have some routines for that in your stash"

    • By JoelMcCracken 2026-01-0715:571 reply

      The only languages I know that can do prolog-like-constructs as-a-library are lisps, or at least langs that have reasonable symbol constructs. Usability is way way worse if you can’t talk about variables as first class objects.

      I was talking to Bob Harper about this specific issue (context was why macro systems are important to me) and his answer was “you can just write a separate programming language”. Which I get.

      But all of this is just to say that doing relational-programming-as-a-library has a ton of issues unless your language supports certain things.

      • By vlovich123 2026-01-0716:103 reply

        I believe Rust uses datafrog, Datalog as a library to implement some of its next gen solvers for traits and lifetimes. Not a lisp and maybe this still isn’t as elegant as you had in mind? Curious how this library compares for you.

        https://github.com/rust-lang/datafrog

        • By brabel 2026-01-0718:29

          If you want to see what it looks like when you actually embed Datalog in your language, have a look at Flix: https://flix.dev/

          (Select the "Usinag Datalog..." example in the code sample dropdown)

          The Rust code looks completely "procedural"... it's like building a DOM document using `node.addElement(...)` instead of, say, writing HTML. People universally prefer the declarative alternative given the choice.

        • By eru 2026-01-0716:311 reply

          Haskell can do the same, and does with a lot of little embedded DSLs.

          • By JoelMcCracken 2026-01-0814:331 reply

            Yea I’ve wanted to try using logict to do some larger logic programming stuff. I’ve done it with list monad but found a lot of speed issues, never quite figured out why it was so slow.

            • By eru 2026-01-096:301 reply

              Well, lists are really slow.

              To be more precise: lists in your code can be really fast, if the compiler can find a way to never actually have lists in the binary it produces. If it actually has to have lists at runtime, it's generally not all that fast.

        • By debugnik 2026-01-0810:27

          The experimental "Polonius" borrow checker was first implemented with datafrog, but I believe it's been abandoned in favour of a revised (also "Polonius") datalog-less algorithm.

    • By somat 2026-01-087:005 reply

      Speaking of prolog, any recommendations for resources learning it at a stage somewhere between "draw three circles" and "draw the rest of the owl"

      I don't have real work I need prolog for, but I find it an interesting subject, My personal learning goal, the point where I can say I know prolog reasonably well is when I can get it to solve this mit puzzle I found, a sort of variant of soduku. I found a clever prolog solver for soduku that I thought could teach me more in this domain, but it was almost to clever, super optimized for soduku(it exploited geometric features to build it's relationships) and I was still left with no idea on how to build the more generic relationships I need for my puzzle(specific example if soduku cells were not in a grid how could they be specified?), in fact I can find very little information on how to specify moderately complex, ad hoc relationships. One that particularly flummoxed me was that some rules(but you don't know which) are wrong.

      https://www.swi-prolog.org/pldoc/man?section=clpfd-sudoku

      • By dmpk2k 2026-01-089:26

        The only decent Prolog book out there, IMNSHO, is "Clause and Effect" by Clocksin. Maybe some of the later chapters might help?

        All the other books that I looked at were pretty awful, including the usual recommendations.

      • By f1shy 2026-01-0811:16

        I got recommended and have in my bookshelf "The art of prolog" waiting for the year when I have time (or need) for it.

      • By billfruit 2026-01-0810:48

        Prolog Programming for Artificial Intelligence" by Ivan Bratko, is a reasonable text book on Prolog.

      • By pjmlp 2026-01-0812:02

        I would go with the reference, "The Art of Prolog".

        If you want to learn LP concepts in general, Tarski's World is a great resource as well.

      • By dayjaby 2026-01-0822:29

        Sudoku*. Suu means numbers in Japanese and Doku means solving here. So literally "number solving".

    • By ModernMech 2026-01-0715:121 reply

      But why should it be though? You haven’t really addressed that. It’s like saying “Haskell shouldn’t be its own language, it should just be a couple of features like lambdas integrated into a JavaScript library”. Well if you do that you get some nice features in JavaScript but you’ve done away with the whole value proposition of pure functional programming. That’s an actual loss, there’s something to be said for maintaining a pure set of features that gives languages different properties and guarantees you can’t get with “everything is just a lib to an imperative language”

      • By kevindamm 2026-01-0715:25

        Pure functional programming and lazy evaluation.. sure, you could create classes and a meta-function that selectively eval's thunks at a time, but the call site of that kind of library would look atrocious..

        You might be able to hack on some of the datatype semantics into JS prototype-based inheritance (I'd rather start with TypeScript at that point, but then we're back at the "why isn't it a library" debate) to keep those ontologies from being semantically separate, but that's an uphill battle with some of JS's implicit value conversions.

        I consider Logic Programming languages to be the go-to counterargument to TFA but yeah, anything with lazy eval and a mature type system are strong counterexamples too.

    • By jandrese 2026-01-0718:40

      Prolog is great because when it works it feels like magic. You give it some pragmas and it tells you the answer. The downside is when it doesn't work it also feels like magic. It's not easy to reason about the amount of work it needs to do. If your Prolog program is taking a long time to run it is hard to figure out if it is going to take 2 hours or 4,000 millennia.

    • By slaymaker1907 2026-01-0714:541 reply

      I think the examples others have highlighted show the problem with just making it a library. They’re all lacking a lot of features from Prolog, particularly in terms of optimization. Just use Prolog if you need its features and invoke SWI-Prolog like you’d call any other language’s interpreter.

      • By whstl 2026-01-0718:02

        Agree. The optimization caveat also applies to OOP, another example someone threw in above.

        Sure you can implement OOP as a library in pretty much any language, but you’ll probably sacrifice ergonomics, performance and/or safety I guess.

    • By bwestergard 2026-01-0714:236 reply

      Are there any particularly excellent examples of prolog implemented as a library you could point us to?

      • By dunham 2026-01-0715:06

        As an example of a use case, "Gerrit Code Review"[1] is written in Java and uses prolog for the submit rules.[2]

        I haven't looked into the implementation. But taking a brief glance now, it looks interesting. They appear to be translating Prolog to Java via a WAM representation[3]. The compiler (prolog-cafe) is written in prolog and bootstrapped into Java via swi-prolog.

        I don't know why compilation is necessary, it seems like an interpreter would be fast enough for that use case, but I'd love to take it apart and see how it works.

        [1]: https://www.gerritcodereview.com/ [2]: https://gerrit-documentation.storage.googleapis.com/Document... [3]: https://gerrit.googlesource.com/prolog-cafe/+/refs/heads/mas...

      • By khaled_ismaeel 2026-01-0714:272 reply

        Not exactly prolog, but logic programming implemented as a library/DSL: https://minikanren.org/

        • By jayd16 2026-01-0716:071 reply

          If it's a DSL then it's "writing a new language" and you're just calling from a native API, no?

          • By naasking 2026-01-0818:09

            Embedded DSLs are libraries. They are the epitome of the advice to write a library. It just so happens that the library abstractions could map to a language if you wanted to add parsing and all of the other machinery.

        • By EricRiese 2026-01-0717:30

          Clojure's core.logic is based on minikanren, so that fits the bill.

      • By ramses0 2026-01-0714:42

        My time to shine! https://news.ycombinator.com/item?id=45902088

        References were Racket with the Racklog library¹. There's also Datalog² and MiniKanren, picat, flix. There were tons of good comments there which you should check out, but PySwip seemed like "the right thing" when I was looking at it: https://github.com/yuce/pyswip/

        ...documentation is extremely sparse, and assumes you already know prolog, but here's a slightly better example of kindof the utility of it:

        https://eugeneasahara.com/2024/08/12/playing-with-prolog-pro...

        ...ie:

            # ya don't really care how this works
            prolog.consult("diabetes_risk.pl")
        
            # ...but you can query into it!
            query = "at_risk_for_diabetes(Person)"
            results = list(prolog.query(query))
        
        ...the point being there's sometimes some sort of "logic calculation that you wish could be some sort of regex", and I always think of prolog as "regexes for logic".

        One time I wished I could use prolog was trying to figure the best match between video file, format, bitrate, browser, playback plugin... or if you've seen https://pcpartpicker.com/list/ ...being able to "just" encode all the constraints, and say something like:

           valid_config = consult("rules.pl")
              + consult("parts_data.pl")
              + python.choice_so_far(...)
        
           rules.pl: only_one_cpu, total_watts < power_supply(watts)
           parts_data.pl: cpu_xyz: ...; power_supply_abc: watts=1000
           choices: cpu(xyz), power_supply(abc), ...
        
        ...this is a terribly syntactically incorrect example, but you could imagine that this would be horrific code to maintain in python (and sqrt(horrific) to maintain in prolog), but _that's_ the benefit! You can take a well-defined portion and kindof sqrt(...) the maintenance cost, at the expense of 1.5x'ing the number of programming languages you need to expect people to know.

      • By exe34 2026-01-0714:29

        not prolog but logical programming in python: https://sites.google.com/site/pydatalog/

      • By chii 2026-01-0714:25

        not OP, but for clojure : https://github.com/bobschrag/clolog

    • By DonHopkins 2026-01-0813:44

      How many Prolog programmers does it take to change a lightbulb?

      false.

      https://www.j-paine.org/dobbs/prolog_lightbulb.html

      I always wanted to write a compiler whose front-end consumes Prolog and back-end emits PostScript, and call it "PrologueToPostscript".

      prologue: a separate introductory section of a literary, dramatic, or musical work.

      postscript: an additional remark at the end of a letter, after the signature and introduced by ‘PS’.

    • By rienbdj 2026-01-0719:20

      Think of Prolog the language as just a serialization of a Prolog AST. The AST could be constructed in any programming language as a library. But what if we want to share and store these ASTs? We can serialize them to Prolog the language! The language has value even if it’s a library.

    • By f1shy 2026-01-0811:11

      Disclaimer: I've no idea what I'm talking about. :)

      But I have heard repeatedly that the good thing of prolog is the compiler, that takes information and queries that would be awful inefficient, and convert them in something that actually works. So I'm not sure... of course, you can convert virtually any language in a kind of library with some API that basically accepts source code... but I'm pretty sure is not what you meant.

    • By zahlman 2026-01-085:101 reply

      Prolog admittedly mystifies me even more than the Haskell family. How do you do anything effectful, like read from a file, or output arbitrary data to standard out, or set up a loop to process keyboard events every 1/n seconds? How do you make system calls?

    • By nine_k 2026-01-0719:03

      Prolog is a contrived example. It's small and simple enough to be implemented as a DSL embedded in another language, reusing most of the parser and leaningn its execution logic.

      Now try to produce a library that adds compile-time features: static types, lifetimes, the notion of const and constexpr, etc. You can, of course, write external tools like mypy, or use some limited mechanism like Java annotations. But you have a really hard time implementing that in an ergonomic way (unless your language is its own metalanguage, like Lisp or Forth, and even then).

      Creating a library that alters the way the runtime works, e.g. adding async, is not entirely impossible, but usually involves some surgery (see Python Twisted, or various C async libs) that results in a number of surprising footguns to avoid.

      Frankly, even adding something by altering a language, but not reworking it enough to make the new feature cohesive, results in footguns that the source language did not have. See C#'s LINQ and exceptions.

    • By pjmlp 2026-01-0715:17

      Except when implemented as library it doesn't take advantage of WAM and related JIT.

    • By chii 2026-01-0714:23

      i treat it like i treat SQL.

  • By rors 2026-01-0713:509 reply

    I was big fan of Scala a decade ago. The idea of a “scalable language” where DSLs could be built within the type system seemed super powerful. I lost my enthusiasm when the community decided they wanted to use it as Haskell on the JVM.

    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.

    • By Cthulhu_ 2026-01-0715:044 reply

      That's the main issue I found with Scala, and as I grow older also with certain libraries (especially in unit testing land) that try to add a language / DSL on top. Not only do you need to learn Scala, you need to learn various DSLs on top of that depending on what you use or want to achieve. Some egregious examples here and there.

      I'm sure there's good use cases for it - one impressive example at the time was using functional programming to create Hadoop map / reduce jobs, a oneliner in Scala was five different files / classes in Java. But for most programming tasks it's overkill.

      You can write boring code in Scala, but in my (limited) experience, Scala developers don't want to write boring code. They picked Scala not because it was the best tool for the job, but because they were bored and wanted to flex their skills. Disregarding the other 95% of programmers that would have to work with it.

      (And since these were consultants, they left within a year to become CTOs and the like and ten years on the companies they sold Scala to are still dealing with the fallout)

      • By f1shy 2026-01-0811:25

        > Not only do you need to learn Scala, you need to learn various DSLs on top of that depending on what you use or want to achieve

        That is AFAIK the "curse of lisp" because is so easy (and needed and encouraged) to write SDLs, any ecosystem grows many languages in a hurry, so suddenly that elegant minimalistic beautiful pure language, becomes 1000 beautiful clean languages. Now you have to learn them all...

      • By athenot 2026-01-0718:512 reply

        > You can write boring code in Scala, but in my (limited) experience, Scala developers don't want to write boring code. They picked Scala not because it was the best tool for the job, but because they were bored and wanted to flex their skills. Disregarding the other 95% of programmers that would have to work with it.

        Intersting observation.

        So basically Scala is to the JVM what Perl is to scripting?

        • By vaylian 2026-01-0720:44

          You can write readable Scala code, just like you can write readable Perl code. But both languages allow you to to write very concise and cryptic code as well. Scala doesn't seem to optimize for the "one obvious solution" approach like Python does. Scala seems to be more TIMTOWDY like Perl.

          Scala was designed from the beginning to support classical Java-style OOP code and also Haskell-like functional code. These are 2 very different styles in one language. And then Scala supports defining DSLs which give you even more flexibility.

      • By tasuki 2026-01-0721:52

        You can write boring code in Scala, but in my (limited) experience, Scala developers don't want to write boring code. Guilty as charged!

        > They picked Scala not because it was the best tool for the job, but because they were bored and wanted to flex their skills.

        Guilty as charged!

        > Disregarding the other 95% of programmers that would have to work with it.

        No. Your coworkers end up being the other 5% of programmers that have the same taste as you. Interviewers ask about monads and lenses. It's fine, as long as everyone is on the same page. Which... they kind of have to be.

      • By dionian 2026-01-0716:14

        i use scala because i can write more expressive and simpler/safer code than java language.

    • By dkarl 2026-01-0714:111 reply

      > I lost my enthusiasm when the community decided they wanted to use it as Haskell on the JVM

      It's not the whole community, not by a long shot. Don't judge Scala by the Scala subreddit.

      Most new things you'll see written about Scala are about solving difficult problems with types, because those problems are inexhaustible and some people enjoy them, for one reason or another. Honestly I think this shows how easy and ergonomic everything else is with Scala, that the difficulties people write about are all about deep type magic and how to handle errors in monadic code. You can always avoid that stuff when it isn't worth it to you.

      The type poindexters will tell you that you're giving up all the benefit of Scala the moment you accept any impurity or step back from the challenge of solving everything with types, and you might as well write Java instead, but they're just being jerks and gatekeepers. Scala is a wonderful language, and Scala-as-a-better-Java is a huge step up from Java for writing simple and readable code. It lets you enjoy the lowest hanging fruit of functional programming, the cases where simple functional code outshines OO-heavy imperative code, in a way that Java doesn't and probably never will.

    • By vjerancrnjak 2026-01-0713:591 reply

      Haskell is usually used as a DSL. I believe Haxl is used at Meta and TidalCycles is a good example of another DSL built in Haskell.

      Although I agree the usual lens, optics, machines, pipes or other higher kinded libs are completely unnecessary, solving problems you do not want to have and have dire performance implications, but are at least correct and allow you to throw code at problems quickly, even though that code sucks in all ways except correctness.

      • By antonvs 2026-01-0715:21

        I don’t agree that pipes should be in your list, at least for some use cases. Streaming data through pipes gives capabilities that systems written in more traditional ways often simply don’t match. Look at the use of the Stream API in Java for an example of the utility of this outside of the Haskell context.

        Pipes also don’t necessarily have “dire performance implications”, but it depends a lot on the implementation. Haskell libraries don’t always emphasize real world performance as a top criterion. E.g. see https://github.com/composewell/streaming-benchmarks for some truly wild variations in performance across libraries (disclaimer: I haven’t investigated or verified those numbers.)

    • By cbeach 2026-01-0718:462 reply

      Scala is a fantastic language and in fact I'd say it's the language that proves the article wrong.

      Java was the language where "write libraries instead" happened, and it became an absolute burden. So many ugly libraries, frameworks and patterns built to overcome the limitations of a simple language.

      Scala unified the tried-and-tested design patterns and library features used in the Java ecosystem into the core of its language, and we're better off for it.

      In Java we needed Spring (urghh) for dependency injection. In Scala we have the "given" keyword.

      In Java we needed Guava to do anything interesting with functional programming. FP features were slowly added to the Java core, but the power and expressivity of Java FP is woeful compared what's available at the core of Scala and its collections libraries.

      In Java we needed Lombok and builder patterns. In Scala we have case classes, named and default parameters and immutability by default.

      In the Java ecosystem, optionality comes through a mixture of nulls (yuck) and the crude and inconsistently-used "Optional". In Scala, Option is in the core, and composes naturally.

      In Java, checked exceptions infect method signatures. In Scala we have Try, Either and Validated. Errors are values. It's so much more composable.

      There's so much more - but hopefully I've made the point that there's a legitimate benefit in taking the best from a mature ecosystem and simple language like Java and creating a new, more elegant and complete language like Scala.

      • By kelnos 2026-01-085:26

        I think you misunderstood the article (or only read the first couple paragraphs). The author sets the stage with the statement in the article title (a quote heard from other people), but shows that those fancy language features in some languages are exactly why rich, easy-to-use libraries can be built. And that some of these rich, easy-to-use libraries simply cannot be built in some languages that lack those features.

        So you don't actually disagree with the article.

      • By jibal 2026-01-0811:58

        > the language that proves the article wrong

        It helps to actually read it. The title is in quotes because the point of the article is to refute it.

    • By antfarm 2026-01-0716:23

      Have you tried Clojure(Script)? It could be just what you need, bottom-up programming in a Lisp-like language essentally means extending the langauge in order to solve the problem at hand.

      Or, as Paul Grahmam put it in his 1993 book On Lisp: "a bottom-up style in which a program is written as a series of layers, each one acting as a sort of programming language for the one above"

      https://paulgraham.com/progbot.html

      https://www.paulgraham.com/onlisptext.html

      Here is a talk that explains the concept in Clojure, titled Bottom Up vs Top Down Design in Clojure:

      https://www.contalks.com/talks/1692/bottom-up-vs-top-down-de...

    • By sambuccid 2026-01-0714:111 reply

      I recently started to learn Scala and I love it, also for it's functional aspect. Regarding your comment, it feels like scala is generic enough to be used also in other ways, and definitively for DSLs. What do you think it's missing?

      • By hibikir 2026-01-0715:05

        I think the GP is thinking about how libraries and ecosystems are often more important than the language. Most emphasis in scales is in a collection of competing frameworks that, today, are very FP oriented. Some hide the category theory while others put it up front, but it's ultimately what you do. The libraries that wanted to do imperative OO lost most support.

        Also see, for instance, Java. There's Java, the language that keeps improving, and then the Spring ecosystem, which is what 95% of programmers end up having to use professionally, with its heavy "magic" component. Writing services avoiding Spring is going against the grain. It might as well be part of the language as far professional Java use is concerned.

        Communities matter more than the language features, and Java is all Spring, and now Scala is really a choice of Zio and Cats

    • By willtemperley 2026-01-0715:14

      Hopefully project Panama will see better interoperability with libraries using the C memory model however migration does not appear to be easy. Arrow Java still uses sun.misc.Unsafe for native memory access.

    • By kayo_20211030 2026-01-0715:02

      Reminds me of a joke.

      I have a problem.

      Right, I'll design a DSL.

      Hmm. Now I have two problems.

    • By morshu9001 2026-01-0715:133 reply

      Doing fancy things with types used to interest me, now it's the last thing I want to touch, after being burned too many times by libs trying to be clever.

      I used Scala a few times when it was semi popular, just seemed like Java but with lots of redundant features added. Not sure what the aim was.

      • By kelnos 2026-01-085:111 reply

        Certainly one can get too clever/fancy, but I appreciated that Scala let me express things in the type system that made more of my program confidently correct at compile time than I could do in Java. I hate writing tests, and with Scala, I could write fewer of them, but still be confident that things were working as intended.

        But ultimately using Scala at the place I worked at the time was a failure. A couple of my co-workers had introduced it, and I joined the bandwagon at some point, but it just didn't work out.

        Many Java developers inside the company didn't want to learn, and it was really hard to hire good Scala developers. The ones who did learn (myself included) wrote terrible Scala for a least the first 6 months, and that technical debt lingered for a long time. When other people outside the team (who didn't know Scala) needed to make changes to our code, they had a lot of trouble figuring things out, and even when they could, the code they wrote was -- quite understandably -- bad, creating extra work for us to review it and get it into shape.

        I also feel like Scala suffers from similar complexity/ways-to-do-things problems as C++. I often hear people say things like "C++ can be a safe, consistent language if you just use a subset of it!", and then of course everyone has a subtly (or not-so-subtly) different subset that they consider as The One True Subset. With Scala, you can write some very complex, type-heavy code that's incredibly hard to read if you are not well-versed in type/category/etc. theory (especially if you are using a library like cats or scalaz). Sure, you could perhaps try to come up with some rules around what things are acceptable and what aren't, but I think in this case it's a hard thing to specify, and different people will naturally disagree on what should be allowed.

        I really wanted Scala to succeed at our company, but I think that's hard to do. I feel like the ideal case is a small company with just a few tens of developers, all whom were hired specifically for their Scala expertise, with a product/business that is going to keep the number-of-developers requirement roughly static. But that's probably very rare.

        • By morshu9001 2026-01-087:22

          C++ was how I'd describe it, too many different ways to do simple things. I guess Java++

      • By dionian 2026-01-0716:143 reply

        then why is java adding back half baked versions of scala features every major release

        • By brabel 2026-01-0718:401 reply

          Saying that the new Java features are half baked, to me, shows you're just feeling hurt because people prefer Java over your favourite language.

          Java may not be the pinnacle of programming languages, but since Java 8, pretty much every feature it's added has been absolutely excellently done.

          • By dionian 2026-01-0722:031 reply

            i mean, it follows the java philosophy (preseving backward compat). theyve done great work improving java. but i see no reason to use it over scala where i get better features, its more like a java 2.0

            • By surgical_fire 2026-01-0817:221 reply

              Then don't. You can use Scala to your heart's content. No one is stopping you.

              I had to work on a Scala codebase at some point, and I thought it horrible. I judge a language on how easy it allows you to create an unreadable mess. Scala makes it incredibly easy. And the people that enjoy Scala seem to like "unreadable messiness" as a feature.

              I found it fun to learn the basics, and it was interesting to think of problems from a FP approach, but it is never something I would use in the real world.

              I vastly prefer Java. The features it imported from Scala were fine, made the language better. It doesn't need to import everything.

              • By morshu9001 2026-01-0819:57

                Usually someone is stopping you, unless this is a hobby project. At least Scala can use Java libs so you aren't stopped by stuff not being available for it. But yeah I would never use it.

        • By morshu9001 2026-01-0716:521 reply

          Cause it actually needed lambdas and things that go with it. Didn't need all the Scala-specific data structs like Array.

          And the most important thing Java was always missing until recently, virtual threads, were lacking in Scala too.

          • By kelnos 2026-01-085:231 reply

            Virtual threads is a JVM & stdlib feature, not a language feature.

            (And I'd disagree that virtual threads were all that important compared to language features.)

            • By morshu9001 2026-01-087:27

              In pretty common applications, virtual threads will make the difference between chaining futures (this.then(that).then(...)) vs not, all throughout your code. Or some frameworks had far uglier ways to deal with cooperative multitasking.

        • By EricRiese 2026-01-0717:44

          Lambdas weren't simple to shoehorn into Java. But most of the recent changes have been implemented as well or better, or as well as you could imagine while maintaining backwards compatibility and Java-ness.

          Records/sealed interfaces (ADTs) are quite clean.

          Text Blocks are better in Java IMO. The margin junk in Scala is silly.

      • By tasuki 2026-01-0721:58

        > I used Scala a few times when it was semi popular, just seemed like Java but with lots of redundant features added. Not sure what the aim was.

        Blub is a great language!

  • By dev_l1x_be 2026-01-0713:0612 reply

    I would love to have a scripting language has typed features and you can replace bash with.

    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()

    • By jakkos 2026-01-0713:367 reply

      Have you seen nushell? It lets me one-liner so many things that would have previously taken breaking out a "real" language to do

      Contrived example:

        ls | where type == 'file' | sort-by size | take 4  | each {|f| {n: $f.name, s: ($f.size | format filesize MB) }} | to json
      
      outputs

        {
          "n": "clippy.toml",
          "s": "0.000001 MB"
        },
        {
          "n": "README.md",
          "s": "0.000009 MB"
        },
        {
          "n": "rustfmt.toml",
          "s": "0.000052 MB"
        },
        {
          "n": "typos.toml",
          "s": "0.00009 MB"
        }

      • By vidarh 2026-01-0718:011 reply

        With this:

            E = Struct.new(:name, :size, :type)
            def ls = Dir.children('.').map{ s=File::Stat.new(_1); E.new(_1, s.size, s.file? ? 'file' : 'dir') }
        
        This becomes valid Ruby:

            ls.find_all{_1.type == 'file'}.sort_by(&:size).take(4).map{ {n: _1.name, s: _1.size } }.each { puts JSON.pretty_generate(_1) }
        
        (drops your size formatting, so not strictly equivalent)

        Which isn't meant to "compete" - nushell looks nice -, but to show that the lower-threshold option for those of us who don't want to switch shells is to throw together a few helpers in a language... (you can get much closer to your example with another helper or two and a few more "evil" abuses of Ruby's darker corners, but I'm not sure it'd be worth it; I might a wrapper for the above in my bin/ though)

      • By 0x3444ac53 2026-01-0714:234 reply

        I've tried nushell and other shell replacements and it just feels like I'm learning a new programming language for no good reason

        • By ectospheno 2026-01-0715:462 reply

          To be fair the example above is easier to remember than:

            ls -l --sort=size | head -n 5 | tail -n 4 | awk '{print $5 " = " $9}' | numfmt --to iec | jq --raw-input --null-input 'inputs | gsub("\r$"; "") | split(" = "; "") | select(length == 2) | {"s": (.[0]), "n": .[1]}'

          • By fainpul 2026-01-0716:043 reply

            This example shows nicely how ugly text processing is: you have to use head and tail simply to trim out the first line of ls (the total).

            I think it doesn't even work correctly. ls lists files and directories and then picks the first 4 (it should only select files).

            And this also uses awk and jq, which are not just simple "one purpose" tools, but pretty much complete programming languages. jq is not even part of most standard installations, it has to be installed first.

            • By vidarh 2026-01-0718:101 reply

              I'd replace the first part with (which isn't any shorter, but in general if I want a list of files for a pipeline, find is usually more flexible than ls for anything but the most trivial):

                  find -maxdepth 1 -type f -printf '%s %f\n' | sort -n | head -n 5
              
              For the latter part, I'd tend to think that if you're going to use awk and jq, you might as well use Ruby.

                 ruby -rjson -nae ' puts(JSON.pretty_generate({n: $F[1], s: "%.5f MB" % ($F[0].to_i / 10e6) }))'
              
              ("-nae" effectively takes an expression on the command line (-e), wraps it in "while gets; ... end" (-a), and adds the equivalent to "$F = $_.split" before the first line of your expression (-n))

              It's still ugly, so no competition for nushell still.

              I'd be inclined to drop a little wrapper in my bin with a few lines of helpers (see my other comment) and do all Ruy if I wanted to get closer without having to change shells...

            • By kelnos 2026-01-085:311 reply

              > And this also uses awk and jq, which are not just simple "one purpose" tools, but pretty much complete programming languages

              In a way that exactly illustrates the GGP's point: why learn a new language (nushell's) when you can learn awk or jq, which are arguably more generally- and widely-applicable than nushell. Or if awk and jq are too esoteric, you could even pipe the output of `find` into the python or ruby interpreters (one of which you may already know, and are much more generally applicable than nushell, awk, or jq), with a short in-line script on the command line.

              • By fainpul 2026-01-089:39

                > awk or jq, which are arguably more generally- and widely-applicable than nushell

                That is backwards. I know I said "complete programming languages", but to be fair, awk only shines when it comes to "records processing", jq only shines for JSON processing. nushell is more like a general scripting language — much more flexible.

            • By ectospheno 2026-01-0716:291 reply

              Yes, the point was to show that nushell is pretty awesome. I totally punted on the file only part.

        • By bbkane 2026-01-0715:151 reply

          Yeah... https://www.sophiajt.com/case-for-nushell/ makes a really good case for Nushell as an alternative to Bash.

          Unfortunately, I don't think Nushell brings much benefit for folks who already know Bash enough to change directories and launch executables and who already know Python enough to use more complicated data structures/control flow/IDE features

          I'm still rooting for Nushell as I think its a really cool idea.

          • By misir 2026-01-0717:02

            For me the blocker was having to switch to bash/powershell when moving to a different machine (ie: servers, work machine, etc..). I would end up needing to redo same things to be compatible with the existing tools; eventually I just gave up and got used to readily available shells instead.

        • By fainpul 2026-01-0715:021 reply

          Ok if it's not for you. But there is of course a very good reason — work with objects in the pipeline instead of "dumb text". Also PowerShell and nushell are quite nice to learn, whereas Bash is absolutely horrible.

          • By kelnos 2026-01-085:371 reply

            I wonder if this is a case of "worse is better", or just the long-term entrenchment of text. Because nushell hasn't been adopted all that much compared to bash or even zsh (or a "real" scripting language like python or ruby). I don't know much about PowerShell adoption (haven't used Windows in over 20 years), but I'd assume since it's a first-party system that's default installed(?), it's done better adoption-wise.

            I agree that bash sucks, but I really have no motivation to learn something like nushell. I can get by with bash for simpler things, and when I get frustrated with bash, I switch to python, which is default-available everywhere I personally need it to be.

            Back to text, though... I'm honestly not sure objects are strictly better than dumb text. Objects means higher cognitive overhead; text is... well, text. You can see it right there in front of you, count lines and characters, see its delimiters and structure, and come up with code to manipulate it. And, again, if I need objects, I have python.

            • By fainpul 2026-01-087:11

              I get the point of "either Bash or straight to a real programming language". That's what I do too, for automation. I like how PowerShell makes one-off tasks easier which would otherwise be the typical pipe of cat, grep, sed, awk etc.

              About objects vs. text: I'm convinced that objects are vastly superior. There was a comment about this here with good arguments: https://news.ycombinator.com/item?id=45907248

        • By IshKebab 2026-01-0715:48

          Well, the reason is you can stop using Bash. If you never write Bash scripts already then you probably don't need it (and also congratulations on doing things right), but most people at least have lazy colleagues that write shell scripts. One day I'd like them to be not awful.

      • By fainpul 2026-01-0714:222 reply

        In PowerShell:

          gci -file | sort-object size | select name, size -first 4 | % { $_.size /= 1MB; $_ } | ConvertTo-Json

        • By xigoi 2026-01-089:261 reply

          ConvertTo-Json? What kind of naming convention is that, especially with all the other commands being lowercase?

          • By fainpul 2026-01-089:44

            The naming convention is `verb-noun`. It's convenient for discoverability and consistency. The short commands are aliases.

            The last command is properly cased, because I pressed tab (it auto-completes and fixes the case). The other commands I typed without tab completion. You can write however you want, PS is not case sensitive.

        • By NSPG911 2026-01-086:291 reply

          i dont think you need to select name and size, you can just remove it and use `select -first 4`, but cool, I never knew about `/=` syntax

          • By fainpul 2026-01-087:00

            I was trying to replicate the nushell example, which only has name and size in the output.

      • By BoppreH 2026-01-0716:42

        For me the best benefit of nushell is not the easier syntax, but the static type checks. It catches most typos before running the script, which is a godsend when the script is slow and/or has destructive operations.

      • By ifh-hn 2026-01-0717:54

        Was just about to suggest nushell. I love programming in nushell, the out of the box features are excellent.

      • By dev_l1x_be 2026-01-087:38

        this is pretty cool!

    • By frou_dh 2026-01-0714:201 reply

      OCaml is a scripting language in this sense. No need to compile an executable ahead of time, just have a `#!/usr/bin/env ocaml` shebang (or more realistically: `#!/usr/bin/env -S ocaml -I +unix unix.cma`) at the top of a source file.

      Though, I don't think it has the capability for single-file scripts to declare 3rd-party dependencies to be automatically installed.

      • By IshKebab 2026-01-0715:50

        It also has poor support for Windows.

        The best option I've found for this use case (ad-hoc scripting with third party dependencies) is Deno.

        I'm hoping Rust will get there in the end too.

    • By leonidasv 2026-01-0713:50

      There's a trick shared here days ago to add a kind of shebang to Go that may interest you: https://lorentz.app/blog-item.html?id=go-shebang

      Discussion: https://news.ycombinator.com/item?id=46431028

    • By PaulHoule 2026-01-0713:164 reply

      Two interesting options for everyday scripting are Python and Powershell.

      • By b40d-48b2-979e 2026-01-0713:20

        A nice part of PowerShell: you can `Add-Type` and embed C#/F# when you want.

      • By bashkiddie 2026-01-0716:002 reply

        I am unhappy with python. It degrades fast. It deprecates libraries every minor release and that tends to break the applications I use. Recent examples are distutils and opsaudio.

        • By kelnos 2026-01-085:41

          For everyday scripting -- the types of things where I'd be writing in bash but get frustrated with it and switch to python -- I nearly always only need what's in the stdlib.

          Sure, for "applications", the ecosystem can be frustrating at times, but I don't think that's what we're talking about here.

        • By ActorNightly 2026-01-0717:321 reply

          Thats why venv exists. Much better solution than lock files.

          • By hashhar 2026-01-0811:191 reply

            Doesn't help much because even the standard library bitrots after enough Python releases. I have things I write today but can't run on a NAS that has older Python. No issues like that with Powershell for example.

            • By ActorNightly 2026-01-0817:42

              I dunno what issues you are running into, but generally, code from old Python should work fine under new releases if you are developing, you just have to set up your venv right up front and install the specific version of libraries that don't have modern Python code.

              I still work on projects that were written under 3.6.

              If you care enough, you can also use something like asdf to install an older Python alongside the system one.

      • By logicallee 2026-01-0713:442 reply

        you won't believe how powerful Python is with libraries. ChatGPT and Claude made a brand new browser, that isn't based on Chromium or Firefox, and yet still follows many aspects of layout correctly. I read the article we're discussing ("stop designing languages") on this browser and I'm currently using it to post this reply.

        • By F3nd0 2026-01-0713:541 reply

          Knowing that LLM’s have been extensively trained on public code, I wonder how much of it is based on Chromium or Firefox.

          • By logicallee 2026-01-0715:08

            That's a good question! You can read through the entire source code for the latest version:

            https://taonexus.com/publicfiles/jan2026/171toy-browser.py.t...

            it doesn't look like it would be easily derived from Chromium or Firefox, because this code is Python and those don't use Python this way.

            By the way is there any feature you'd like to see added to the toy browser? The goal is that one day it's a replacement for Chrome, Firefox, etc. It's being built by ChatGPT and Claude at the moment. Let me know if there are any feature ideas you have that would be cool to add.

        • By PaulHoule 2026-01-0715:081 reply

          A python-based browser? What are you using for the GUI toolkit?

          • By logicallee 2026-01-0716:01

            >A python-based browser? What are you using for the GUI toolkit?

            Great questions. 1. Yes, for the moment. Like the title of this article suggests - we're using a library! :)

            It's great to iterate in Python, which has a large ecosystem of libraries. Believe it or not, there is a chance that in the future it would be able to translate the language into a different one (for example, C++) while using C++ bindings for the same gui libraries. This would speed up its actions by 40x. However, not all of the libraries used have C++ bindings so it could be harder than it looks.

            2. Here's the current version of the source code:

            https://taonexus.com/publicfiles/jan2026/171toy-browser.py.t...

            you can have a quick read through. Originally it was using tkinter for the GUI toolkit. I believe it is still using tkinter, but the AI might be leaning on some other library. As you read it, is it using anything but tkinter for the GUI toolkit?

            These libraries are doing a lot of heavy lifting, but I think it is still ending up drawing in tkinter (not handing off rendering to any other library.)

      • By IshKebab 2026-01-0715:511 reply

        Python is actually kind of awkward for this use case since you can't import from other files easily unless you are in a proper Python package, which isn't usually the case for everyday scripting.

        • By ActorNightly 2026-01-0717:341 reply

          Lol what.

          Python lets you dynamically import from anywhere. The syntax is a bit funky, but thats what llms are for.

          • By IshKebab 2026-01-0719:432 reply

            No it doesn't. You can't do something like `import ../../foo/bar`. You can mess around with PYTHONPATH and importlib to work around that but that's a horrible hack that also breaks all tooling. Not a good idea.

            With Deno you can just import by relative file path and it just works like you'd expect and the tools support it. I wish more languages worked like that.

            • By Jtsummers 2026-01-0719:481 reply

              > You can't do something like `import ../../foo/bar`.

              https://docs.python.org/3/reference/import.html#relativeimpo...

              You'd use:

                import ...foo.bar

              • By IshKebab 2026-01-087:44

                Common misconception. That doesn't import by relative file path; it imports by relative package path. It's actually quite different. Scripts you run directly aren't in a package so you can't use it at all. You can go above the package root. Namespace packages mean it can jump to other directories.

                Everyone wants that to just mean "import relative to this file" but it doesn't.

            • By ActorNightly 2026-01-0817:381 reply

              >You can mess around with PYTHONPATH and importlib to work around that but that's a horrible hack that also breaks all tooling

              ....no.

              import keyword uses importlib under the hood. It just does a lot of things for you like setting up namespace. But importlib has all the functionality to add the code in any python file cleanly.

              My custom agent that I use basically has the functionality to wrap every piece of code it writes as a tool and stores it into python files. During tool calls, it pretty much dynamically imports that code as part of a module within the project. Works perfectly fine.

              • By IshKebab 2026-01-097:35

                > Works perfectly fine.

                Unless you want to use type checkers, linters, IDEs, etc.

    • By Pet_Ant 2026-01-0715:091 reply

      Have you considered PowerShell? It's open-source, and typed, and definitely usable from the command line with lots of resources for.

      https://github.com/PowerShell/PowerShell

    • By ashton314 2026-01-0714:05

      If you just wait a few months, then that program will be written in a typed language. The type checker for Elixir is coming along nicely and every release brings more checks.

    • By librasteve 2026-01-0713:231 reply

      Suggest you take a look at https://raku.org for a strongly (but gradual) typed scripting language.

      • By dnautics 2026-01-0715:134 reply

        that's just perl with a new coat of paint

        • By fn-mote 2026-01-0716:122 reply

          Perl 5 does not have types, as far as I know.

          I’m taking the GP seriously instead of dismissing it. Raku looks like more fun than nushell tbh.

        • By DonHopkins 2026-01-0716:49

          Lead paint with asbestos sprinkles and radium racing stripes! ;)

        • By radiator 2026-01-0718:521 reply

          it is so much slower to start than perl, that you don't want to run it for quick one-off tasks

          • By librasteve 2026-01-1518:08

              ~ > time perl -e ''
              perl -e ''  0.01s user 0.01s system 10% cpu 0.179 total
              ~ > time raku -e ''
              raku -e ''  0.09s user 0.04s system 53% cpu 0.232 total
              ~ >

        • By librasteve 2026-01-0716:161 reply

          well waiting for Raku (formerly perl6) to be built was like watching paint dry

          • By DonHopkins 2026-01-0716:50

            They should have named it Godot. ;) But now that name is taken.

    • By jeroenhd 2026-01-0815:42

    • By unpigged 2026-01-0714:20

      Babashka (https://babashka.org/) is an interesting tool for scripting. It's Clojure, so dynamic typing, but it's data orientation makes it a great fit for something like your example.

    • By qrobit 2026-01-0713:22

      I wanted to say Haskell with shh[^1] and stack's or nix's shebangs[^2][^3], but interpreted haskell is not particularly fast.

      Also I think a Python script is reasonable if you use a type-checker with full type annotations, although they are not a silver bullet. For most scripts I use fish, which is my preferred interactive shell too.

      [1]: https://hackage.haskell.org/package/shh

      [2]: https://docs.haskellstack.org/en/v3.9.1/topics/scripts/

      [3]: https://wiki.nixos.org/wiki/Nix-shell_shebang. On a side note, if you were to use nix's shebang for haskell scripts with dependencies, you should be using https://github.com/tomberek/- instead of impure inputs, because it allows for cached evaluation. I personally cloned the repo to my personal gitlab account, since it's small and should never change

    • By melagonster 2026-01-089:06

      It probably is perl or Python.

    • By DonHopkins 2026-01-0714:531 reply

      @dev_l1x_be: The answer isn't a new typed scripting language. It's recognizing what the interpreter already is.

      LLMs are eval(). Skills are programs. YAML is the motherboard.

      @unkulunkulu nails it -- "library as the final language", languages all the way down. Exactly. Skills ARE languages. They teach the interpreter what to understand. When the interpreter understands intent, the distinction dissolves.

      @conartist6: "DSL is fuzzy... languages and libraries don't have to be opposing" -- yes. Traditional DSL: parse -> AST -> evaluate. LLM "DSL": read intent -> understand -> act. All one step. You can code-switch mid-sentence and it doesn't care.

      The problem with opinionated frameworks like ROR and their BDFLs like DHH is that one opinion is the WRONG number!

      The key insight nobody's mentioned: SPEED OF LIGHT vs CARRIER PIGEON.

      Carrier pigeon: call LLM, get response, parse it, call LLM again, repeat. Slow. Noisy. Every round-trip destroys precision through tokenization.

      Speed of light: ONE call. I ran 33 turns of Stoner Fluxx -- 10 characters, many opinions, game state, hands, rules, dialogue, jokes -- in a single LLM invocation. The LLM simulates internally at the speed of thought. No serialization overhead. No context-destroying round trips.

      @jakkos, @PaulHoule: nushell and Python are fine. But you're still writing syntax for a parser. What if you wrote intent for an understander?

      Bash is a tragedy -- quoting footguns, jq gymnastics, write-only syntax. Our pattern: write intent in YAML, let the LLM "uplift" to clean Python when you need real code.

      Postel's Law as type system: liberal in what you accept. Semantic understanding catches nonsense because it knows what you MEANT, not just what you TYPED.

      Proof and philosophy: https://github.com/SimHacker/moollm/blob/main/designs/stanza...

HackerNews