Rhombus Language
72 comments
·March 18, 2025pmontra
gus_massa
From Rhombus you can call all the Racket libraries. I used Racket in a few projects:
* To edit a Moodle backup file, I used Racket to unzip it, find the xml file, parse and filter some of the parts of the xml file and then zip the new version.
* To autoreply some emails, I used IMAP, then scrap some info from my webpage and then SMTP.
There is also a JSON library, but I never used it.
The only problem is that some libraries have no wrappers still, so instead of the expected snake_case name you must use the spear-case with some delimiter to make the parser happy. (Something like |spear-case| or {spear-case}, I should check the docs.) And if that annoys you too much, it's easy to write a macro with a rename transformer so you can use the nice snake_case name, it adds a negligible compilation time and no penalty at run time.
timkq
TypeScript & Rust don't "look nice to work with" because they force you to write maintainable code that doesn't just stop working because of a random runtime error. In my opinion, Go looks nice to work with but actually is a hidden monster full of footguns.
hnlmorg
Curious to read that because I’ve always had the opposite opinion of the above:
Typescript looks nice to work with but the tool chain is horrible (this isn’t really Typescripts fault though, more a synonym of it having to compile to JS).
Go looks horrible to work with (too simplified syntax) but is actually really nice because the tooling is (mostly) spot on and it’s simplified syntax weirdly helps with maintainability for large projects that have evolved over multiple years.
I guess this just goes to show how much personal preference can be a driving force behind our platforms of choice.
frontfor
I’m not sure about Go being full of footguns, but for one, a panic in any goroutine forcibly terminates the entire application.
a2800276
Exactly, Typescript doesn't stop working because of random runtime errors, it stops working because you didn't update the toolchain tangle last Thursday and then some configuration file got out of whack with the tsc defaults ;-)
pjmlp
Typescript is like C++ and Objective-C for C.
Technically, it provides an improved type system that offers the tooling to write safer code.
In practice, plenty of folks just rename the file extension and keep coding as they always did.
alpaca128
Technically TypeScript doesn’t force you to anything other than writing valid JS code. Its design was great for wide adoption but also suffers from the JS part.
kalekold
> Go looks nice to work with but actually is a hidden monster full of footguns.
Really? Me and my team been using it for years with no problems whatsoever.
tgv
While Typescript has the gaping hole that is typing external data. Your code can't enforce that in TS, but in Go you're forced to.
I do admit Go has an easily found foot gun: nil pointers. It's a small one though, in comparison to the original problems with nil pointers. More stubbing your toe than shooting your foot.
cies
I found Kotlin a "typed Ruby" (I found Ruby a "sane Perl").
Rust seems pretty nice to work with (good DX) in it's domain: close to the metal programs were every tick counts. The main DX issue with it would be compile times.
Go's awful to me from a DX perspective as it is lacks proper error handling. Compile times are great though.
Maybe OCaml is a good fit for me (and you!). Fast compile times and good error handling.
TypeScript suffers too much from being a JS superset. JS has horrendous DX imho.
dominicrose
Interesting. I learned Ruby a long time ago because a Perl expert told me Ruby was getting good. I like Typescript because it's really easy to read and maintain without breaking anything. But you can't do this: `next x.map { _1 + 3 }.sum if sth`. I guess I should give Kotlin a try then.
lygaret
This is racket's [rhombus], which might be an interesting second link here; it's a scheme, underneath, with the full power of Racket libs available.
[`shrubbery`], the replacement for s-exprs, is pretty interesting, expanding s-expr simply with grouping, and then a separate infix-pass on top. I've been playing with using it as the basis for a separate language; it's in an interesting place in the AST space, especially given the forethought put into macros.
[rhombus]: https://docs.racket-lang.org/rhombus/index.html
[shrubbery]: https://docs.racket-lang.org/shrubbery/index.html
HexDecOctBin
I really wish they had kept the old C-like Honu syntax rather that the Python-like Shrubbery. If Rhombus is supposed to be an educational language, copy-pasting and trying out new code is going to be a important part of ecosystem, and indentation based syntax is not ideal for that.
spdegabrielle
A valid point.
There is a long history of identifying the problems and risks of copy-pasting, and trying to reduce it. I remember it was a selling point of Java in the early days. For all the efforts it doesn't seem to be going away. (all the boilerplate in Java probably didn't help)
I'd love to see a C-like Rhombus. A Chombus.
shakna
C-parsing is still built-in [0], so whilst I don't think the standard library has a C-language, it's either really simple, or there'll be a few on the package manager.
dexterlagan
I have used Racket in production for a decade and a half, with great success. Racket belongs to a sort of invasive species equivalent in languages, in the sense that once it has a hold on you, all other languages, old and new, vanish from your mind. The elegance of Scheme married with the power of hygienic macros does a great job at tricking your mind into believing Paul Graham's Hundred-Year Language idea again.
What if Racket and Python had a child? Rhombus represents much, much more to us Racketeers. It may quite possibly be the crown jewel of multi-paradigm meta-programming languages and most importantly, a possible solution to the 's-expression barrier'. Who knows, it might even make a dent in the LISP curse. And we were all hoping for this. We were all waiting for this. And so I applaud the enormous effort involved, and I hope it inspires people to try a different approach to programming, and to language in general. It represents an impressive achievement in terms of elegance, pragmatism/practicality and efficiency in a language built atop a very solid foundation, coming from one of the greatest lineage of programming languages in history.
Like many others, I have been waiting for a killer app, a real showcase of the power of language-oriented programming. I was secretly hoping Rhombus would become a catalyst to the production of something great. While the emergence of LLMs presents challenges, it doesn't have to seal the fate of amazing purely and proudly human innovations like this one. My GitHub account may be filled with Racket code few will ever use, but Rhombus gives me new inspiration.
Sure, the future of programming might involve neural networks programming CPUs and GPUs directly. We're getting there. Yesterday we were programming with cryptic machine language, today we program computers with increasingly natural syntax. Tomorrow we might just tell machines what we need. But that doesn't make what we're doing now any less significant or exciting.
We programmers aren't going anywhere just yet, and many of us will keep writing code because we love it, not just because we have to. And now we have this pinnacle of human ingenuity in the form of a beautiful language, a love letter to the art of programming by humans, for humans. Thank you.
rednafi
The syntax looks clean, akin to Python, but with terser record types. This would make a nice config or an embedded language like Lua.
One thing I’d appreciate here is a “Why Rhombus?” page, even if the rationale is simply that it’s fun.
Edit: Turns out there’s a goals[1] page. Rhombus is trying to replace Lisp’s parenthesis-heavy syntax with something cleaner while keeping Racket’s powerful macro support.
Jtsummers
> Why a new language? See Rhombus Goals.
Rhombus Goals links to: https://rhombus-lang.org/goal.html
rednafi
Graaah, totally missed it. Thanks!
hudon
here is the "goal" page: https://rhombus-lang.org/goal.html (with related paper & talk)
rednafi
Thanks. It’s nice to see at least a few in the FP community recognize that Lisp dialects, with their parenthesis-ridden S-expressions, are hard to read and write.
cardanome
It is hard to have empathy for a problem you don't have.
I have only recently become open to the idea that people might legitimately experience pain using an unfamiliar syntax.
For me, it is a non-issue. From Lisp to C to APL to Forth to Prolog, syntax was never an issue for me. I greatly enjoy learning languages with different approaches to syntax. It has never caused me pain. Only joy. Then again programming languages are my special interest.
It kind of easy to dismiss complains about syntax as intellectual lazyness. After all, learning Lisp-style syntax takes maybe a few hours tops, how can that be a problem? Syntax is just the easiest to criticize but would these people really learn the language if it had curly braces or is it just an excuse?
I don't know. I am the kind of person whose day gets ruined by an app minimally changing its UI so maybe I shouldn't be too judgy about syntax sensitive people.
pjmlp
This is nothing new, see
- M-expressions (https://en.wikipedia.org/wiki/M-expression)
- Lisp 2 (https://en.wikipedia.org/wiki/LISP_2)
- Dylan (https://en.wikipedia.org/wiki/Dylan_(programming_language)
- Wolfram (https://en.wikipedia.org/wiki/Wolfram_Language)
- Julia (https://en.wikipedia.org/wiki/Julia_(programming_language))
However the large majority of Lisp folks end up using plain old Common Lisp and Scheme with their S-expressions, because it is easier, it is like telling written languages with symbols are harder than those with latin characters, it is only hard to read and write until one actually learns them.
MathMonkeyMan
I'd say it's more like "we've been teaching Scheme for decades, and we just have to admit that most people don't like S-expressions."
Y_Y
I've been cautiously optimistic about Rhombus since the initial "Racket 2" controversy. I'd have preferred they went with something more like Wisp or Wraith, but it could be a lot worse.
I am somewhat troubled by tricks that are "too magic", like this example from front page:
class Posn(x, y)
fun flip_all([Posn(x, y), ...]):
[Posn(y, x), ...]
flip_all([Posn(1, 2), Posn(3, 4)])
// ⇒ [Posn(2, 1), Posn(4, 3)]
Why should the later Posns be flipped? That's certainly not what I would expect.(Then again being too magic is working well for Python, e.g. that a<b<c thing)
soegaard
It's not magic. It's pattern matching.
The `[Posn(x, y), ...]` is a pattern that matches a list of positions. The `[Posn(y, x), ...]` is a template that produces a list of positions.
norman784
Care you to elaborate on Racket 2 controversy? I don't follow the language, but I'm aware of it, so I didn't learn about the controversy.
anacrolix
This is good to see, but I think too much effort is being used to maintain the prefix style function application. As a result a significant amount of the novelty is just mapping syntax from new to old. Special cases, special cases everywhere, even in an implementation like this which is specifically attempting to allow you to make your own "special" cases.
Tewboo
Interesting to see a new language like Rhombus popping up. Always curious to see what innovative features it brings to the table.
wavemode
From the 2nd example:
class Rect(left, top, right, bottom)
fun rect_like_to_rect(v): match v | Rect(_, _, _, _): v | {"LT": [l, t], "RB": [r, b]}: Rect(l, t, r, b) | {"TL": [t, l], "RB": [b, r]}: Rect(l, t, r, b)
rect_like_to_rect({"TL": [0, 2], "RB": [10, 5]}) // ⇒ Rect(0, 2, 10, 5)
Isn't this wrong? I'd expect to see Rect(2, 0, 5, 10) instead.
It also seems like "RB" was meant to be "BR".
unwind
If you indent each line by, uh, something (I use 4 spaces), HN gives you code formatting:
class Rect(left, top, right, bottom)
fun rect_like_to_rect(v):
match v
| Rect(_, _, _, _): v
| {"LT": [l, t], "RB": [r, b]}: Rect(l, t, r, b)
| {"TL": [t, l], "RB": [b, r]}: Rect(l, t, r, b)
rect_like_to_rect({"TL": [0, 2], "RB": [10, 5]})
// ⇒ Rect(0, 2, 10, 5)
rect_like_to_rect({"LT": [0, 2], "RB": [10, 5]})
// ⇒ Rect(2, 0, 5, 10)
Not sure about the typo though, just wanted to make the code readable here since showing off code in the language being talked about is helpful.gus_massa
I guess it's a typo and the second line should say "BR". I just send a PR to fix it.
coolio1232
This actually looks good. It's like a less-obtuse Haskell. At a glance the features seem to be just the right mix of functional programming paradigms and standard imperative programming.
steve_adams_86
The other day I saw someone describe writing Haskell as “programming with your elbows while listening to math rock”, which is awesome. I can see the need for a less-obtuse Haskell
ksp-atlas
It also involves sending values forwards and backwards in time using Tardises occasionally
bmitc
Less obtuse Haskells have existed for years: Standard ML, OCaml, and F#.
bmitc
What is the relation to Haskell?
The language is basically Racket, which is a Scheme at its core. There's very little in common with a language like Haskell.
coolio1232
Syntax-wise it looks a lot like Haskell to me, especially the pattern-matching, the variable declarations (with `::`), as well as the indent-based blocks.
cies
It's usually called ML-syntax. SML, OCaml, Elm, PureScript, and many more have used this.
galaxyLogic
So it's not PURE!
otabdeveloper4
Yeah, it doesn't have the one thing that makes Haskell Haskell.
cies
> What is the relation to Haskell?
I could only think of is they are both being a "typed lambda calculus" language with an ML-syntax.
zerr
Does anyone use Racket outside academia? Is it production ready (or friendly)? Especially Typed Racket.
spdegabrielle
Racket has been used outside academia for years. Racket has been production ready for years.
Here is a recent example https://blog.cloudflare.com/topaz-policy-engine-design/
MathMonkeyMan
I've used it for some command line [tools][1]. Nothing running on production. Mostly programs that process programs or markup. I haven't used Typed Racket.
[1]: https://github.com/dgoffredo?tab=repositories&q=&type=&langu...
procaryote
I tried, it's a really nice language with almost no libraries so you end up reinventing the world every new thing you do. It's not really practical compared to arguably worse languages with better ecosystems
eviks
How hard would it be to uniquely extend the language to make *fun* into *fn* and *...* into a single letter *…*?
fun all_same([str0, str, ...]):
all(str0 == str, ...)
rscho
Very easy. You could do it yourself after 5 min of reading ;-)
eviks
That time would only be enough to read the overview, go through the examples, click on the "uniquely customizable" link hoping to see the answer and then be flooded with the garbage digital tokens of the scientific world - 100+ references...
fc417fc802
True. If you are new to Lisps it will require substantially more than 5 minutes to learn about the different types of macros. For Racket in general you might start here.[0][1] For Rhombus probably here.[2][3]
I'm not clear what your asking about regarding the ellipses though.
[0] https://docs.racket-lang.org/guide/macros.html
[1] https://docs.racket-lang.org/reference/Reader_Extension.html
[2] https://docs.racket-lang.org/rhombus-meta/index.html
[3] https://docs.racket-lang.org/rhombus/Syntax_Objects_and_Macr...
datadeft
Is it possible to have Hindley–Milner type system for a LISP?
tmtvl
I don't know what Hindley-Milner means, but maybe Coalton matches what you mean? <https://github.com/coalton-lang/coalton>
lou1306
It's static typing with inference. Essentially what you have in Haskell/OCaml/F# where you declare a variable `x` through a let-binding witout specifying its type (`let x = something`), and the compiler analyses `something` and infers the type of `x`.
The examples on the home page are a nice way to quickly show the features of a language. I'll check the documentation to see how to work with files, make HTTP calls, parse JSON.
It's the first time in more than 10 years that I actually feel like trying a new language. The last time was Elixir. Since then I had to use Lua (hobby project) and Python (work) but I don't enjoy them much. I would have skipped them if I hadn't have to use them. Before Elixir I enjoyed Ruby, before that it's been Perl 5 in the 90s. Everything else I used in that period and before was because I had to (C, Java, PHP, JavaScript/Node) and I skipped many other mainstream languages because they didn't look nice to work with (Go, Rust, TypeScript.) I still have to see what's writing and running a Rhombus programs looks like so I might discover that it's not so nice after all. I'm hopeful.