92 comments

[ 3.6 ms ] story [ 165 ms ] thread
As one of the Ten Commandments of C says, “your time is better spent writing programs then creating beautiful new impediments to understanding.”
At the same time things like proper macros are a great way to try new language features. Iterating on something like an object system or miniKanren becomes a lot more simple.
Sometimes the shear amount of repetitive code you need to have to accomplish some task is in itself an impediment to understanding, or it will encourage unfortunate shortcuts later on.
I didn't look up the exact wording, but it's a paraphrase of the second part of Commandment 8 in the version you linked. I think I'd conflated it somewhat with another one (not in that version, there are a few around though) about not using the preprocessor to turn C into a different language.
Thou shalt make thy program's purpose and structure clear to thy fellow man by using the One True Brace Style, even if thou likest it not, for thy creativity is better used in solving problems than in creating beautiful new impediments to understanding.

I'd rather strive for beauty and try to avoid impediments. Even though "Brace Style" is loaded with impediments, I'll stick to Brace Style when writing C code. Any C macros I might write are weird enough already.

(comment deleted)
Great idea. When we need to store relational data, let’s all write C instead of SQL as well.
Insufficiently-abstract code is an impediment to understanding.
> Sergey seems to believe that the main barrier preventing the invention of new computer languages is that it's too difficult to write language-specific tools.

Was the eventual solution MPS? (https://www.jetbrains.com/mps/)

MPS has a thing where mistakes written in the DSL are caught in the implementation layer and then translated back into terms related to the DSL before they're reported to the programmer. Looked good in a talk one of their developers gives. I'd have written this off as "can't be done" without that existence proof.
Funny seeing that relatively old article, when you consider that JetBrains made good on that promise: Kotlin made writing DSLs actually pleasant.

    class ModuleTest: StringSpec({
         "it should behave well" {
             2 + 4 shouldBe 6
             "test" shouldBeInstanceOf<String>()
         } 
    })
This includes many things that Kotlin makes use of, like String.invoke(block: () -> Unit) which is both an extension on String instances and makes uses of Kotlin's "ability" to move lambdas out of parentheses if they are the last argument (so something like log(lazyString: () -> String), can be used as log({ "message" }), or log { "message" }, @DslMarker (to allow a String.invoke(() -> Unit) block in the form of "it should behave well", only inside the context of a StringSpec.), infix funs (+ is infix operator fun plus(), with some slightly specific language handling because it's extremely common, infix fun shouldBe). This is using Kotest (https://kotest.io/docs/framework/writing-tests.html), but other tools like Ktor, Skrape.it (https://github.com/skrapeit/skrape.it), and more: https://kotlinlang.org/docs/type-safe-builders.html
Yes, in my career I've seen a OO extension of C written in XML that required a custom eclipse plugin to write. A language where you defined a function like: function foo() while (...) ... end while; if (...) ... end if; end foo, because those guys loved the C++ style of putting comments at the end of control structures. Finally there was the language you had to write in excel that was exported to CSV that in turn was used to generate XML that was parsed before compile time to generate java code with System.out.println and was finally loaded at runtime through some dynamic loading. I never had any respect for these people as engineers, I was very KrugerDunnings early on in my career but I don't think I was to entirely to blame for always knowing better.
One time, someone did something in a dumb way that other people sometimes do in a good way. That said, I decided that the something someone can do is dumb, because I saw it done in a dumb way. Thank you for coming to my Ted Ted Talk.
I think of API design like little languages. Got data structures, functions that operate on them, and a job to do with those functions. Anticipating the useful ways an API might need to be used is difficult so keeping it small to start is generally advisable. Plus if you’re wrong in some ways you have a lot less to refactor.
I share the sentiment; in the end, all abstractions are just that, little languages, perhaps even dialects within a broader language that defines what constructs you may use while remaining "correct".

I am working on a project at work that may involve some kind of language, and the language essentially came up because we need a way to define an arbitrarily large abstraction, effectively behaving as an intermediate layer between multiple different front-ends and a backend.

I agree. In a way, all applications have a sort of implicit Domain Specific language in them. You have a bunch of things (nouns or types) and you can tell the application to work with those things in certain ways (language).

When I learned Haskell at University there was a lot of emphasis on EDSL (embedded domain specific languages), where haskell allows you to define grammars inside haskell. There are many examples of EDSL:s in other langauges but Haskell takes things a bit further. I think there could be a good point in allowing such approaches in more languages. I heard that Rust has ADT:s, which is a good building block for EDSL:s.

It might make things a lot clearer, or it might make things over engineered. I'm a bit on the fence about it. It probably makes things more manageable in the long run.

Late edit: (*language or business logic)

The point of Building an EDSL could be to isolate the business logic from everything else. This should be a big benefit since for most cases it should be possible to make everything else from off the shelf commodities.

If done well most code is just extending the language you're writing it in to make it easier to say the things you need.

This is perhaps clearest in lisp because there is no syntax to get in your way (kind of the opposite approach to operator overloading).

Perhaps the most interesting way you can approach this is by designing the language first and then figure out how to implement it.

> Perhaps the most interesting way you can approach this is by designing the language first and then figure out how to implement it.

Yeah, I'd say if you're not creating a "domain" in which solving the problem at hand is easier, you need to get back to the drawing board. That's true for language and API design.

This really isn't the same. If you're just building up objects/data structures in your host language, and calling functions/methods on them, then you're not creating a language. It doesn't matter how slick/fluent or whatever else your API is, you're just working in the host language.

To have a reasonable claim that you're writing a language, you'd need to write something with a different syntax and/or model of execution, and somehow embed it in your language. Arguably regexes and SQL count, though the perennial problem there is that to the host language, they're just opaque strings.

None of this is to say your APIs are bad. Embedding one language in another is hard--that's why they're so often just opaque strings. Beyond that, as this article points out, embedding a new language gives anyone working with your code a significant obstacle. For most things, little languages aren't the right tool--standard imperative/functional programming goes a really long way.

(comment deleted)
> This really isn't the same. If you're just building up objects/data structures in your host language, and calling functions/methods on them, then you're not creating a language. It doesn't matter how slick/fluent or whatever else your API is, you're just working in the host language.

It can be. They're called EDSLs, "embedded domain specific languages". The point is to embed the language semantics in the host language via judicious choice of data types, and then methods implement semantics-preserving transformations on them. The more expressive the type system, the more expressive the languages you can safely embed in the host language, and you then have all the debugging capabilities and libraries of the host language at your disposal.

This pattern is very common in Haskell, Oleg is well known for doing this with OCaml [1], but you can also do this in typical OO languages like C#. Arguably C#'s IEnumerable<T> interface is such an EDSL for set programming, and here's a simply typed lambda calculus [2], here's an SKI combinator calculus [3], here's a stack-based language [4], and here's a logic programming EDSL based on µKanren [5].

[1] https://okmij.org/ftp/ML/#DSLs

[2] https://higherlogics.blogspot.com/2008/09/mostly-tagless-int...

[3] https://higherlogics.blogspot.com/2013/09/combinator-calculu...

[4] https://higherlogics.blogspot.com/2009/01/embedded-stack-lan...

[5] https://higherlogics.blogspot.com/2015/02/kanrennet-featherw...

I feel like minikanren matches pretty closely to what I wrote about regex and sql? The execution model really isn’t visible from the surface syntax.

And while you probably don’t embed it as a string, you do basically have a shim layer between the host language and the natural ways of expressing a logic program.

My point is something like “if you’re doing something like SQL or regex or minikanren, you have a claim to implementing your own language, but the normal case is just another API.”

There is a reason we’re talking about Oleg! He’s really unusual (in a good way).

I may be wrong but I think that's not the view of the modern PL community. If your API talks about values, combinators, and has (implicit) laws about them then I would certainly consider that a language.
Maybe the view that APIs are little languages can be seen as the view of the postmodern PL community.

Since object orientation brought the possibility of adding little languages to the masses and a few decades later value objects and lambdas and generics where added to all OO languages, a postmodern view may be quite an applicable and useful perspective to deal with this question.

I would disagree. One of my biggest revelations and improvements to my programming from reading SICP was the concept that as soon as you start to declare functions you are starting to create an abstraction over hte host language and as a result a new language for your problem will emerge.

This begs the question: what is the benefit of treating nearly all program writing as "language design".

Using that frame of reference I can use it to spot where my abstraction/program design breaks down when I start using too much "raw programming language" to glue between different parts of my program together. That suggests I have a gap in how my domain objects relate to each other.

In my view, we are often well served by a perspective in the direction of Sergey's. I see a gradual scale from applications to full languages. When I write applications, I try to define types and operations on those types. When I feel I succeed well at this, it almost feels like I have written a new 'sub language'. I prefer languages that aid this hallucination, that is where the hosting language's syntax doesn't get in the way. I don't buy the argument that we should not try to create new 'unknown' languages - when we are defining a complex application, we are already in the business of making up a language and a vocabulary. What I _do_ buy, is that we should avoid reinventing variants of syntax when we can help it. Mostly, syntax works as 'glue' but doesn't really define fresh concepts.

I have no addiction to playing around with Lex and Yacc needlessly, but with types, methods and classes from modern languages, I do feel we have tools akin to defining 'languages'. Our defined types even help define the legal expressions - if Baz can only be constructed by pasing a Foo and a Bar, I have constrained that you can't accidentally mix up the ordering that your Foo must be defined/acquired before you start doing verbs on a Baz item.

I can appreciate having access to e.g. operator-overload in C++, but I can build most of what I want/need, even without those.

Every significantly complex software is a domain specific language with it's own ontology. It just that some programming languages make it feel like you only have nouns, and must use some alien syntax.
Honestly, who has the time anymore? Domain specific validators like XSDs, JSONSchema, simple enums, and various remote APIs for proprietary formats I need take care of everything well enough. There's just too much high value business work to do. The C-suite doesn't care that I made some DSL, and they're gonna be pissed if future work takes twice as long when it needs updates and testing on top of the actual feature work they want done that relied on an earlier conception of its functional requirements.
> There's just too much high value business work to do.

e.g.?

I always had the dream of building a language, then I did it and found what an extraordinary undertaking it is, and abandoned it. The issue is not getting something working early on or lack of supporting tooling. The issue (as I see it) is that most well known languages are extraordinarily sophisticated not just in their syntax but also things like debugging, profiling & analysis. Once you start conceptualising an entire system to get actual work done, you realise it really isn’t feasible as a lone endeavour. While not impossible, it’s very hard to be an expert in all these fields. You are therefore presented a choice: somehow fund your language (maybe you’re rich), or make it open source. Just open sourcing something isn’t a silver bullet either, successful projects often have a charismatic leader. I generally prefer to program alone when working on vanity projects, so I figure I’d just wait until someone invents something that most aligns to my tastes (SerenityOS/Jakt is close).
There is a third option: make your language shine where it matters (to you), and accept subpar experience in areas that matter less. Specific things you mentioned — debugging, profiling & analysis — could be treated as a solved problem if you transpile your language into some other language that already has these nice-to-haves. JS is a wonderful target, as long as you generate something remotely readable you already have a way to debug it, no need to reinvent it. Instead, it's much more fun and beneficial to focus on the reason you want to create the language, on the features that make it stand out.
Firstly, JS is a horrendous target. Second, breakpointing in another language is about as great (possibly worse) as debugging via printf.
Depends on your needs. In terms of functionality, JS has everything you might want, even the ability to execute itself. Viewed as a platform, not just a language, it offers WebAssembly, soon WebGPU. I don't see anything else that comes even close as a target platform!
The usual choice is C. I'm currently liking luajit as the tracing cuts through some of the DSL. The JavaScript compilers probably manage the same thing.
Unless you write a basic interpreter or code in plain binary, you're breakpointing in another language. It's really not a big deal as long as you preserve the mapping to the original code.

When you breakpoint in C, you breakpoint in assembly and find your C location from the debug information for example.

> Second, breakpointing in another language is about as great (possibly worse) as debugging via printf.

You don't have to. Just generate sourcemaps and you'll be able to set breakpoints in your own language even when targeting JS.

If anything that makes JS an even better target since you can leverage tooling.

I think this is an important point. Comparing an initial implementation of a language with that of mature projects doesn't make sense. Every cool language started off in a rough initial state I'd wager, and many were initially developed by a single person, so why not give it a shot if it's compelling?
This is how we went with https://wasp-lang.dev/ (a DSL for building full-stack web apps). It is a very declarative language (config pretty much) and there is still plenty of work around tooling, but also enabled to cut down on a lot of boilerplate.

Another route to consider when implementing a DSL, is to make an embedded one (e.g. like Terraform or Pulumi have, even both at the same time). That doesn't resolve all the tooling problems since there is still a compile step, but might provide a more integrated experience, although at the cost of brevity.

Yup, I found out how hard it is just writing a simple language that doesn't even need computer tooling: https://dogma-lang.org/

And even with a language as simple as this, it still took 6 months. The biggest problem is keeping the patterns simple and coherent, while avoiding unnecessary features. It pains me to think of the weeks spent developing parts that were ultimately ruthlessly slashed away. Hours spent agonizing over a usage pattern that was mostly the same but different enough that (I thought at the time) it required special constructs... and then not as I thought about it in the shower days or weeks later. It's one hell of an eye opener.

And then there's the type system... UGH.

There are languages out there that are more or less designed for rapid prototyping of PLs. Lisps, and in particular, Schemes such as Gerbil and Racket, are particularly well-suited to building languages. Yes, you have to get used to the prefix notation and (((((((, but ultimately it lets you have a lot of flexibility in testing out language constructs and usage-patterns before you build the parser, lexer, etc. that are time consuming.
I think you meant, ))))))))
I think you just couldn't stand seeing all those unclosed braces ;-))))))))
I have the same fanciful desires. I've decided to focus on extending Python with C instead. I can keep the benefits of Python and increase its speed as needed. This concept scratches that same itch.
I believe that's why the article is saying "little" languages. Not all languages need a package repository and a language server
What kills it for me is the amount of middlebrow dismissals new PLs get, especially here.

Tons of work and some rando comes in complaining you didn't advance type theory to help avoid annotating a type in one location. Arguably worse are the people who advocate against the new PL because no one is using it, strengthening the Matthew Effect, collecting Internet Points for cosplaying as a "responsible engineer" that argues solely for the status quo.

> Tons of work and some rando comes in complaining you didn't advance type theory to help avoid annotating a type in one location.

If your language gets any traction, then you're going to get a number of randos saying things like that. Worse, some may not be randos. Some may be people with a connection to other languages.

> Arguably worse are the people who advocate against the new PL because no one is using it, strengthening the Matthew Effect, collecting Internet Points for cosplaying as a "responsible engineer" that argues solely for the status quo.

Well... one of the things a responsible engineer should in fact consider is maintenance, including the ability to find future workers who know that language. It's only one factor, not completely determinative, but it should be considered.

(comment deleted)
I don't like dismissals about adoption for anything new or under development as it's a given.

I would complain if a posted language doesn't describe why it was created. What's the thing it does that others don't or do poorly. If just playing with syntax or scratching an itch that's ok too--simply make that clear.

Pretty sure Javascript is an example of why most of us shouldn't invent a language:)
Another option is to use tooling that helps you write little languages with debugging, profiling, etc for free.

An interesting article I saw the other day: https://news.mit.edu/2023/d2x-easier-way-get-bugs-out-progra...

Isn't that article / researcher saying the same opinion the submission article is responding to? JetBrains about 9-10 years ago made those arguments and claimed to work on providing the tools to solve those challenges.

I'm kind of curious what actually happened in that time. I've actually seen a few of these research projects over the years, i.e. providing tools to build languages with automated IDE and debugging support. Ultimately, I think (like the submission article's author) that it's something else holding adoption back. It may simply be lack of a convincing use case, e.g. industry adoption by one large company could make the overall approach (DSLs) more convincing.

Now DSLs or DSL-like languages are of course in use in many orgs but they very often aren't more than configuration languages and often embedded in something else. Very rarely do they get complex enough to warrant debuggers. So I think we a) still lack good examples of DSLs being worth it, or b) a more convincing argument why today's methods would benefit from building a whole new language (incl. tooling).

What an great yet obvious analogy for adoption, between human language and programming languages.

Like the first telephone, the first adopter of a new language is the hardest sell (because there's no one to talk to).

No wonder some languages hitch a ride as a language for a platform that enables some great thing, like C-unix, JS-web.

Human languages don't evolve from scratch, it's just some extra words here and there, sometimes a grammatical change. This is like domain-specific-functions-and/or-objects, not domain-specific-entire-languages.

And yet... little languages already abound, markdown, escaping rules, and several based on algebra: arithmetic, boolean, kleene, relational (others?). Therefore, you can "make" a new language by slightly modifying one of these, so it's really a minor evolution in practice for users.

Another approach is the little languages that already exist in a workplace, the jargon and implications and defaults and patterns and rhythms. If it is already formalized, maybe it can form a DSL.

I once got sucked into making a little language out of Diplomacy (the board games) specific way of writing down moves. It was kind of nuts because it was both sort of a coding language (albeit an annoying one unless you're writing a Diplomacy variant) and sort of a natural language (so long as the topic of discussion is negotiating within the context of the game). But really, these two are the same thing, as any tool powerful enough to define game rules is also powerful enough to define agreements between players. Really, a rule is nothing more than an unbreakable agreement with an unseen god character called the GM.

I know, very different from the coding languages everyone here is on about. But the extent to which my mini language was conversational despite very few additional words was really profound. Its smaller than toki pona even! And less than half the vocabulary comes from me!

Reminds me a bit of the old (over 30 years old) computer game "Trust & Betrayal" in which the player interacts with the computer controlled opponents with a little icon-driven language. It was very impressive for the time and it's odd that (as far as I know) the concept wasn't picked up on by later games.

https://en.wikipedia.org/wiki/Trust_%26_Betrayal:_The_Legacy...

I think my little language long ago crossed the threshold of composibility far beyond what simple icons can express. The spark to it is that sending a message to someone is itself an act within the game, and so there should be an order type to represent it. I introduced only two new words to the games formal vocabulary: propose and inform. They both have the same syntax. <country name> propose <country name>: <some set of orders>. Since these orders can contain other orders, but also are a type of order, you may in fact nest them to propose plans which involve proposing other plans. All sorts of emergent complexity bursts through after taking just that minor change. You can now gossip, that is compose inform statements which describe a chain of he said she said events. Without introducing it intentionally, you now have a way to ask questions. "I propose you inform me." Despite excess restraint towards changing the language that comes in the box, my "little" language could was eerily general
I guess it depends on the definition of "little language". I do see a fair amount of using formats like yaml with some macro-like support for conditionals and expressions replacing what used to be done with a little language or a general purpose language. Github actions and Gitlab's CI/CD are good examples...replacing what used to often be some custom or general purpose language. Similar for things like helm charts, CloudFormation, etc.
> It's that other people won't understand you.

I think the idea is the other way around. It's not about inventing a new language, it's about taking a jargon that already exists, is used and understood by domain experts, and make it executable. Less regex/XML, more nouns and verbs from a very specific business context.

Granted, even with that perspective, it's still a stretch to say little languages are the future, but both the article linked here and the one it's replying to are from 2004, so, there's that.

I have yet to see a cucumber test that was actually touched by a non-technical domain expert. It is a fantasy and only introduces inscrutable abstraction layers that don’t add value.
It's not a fantasy. They may not write them (though some less technical manual QA people will add to scenarios with a data table), but deciding on them and reading them, and spitting their results out into documentation are all useful in their own rights.
I think this is due to Cucumber's syntax and culture, not because the idea itself is a fantasy. The syntax simply doesn't allow for complex representations of specifications and doesn't have anything resembling inheritance (e.g. add employee story->depends on admin logged in story).

I built this tool/DSL on the basis that a more flexible language combined with templated doc generation would bridge the gap better: https://github.com/hitchdev/examples/

I have, and that is how they wanted to communicate the needs of the application to the development team.

It was horrid. Getting non sequitur snippets of requirements without the big picture, in this weird almost English, but not, language that looked like it was desperately trying to copy the structure of test code, but without anything executable, losing the entire reason you might choose to accept the tradeoffs of documenting your requirements in code as promoted by actual BDD.

Not only did it not add value, it took away value.

Most of us are inventing little languages all the time. Every codebase is a little language. The question is not whether we'll be implementing little languages, but how integrated or separate those languages feel and to what extent they "leak" when you try to integrate different code-bases.

In some "host" languages like Smalltalk, or lisps or Ruby they can feel like they become part of the host language. In other they're - sometimes intentionally, sometimes as a byproduct of the way the languages are structured - feel very clearly separate and delineated.

Small languages are everywhere:

- configuration files (*.ini, .<tool>rc, Makefile, TOML, CMake, ...)

- scripting complex applications (ELisp, Lua)

...

- pattern match languages for tree-to-tree rewriting in document processing (DSSSL) and compilers (GCC INSNs)

- modeling the shape of syllables and words of human languages (lexc, twolc, xfst)

- A DSL for modelling/simulating habours/ports became PostScript (no joke)

LLVM and Graal are overly low level and they don't generate the rest of the tooling necessary like language servers, linters, and formatters.
> Learning to use the Swing API properly may be difficult, but would it really be easier if the Swing developers invented a new language to write it in?

That's a first-class example of sunk cost fallacy. Sure, everyone can understand that the field won't move from Java soon. But discarding legitimate criticism of the object-oriented paradigm because "people already learned it anyway" is a surefire way to make sure new languages aren't better than old ones.

Also I believe that the author had a myopic way of the field. Sure, new enterprise languages don't appear every day, but they do appear (hello, Rust), and when they do, lots of their innovation can be traced to smaller experiments, "failed" languages and ideas written on a napkin by people that won't stop thinking beyond Java. And old languages don't die, but they certainly go past their prime (hello Cobol), and I'm quite happy that they do.

As for the final paragraph, it got invalidated completely by the groundbreaking innovation of LSPs. As it stands now, most new small languages communities already write their own LSP, and IDE creators usually stop at the client. Granted, the article is 18 years old.

In my opinion, and with the benefit of hindsight, the author couldn't project as far in the future of our industry as the Jetbrains CEO did.

Well, if people can't read a language, they can learn it.

Most DSLs take to few hours to maybe a weekend to learn. Not understanding a language is not really an issue when it is so small than you can easily learn it on demand. Being able to follow the basic flow can require as little as a few minutes of explanations form a co-worker.

Familiarity plays a huge role when deciding between different DSLs. Are we going to use good old JSON or that new thing that is technically a little better? Yeah, let's use what we know already. Would we decide to not use any interchange format at all because no one has ever worked with JSON? Nope.

Similarly, I don't know many workplaces that outright ban using regular expression even though chances are not everyone is exactly fluent in reading them.

If you language is good, fits a new use case that other languages don't and has good tooling, people will use it. The good tooling part can not be underestimated here.

Problems can be solved by introducing an abstraction that provides tools for working in a certain domain, and then using those tools to solve problems in that domain. This can be really effective when the requirements are complex and shifting because it allows for flexibility and working more directly in the problem domain.

You can invent a language to do this.

But quite often existing languages are perfectly capable of expressing the abstraction. Meanwhile, there can be a huge overhead to a programming language… you tend to need syntax, documentation, parsers, a standard library, third party libraries, debuggers, programmers, etc.

Usually it just makes a ton more sense to express your domain concepts withing an existing language than make a domain-specific one.

Counterpoint: code is not natural language. It is meant to be read and understood by other humans. However it requires training and education to use and appreciate.

The reason this is important to note is that in similar languages, like mathematics, notation and language make a significant difference in the theorems we can write and in explaining our ideas to others. Computing might not have come along without having first inventing algebra and calculus.

And so it is often worthwhile to build new language constructs: abstractions that provide new semantics and notation to make writing terms convenient in the abstraction.

A lot of the criticisms of this approach offer their alternative: avoid abstraction, use only the primitive keywords available; all in the noble effort of keeping code, “simple.”

I think there is a balance to be struck. Code written without abstractions tends to be simple in “local” terms but it leads to highly verbose programs that are hard to follow. Improper use of abstractions create unnecessary indirection and mislead the reader from the problem. The antidote to these problems is to write, think, and to use sufficient means to convince your reader that the abstractions work.

> think

this,

it's the first step, think clearly without ambiguity, if you can't the compiler should be designed to force you to do this.

I'm surprised there wasn't more of a mention of Racket except for a brief line about why language oriented programming might've been the reason Lisps don't get widely adopted and I'm similarly surprised with the lack of Racketeers in the comments.

I haven't really explored the "language oriented" aspect of Racket yet (I'm just starting my foray into with the Little Schemer books), but the "tower of Babel" effect does seem real. I somewhat (very weakly!) suspect language oriented design works passably if the DSL that's designed is not Turing complete, but that's more of just a hunch...

It seems to me that TCL provides a very good compromise position between inventing a domain-specific language and using a standard language. It's intended for that use case.
Contrary take, all programs are little languages. They are, of course, written in a larger language that has more capabilities, but every program is reducing down to the parts that are getting used. And moreover, most of the bugs are when people don't keep themselves to this reduction.

Is why most "little languages" should probably not aim for complete capabilities. The smaller you can keep these little languages, the better.

But, this means you will get more things like regex as a little language. Format strings. Basic workflow validation programs. Not full programming interfaces.

Completely agree that every program (domain model) is in essence a little language.

But I don’t follow your comment about bugs corresponding to when programmers don’t stay within the reduction. Do you mean simply that every “bug” is (literally) a misunderstanding of the domain semantics , or are you making a stronger/constructive statement?

Apologies, I was not trying to say all bugs. But it is not surprising to find bugs in code when someone pulls in new libraries/functions/whatever to a piece of code. More so if it ships out any data to use those things.
> Completely agree that every program (domain model) is in essence a little language.

You almost called them by name: domain-specific language(s).

> Learning to use the Swing API properly may be difficult, but would it really be easier if the Swing developers invented a new language to write it in?

It absolutely would. I learned both Swing and web programming around the same time and web programming—with its domain-specific HTML and CSS—was far easier to learn, especially for anything beyond the most basic UIs. I never got beyond the point of making a Swing app that looked and behaved just like ≈every other Swing app; in substantially less effort, I could make web apps that looked and interacted in the way I wanted.

What made web programming so much nicer? I see a clear core dynamic: the web had a substantially better conceptual model. The layout system, the separation of content and styling (even if imperfect), the DOM... Compared to Swing and other non-web UI toolkits I tried, it was simpler, more regular and more adaptable. And the simpler conceptual model was directly supported by the web's core domain-specific languages! Sure, in principle, you could make a pure Java library that had a similar model but it would be much less natural and direct than having dedicated DSLs. Java and Java-style OOP is simply not expressive enough to reasonably encode that kind of conceptual model.

I love languages, but "little" doesn't fit. The reason is that once you pull the thread, you create a boundary and things love to cross boundaries.

My Adama language/platform ( https://www.adama-platform.com/ ) , for example, started as a simple way to manage state within a document and now I've turned it into a distributed system among other things. I'm very happy with it, and I've decided to have a real go at building a company around it.

It's been a long-running (but fairly unimportant) dream of mine to create a language (made several attempts in HS but was more concerned about the IDE UI...). Probably focused on 2D gaming, and I know there's a billion of those. Just something small and fun for my own projects and I'll see where OSS takes it.

Something about inventing a language just feels like an itch almost every programmer has to scratch.

Just do it. A good way to start is by building a Lisp like language as this unveils the game, and then syntax is fun to add.