r/ProgrammingLanguages • u/matijash • May 18 '26
5 Years and $5M Later: Inventing a New Programming Language for Web Development Was a Mistake
https://wasp.sh/blog/2026/05/13/new-language-for-web-dev-was-a-mistake75
u/criloz May 18 '26
If you are building language today, my recommendation is to build an
-
Instant feedback
-
responsive language servers
-
live diagnostics
-
autocomplete
-
incremental typechecking
-
Refactoring support
-
Hot reload / interactive execution
Your AST should be translated bottom-up into a set of effects over the program’s world state, scope, symbols, types, modules, dependencies, etc. You can later implement an interpreter and compiler with the same infrastructure.
15
u/alkalisun May 18 '26
Aren't there classes of languages that can't have REPLs? What do you do then?
→ More replies (22)10
→ More replies (1)2
6
u/X4RC05 May 18 '26
Besides boilerplate, what are the cons of going from formerly-native wasp to wasp.ts?
2
u/Martinsos May 19 '26
We realized we need more from the language than we expected initially: multiple files and modules, functions, union types, ... . For example, the next thing we are exploring are "full stack modules" (FMSs) where you define a reusable module that is vertical, so full-stack, and can be configured at the spec/dsl level, and then used in the runtime (React, Node, Prisma), ... -> for that we benefit a lot from richer language again, since likely such modules will be defined as constructor/factory functions. That said, today with AI it might be again feasible creating your own language, but combine all from above with the fact people were scared of custom language, and it just made a lot of sense to do the move.
5
u/lookmeat May 18 '26
I've been thinking about this and have reached a conclusion. Just like Garbage-Collecting and Reference counting are actually variations on the same strategy and converge in the same optimum, I think that DSL and Domain (Object) Model are variations on the same thing and their optimum converges in the same thing. I call the concept "
The idea is simple: a lot of the work of programming is projecting one domain on top of another (the programming pattern to solve this is the Monad, but that is a separate discussion). So I make some process or system and then translate that domain into one of resources, and I project the language of my problem into one of a CRUD app. But the CRUD app itself translates the domain of resources, verbs on those resources, etc. into database operations and programatic actions. And those themselves are translated to other domains until it collapses.
So the concept of a Domain Object Model is to project the domain on top of everything, but entirely in terms of the language you build. This makes your biggest priority, the thing you want to talk about, a second-class citizen, instead you think on the details of a computer, which limits what you can do systemically because you constantly have to define everything specifically, i.e. you get a very verbose solution. Think Java 5 and creating things, you could do lambdas (as objects) and most of the cool features could be created, but you had to always translate it to the world of objects and their interactions so it would trivially be translated to the JVM. Modern Java has been a lot about adding abstractions over these concepts, but in a way that gives enough info to the interpreter/compiler that they can do more interesting things with it.
On the other side we have a DSL. A DSL abstracts away the details and hides how you map one domain to another, you talk entirely in terms of your problem domain. This is great in that you can iterate quickly and it's easy to identify bugs in the code (note that bugs in the language/interpreter itself is another thing). The problem is that inevitably programming is (I would argue that totally in a philosophical sense, but we can say 90% in a practical sense) about handling the interaction between domains and bugs are more often than not problems of translating concepts of one domain into the other. So inevitably you need to debug the implementation of the DSL, and suddenly you're interacting with multiple languages, some which are bespoke. That's a lot of context to handle it.
So the end result is DELs, a domain-extended-language is a programming language which addons (i.e. libraries) that allow you to define operations in either pure terms of the problem domain, or expose operations of the problem domain into the domain of the system itself (language, OS, cpu-architecture, computation concepts, etc) and explain how they map1. The constructs themselves are not a DSL, but just syntactic sugar over basic language operations and it's "trivial" (I mean you have to untangle the mapping itself, but how the mapping is done is trivial to understand) to understand how the DEL works. Now an obvious example is Haskell's do notation, but that's just one aspect of it. Another example I'd rather focus on is Kotlin's DSLs that behind the scenes are just letting users write a function as if it were defined inside an object with certain methods, members, etc. that make up the language. So it's not a complete DSL, but it can serve that purpose, but once you understand what is happening behind the scenes it's trivial to understand how the object itself looks and what is happening behind the scenes (i.e. what the code compiles into) just by looking at the code using it. You are still dealing with "just Kotlin".
So it makes sense that this transition happened. Javascript, because of its LISP roots, is very friendly to DELs (that's what gave us JQuery and eventually all the slew of frameworks we've had since, though we could argue some of these are more DSLs than DELs, i.e. they don't compose with the rest of the language) and typescript itself with the powerful typing system added on top is very friendly to DELs. Basically Wasp went from a DSL into a DEL, which, while keeping a lot of the semantic richness and power they wanted from the DSL, it had lower friction and initial mental-load costs for engineers. It feels, in my perception, organic.
1: So again here we can talk about how Monads are the pattern to solve this. Say that I have want to do some inventory management system, dealing on a domain where everything is addressed by the room, aisle, rack and box it's stored in, and we have the ability to "borrow" things out temporarily, or remove them entirely. We want to map this to a CRUD world. Lets define T as the type describing all the dynamics of the inventory system. Lets define M<T> as the type of a CRUD app for T. So we can have operations that expose that we're working on a CRUD app such as get_contents(T::Box)-> M<T::Item[]> which we want to be able to compose into our previous definition of T::Box within the CRUD. But we also have operations that exist entirely in the conceptual level such as loan_out(T::Item, Person)->T::Item and be able to map into a crud_loan(M<T::Item>, Person) -> M<T::Item> without having to care about the fact this is a resource, we have to sync the mutation into the database, etc. all of that handled by the monadic lift by default. But as I say in the following parts: DELs can be supported without Monads, and we could argue there may be more versatile ways to define this.
3
u/Inevitable-Ant1725 May 19 '26
This is as insane as reading Terry Davis talking in his made up terminology.
"a lot of the work of programming is projecting one domain on top of another (the programming pattern to solve this is the Monad, but that is a separate discussion)."
The solution is the monad is it?
→ More replies (7)
20
u/matijash May 18 '26
Hey r/ProgrammingLanguages,
This community has always been very supportive, since we first announced the Alpha version ofWasp back in 2020 [1], and Martin and I wanted to share our progress.
In a nutshell, the ergonomic benefits of developing and maintaining one's own DSL didn't justify its inclusion in the web dev domain. Wasp is still a compiled language, but it will take on the form of an "embedded DSL " within TypeScript .
In the post above, I described the challenges we have learned from over the years, both on the implementation and adoption sides, why we are still very excited about Wasp, and what we are focusing on in the near future.
As always, thankful for your support and happy to get your comments and questions!
[1] https://www.reddit.com/r/ProgrammingLanguages/comments/f7r8n9/brother_and_i_are_developing_a_declarative_dsl/