I've chatted a bit with the author, but not actually tried the language. It looks very interesting, and a clear improvement. I'm not particularly quiet about not liking Go[1].
I do think there may be a limit to how far it can be improved, though. Like typed nil means that a variable of an interface type (say coming from pure Go code) should enter Lisette as Option<Option<http.Handler>>. Sure, one can match on Some(Some(h)) to not require two unwrapping steps, but it becomes a bit awkward anyway. (note: this double-Option is not a thing in Lisette at least as of now)
Lisette also doesn't remove the need to call defer (as opposed to RAII) in the very awkward way Go does. E.g. de facto requiring that you double-close on any file opened for write.
Typescript helps write javascript, but that's because until WASM there was no other language option to actually run in the browser. So even typescript would be a harder sell now that WASM can do it. Basically, why try to make Go more like Rust when Rust is right there? And fair enough, the author may be aiming for somewhere in between. And then there's the issue of existing codebases; not everything is greenfield.
So this seems best suited for existing Go codebases, or when one (for some reason) wants to use the Go runtime (which sure, it's at least nicer than the Java runtime), but with a better language. And it does look like a better language.
So I guess what's not obvious to me (and I mentioned this to the author) is what's the quick start guide to having the next file be in Lisette and not Go. I don't think this is a flaw, but just a matter of filling in some blanks.
[1] https://blog.habets.se/2025/07/Go-is-still-not-good.html
> Basically, why try to make Go more like Rust when Rust is right there?
Go gives you access to a compute- and memory-efficient concurrent GC that has few or no equivalents elsewhere. It's a great platform for problem domains where GC is truly essential (fiddling with spaghetti-like reference graphs), even though you're giving up the enormous C-FFI ecosystem (unless you use Cgo, which is not really Go in a sense) due to the incompatibilities introduced by Go's weird user-mode stackful fibers approach.
> Basically, why try to make Go more like Rust when Rust is right there?
The avg developer moves a lot faster in a GC language. I recently tried making a chatbot in both Rust and Python, and even with some experience in Rust I was much faster in Python.
Go is also great for making quick lil CLI things like this https://github.com/sa-/wordle-tui
No doubt a chatbot would be built faster if using a less strict language. It wasn't until I started working on larger Python codebases (written by good programmers) that I went "oh no, now I see how this is not an appropriate language".
Similar to how even smaller problems are better suited for just writing a bash script.
When you can have the whole program basically in your head, you don't need the guardrails that prevent problems. Similar to how it's easy to keep track of object ownership with pointers in a small and simple C program. There's no fixed size after which you can no longer say "there are no dangling pointers in this C program". (but it's probably smaller than the size where Python becomes a problem)
My experience writing TUI in Go and Rust has been much better in Rust. Though to be fair, the Go TUI libraries may have improved a lot by now, since my Go TUI experience is older than me playing with Rust's ratatui.
[dead]
> moves a lot faster in a GC language
Only in the old "move fast and break things" sense. RAII augmented with modern borrow checking is not really any syntactically heavier than GC, and the underlying semantics of memory allocations and lifecycles is something that you need to be aware of for good design. There are some exceptions (problems that must be modeled with general reference graphs, where the "lifecycle" becomes indeterminate and GC is thus essential) but they'll be quite clear anyway.
> Only in the old "move fast and break things" sense
No, definitely not only in that sense. GC is a boon to productivity no matter how you slice it, for projects of all sizes.
I think the idea that this is not the case, perhaps stems from the fact that Rust specifically has a better type system than Java specifically, so that becomes the default comparison. But not every GC language is Java. They don't all have lax type systems where you have to tiptoe around nulls. Many are quite strict and are definitely not "move fast and break things" type if languages.
Well if you think Java doesn't have a sufficiently good type system, then surely Go is even further from one?
Not saying those are the only two GC languages, just circling back to the post spawning these comments.
- [deleted]
From your blog entry:
> Go was not satisfied with one billion dollar mistake, so they decided to have two flavors of NULL
Thanks for raising this kind of things in such a comprehensible way.
Now what I don't understand is that TypeScript, even if it was something to make JavaScript more bearable, didn't fix this! TS is even worse in this regard. And yet no one seems to care in the NodeJS ecosystem.
<selfPromotion>That's why I created my own Option type package in NPM in case it's useful for anyone: https://www.npmjs.com/package/fp-sdk </selfPromotion>
ReasonML / Melange / Rescript are a wholistic approach to this: The issue with stapling an option or result type into Typescript is that your colleagues and LLMs won't used it (ask me how I know).
You can enable null safety in TypeScript, seems like a pretty good fix to me.
Where did we lose you? we're talking about two flavours of null, not one.
Your readme would really benefit from code snippets illustrating the library. The context it currently contains is valuable but it’s more what I’d expect at the bottom of the readme as something more like historical context for why you wrote it.
Yup, in my TODO list (I've only recently published this package). For now you can just check the tests, or a SO answer I wrote a while ago (before I published the idea as an npm package): https://stackoverflow.com/a/78937127/544947
"A typed nil pointer is not a nil pointer."
How would TS fix null in JS without violating its core principles of adhering to EcmaScript standards and being a superset of JS?
Maybe spit warnings when undefined is used? In the same way it does for when you use typeScript in a type-loose way.
But yeah it's a fair point. Sometimes I think I should just write my own lang (a subset of typescript), in the same fashion that Lisette dev has done.
Rust's async story is much less ergonomic than go's -- mostly because of lack of garbage collection. That might be a good reason by itself?
Does Go actually have an async story? I know that question risks starting a semantic debate, so let me be more specific.
Go allows creating lightweight threads to the point where it's a good pattern to just spin off goroutines left and right to your heart's content. That's more of a concurrency primitive than async. Sure, you combine it with a channel, and you've created an async future.
The explicit passing of contexts is interesting. I initially thought it would be awkward, but it works well in practice. Except of course when you need to call a blocking API that doesn't take context.
And in environments where you can run a multitasking runtime, that's pretty cool. Rust's async is more ambitious, but has its drawbacks.
Go's concurrency story (I wouldn't call it an async story) is way more yolo, as is the rest of the Go language. And in my experience that Go yolo tends to blow up in more hilarious ways once the system is complex enough.
For one, I am glad I don't have to color my functions like your typical async.
I agree that this is the big problem with Rust's async story.
But like I said, in my opinion this compares with Go not having an async story at all.
Go's async story is great, as there is no function coloring at all. That being said, I don't like Go's syntax very much. The runtime is great though.