Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Cassette, a Personal Programming Language (cassette-lang.com)
231 points by news_to_me 9 months ago | hide | past | favorite | 71 comments
I made this simple language over the past year, and it's time for me to say it's "done" (for now) and focus on other projects.

I've struggled to answer the question "what is this language for?" other than "it's just for me" — and that's probably good enough. But I also wanted to make something "complete" that others could use if they wanted to. Writing my own language was an incredibly rewarding experience, and I'd recommend everyone trying it.

Let me know if you have any questions or feedback, and please share your own experience if you've also made a language.




What a great introduction: what it is, how it looks, why you might like it, what the design goals are, and how to write it - all while being short, to the point, and relatively buzzword free. I find a lot of new language offerings (which may be very good technically) fall short on how they make a first impression; other language creators should look at this as a template.


Thanks! While working on this, whenever I would browse another language project's site I got into the habit of asking myself what I wanted to see, in what order. For better or worse, I really want to see a language's syntax first. I think it gives some context, and helps readers connect the concepts of a language to something more visual and concrete.


I agree that it's a wonderful page (although the :symbols confused me a bit), and I want to add that the simplicity of the page, size and lack of complex (almost any) Javascript harks back to how I remember the web when it started.

A clear and concise webpage that gets the message across perfectly without needing megabytes of 'content'.


> without needing megabytes of 'content'.

Although having some MB of an online REPL/Compiler to try the language is _really_ convenient. But not something that should get priority for such a "small" (userbase) language.


> other than "it's just for me" — and that's probably good enough

I love this sentiment, and I'm glad you made this! I love reading different syntaxes for programming languages. You should be proud. Writing programming languages is _hard_.

I made an abstract programming language in 2023 (https://visionscript.dev). The language still needs _a lot_ of work and some bugs fixed. With that said, I had so much fun making it.


VisionScript looks so neat! I always wanted some wrapper around OpenCV as high level as Mathemathica. I see you've even borrowed their syntax.

Though wouldn't it have been nicer as just a library for any functional language for more interesting use-cases like mapping an image of a bar chart to CSV or estimating coefficient of restitution of a bouncy ball?

That's one problem I always had with DSLs, as expressive as they can be for their domain, sooner or later you find yourself having to implement all the features of a modern high level language...


Thank you! The syntax was inspired by Mathematica. I like the idea of using verbs to describe actions that are built into the language.

I had three main motivations for the project:

   1. Learn how to write a programming language;
   2. Explore the extent to which I could use a new language to help people learn computer vision, and;
   3. Learn more about computer vision.
The goal was to create a language that is more suited for beginners, with the intent that you can build a vocabulary you can use to describe computer vision and programming more broadly. The extent to which this is/was achieved is unknown since I'd need to do a lot more work to get it in the hands of new developers, but nonetheless I enjoyed thinking and reading about this.

> sooner or later you find yourself having to implement all the features of a modern high level language

A friend told me "but James, you can just use Python for this!" While that is true, there is definitely something to be said about _how_ you do something, as well as what you can and can't do. How a language works and what it can and can't do is in the hands of the language designer; these decisions are technically interesting to make.


Thanks, that means a lot!

> I made an abstract programming language in 2023

This is super cool. The block editor is especially impressive.


Keep making cool things :)


Your work is in an interesting niche, but I found your home-cooked app philosophy post more fun to read about. It made me feel optimistic about the value of creative coding projects, thank you for writing it.

https://www.robinsloan.com/notes/home-cooked-app/


Looking further into your website, I find the content you write about extremely compelling and well written. The subtle insights about revisions here are great:

https://www.robinsloan.com/moonbound/mortal-after-all/


To be clear, that isn’t my site, I just linked to the home-cooked app article because it resonated with me and I felt it fit the project.


Sorry my bad, your project is cool too! Cassette is a great name for it.


You could have made the file extension ".k7" which is short for "cassette" in French.

Great work of course, just a fun suggestion ;)


I wonder if a numeric in a file extension would cause problems in some systems or violates some convention.


.mp3 is pretty common


At least on Windows, bzip2 and 7z have been common archives for a while. Additionally, ps1 is used by Windows PowerShell. I expect the former two to cause no issues on common Unix distros either.


I think 7zip uses 7z almost everywhere by default ?


Oooh I may have to do this!


K7 also works in Portuguese, and possibly other languages.


I mean, while K exists in the Portuguese alphabet, no words use it.


W, K, and Y were added back to the Portuguese alphabet in 2009, after going away in 1943, exactly because there are words using them.

Also k is widely used in SMS language.


> Playful programming is writing something for the sake of writing it. It’s making a software 3D renderer or a GIF reader, even though better implementations of those already exist. It’s making generative art programs and drawing them with a pen plotter. Cassette itself is playful programming—there are certainly other scripting languages that may be better for personal projects like these, but this one is mine.

Nice hack!


I'm so impressed. I love the syntax (especially the backslash for lambdas and the colon for symbols). I don't know so many languages but it feels quite "new" to me, which is quite hard given the number of languages out there. I recently thought about building my own language just for fun and it makes me realize how all my ideas are just a copy and mix of other languages. The website is also super clean and beautiful (the font is great). How did you manage to use syntax highlighting for your own language on your website?

One thing: I was confused (as others stated here I think) by the link to Robins Loan's website and thought it was an other article from you about Cassette.

Would you consider writing a blog post about how you created it (building the lexer, parser, etc.)? I would definitely be interested.


Thanks! It's hard to escape making a syntax that's just a blend of other language's syntax elements, but I don't think that's a bad thing. Cassette's syntax is in some ways my favorite elements from other languages, and is most influenced by Elixir.

> How did you manage to use syntax highlighting for your own language on your website?

I used Pandoc to format a markdown file to HTML, which supports custom syntax definitions for code sections. (The relevent flags are `--standalone --template=template.html --syntax-definition=syntax.xml`.) The syntax definition is written in an XML format used by the Kate text editor (from KDE): https://docs.kde.org/stable5/en/kate/katepart/highlight.html

> One thing: I was confused (as others stated here I think) by the link to Robins Loan's website and thought it was an other article from you about Cassette.

Thanks, I'll clarify this or remove it soon.

> Would you consider writing a blog post about how you created it (building the lexer, parser, etc.)? I would definitely be interested.

For sure! I've been meaning to write up some of the technical aspects of the project, so those will appear on the site at some point in the future.


> (the font is great)

I also want to shout-out Berkeley Graphics, who made the monospace font. It's been my favorite for some time now.

https://berkeleygraphics.com


I can second this! I've been using it across my dev setup and window manager for almost a year now and haven't wanted to switch to anything else.

I really like how it looks on your page, it makes the code blocks feel "cozy" for lack of a better word.


I like the clear choices you made and that you stuck to them, even when making them optional (particularly shooting for GC-optional) might have attracted attention. Also, like the explicit implementation simplicity as a goal.

I’ve talked about it on Hn a few times, but I wrote the language I use for work. Like you, the language is primarily for me, but my motivation was to prove some type theory and philosophical (mathematics) points I held as true but couldn’t visibly see for myself. It was a trek to get finished, but it was a very rewarding experience.


Thanks! A big part of the project was discovering all of those philosophical sort of trade offs. Going in, I had a naive idea that I could figure out the “perfect language” for me that expressed exactly how I thought. I have a ton more respect for language maintainers now, even when they make decisions I disagree with.


Every now and then the "programming as theory building" article shows up on HN. Language design is even closer to theory building, as it's awfully easy for two superficially unrelated features to interact in an inconsistent way.

(see also Joel Moses on "beautiful crystal structure" vs "ball of mud")


I really like the syntax! I am having trouble building on Linux but I will send patches your way when I figure it out.


Ok, I think I've got it working on Debian now. I've updated the "Getting Started" section with the dependencies: https://cassette-lang.com/#getting-started


Ah yeah, I got a little lazy at the end so the build process is probably a little macOS specific. I'd love to receive patches or bug reports when you get the chance!


Thanks for sharing!

  ; these produce an error, since `b` isn't defined when the body of `a` is compiled
  let a = \x -> (b x * 3),
      b = \x -> (a x / 2)
It surprised me when this was called out, given that both a and b are defined in the one 'let'. Was there a specific reason you decided not to treat it as a 'letrec'?


Yeah I went back and forth on this a little bit. If all variables are defined at the beginning of the `let` expression, you can't rebind a variable like this (assuming some previous `x`):

    let x = x + 1
because the new `x` shadows the old one before `x + 1` is compiled. But if you're defining a recursive function, like this:

    let foo = \n -> foo(n + 1)
you need `foo` to be defined before you compile the lambda body, or else the compiler will think you're referencing an undefined variable.

At one point I had an exception where, if the value of a variable being defined is a lambda, it defines the variable first to allow recursion, but not otherwise. But this felt inconsistent and kind of gross. Instead, I decided to have `def` expressions behave like that, and disallow recursion in `let`. `def` is always a function definition, so you'd almost always want that behavior, and I felt that since it has a different syntax, slightly different assignment semantics wouldn't be so bad.

For mutual recursion you have to go a little further, and find all the definitions in the block before you start compiling anything. So `def` expressions are also hoisted to the top of the block and pre-defined at the beginning. This felt ok to me since `def` expressions look like big, formal, static definitions anyway, and it didn't seem surprising that they would have whole-block scope.


For my hobby language, I figured let rec should be the default and let nonrec the marked case, for exactly the rebinding application. However, it's been over a year since I came to that conclusion, and I still haven't gotten around to implementing the nonrecursive path. (but: mine is very no-moving-parts Immutable, so ymmv)


By the way, why do you need a backslash to define a lambda? Apparently it doesn't give any additional information. All you need to know that's a lambda is the presence of the -> operator. Is that a way to make the compiler faster?


That was a pretty late change to the syntax actually — I really, really wanted Javascript-style lambdas but with a skinny arrow, like `(x, y) -> x + y`. But it made parsing and compiling really finicky, so I settled on the backslash syntax, which I've seen in a couple other languages. It almost looks like a "λ"!


Alternatively, we can go the other way, and dispense with the arrow:

  \x \y x + y
rather closer to the lambda notation in maths, and works well for compact expressions such as S from the SKI combinator calculus:

  \x \y \z x z (y z)
This looks much better with syntax highlighting (hard to demonstrate here of course), being both trivial to implement and informative - just have the back slashed tokens in blue or whatever.

Cassette looks really nice - great intro page, and a great name too! Making something simple is much harder and more valuable than making something complicated.


Love it! Nice work and cool website.


Looks a lot like Elixir and reminds me of Swift. Cool!


Yeah, the syntax is heavily inspired by Elixir, which was of the first languages that "looked right" to me. And Elixir's syntax is very Ruby-inspired, in turn.


is this really lisp like?


I think it's pretty similar semantically, though not syntactically — a lot of it is applying the last chapters of Structure and Interpretation of Computer Programs, which shows you how to build a Lisp interpreter and compiler.


I prefer saying it's more like a lisp-like language like Ruby or Python...


If I've seen this on a flash card I'd have guessed it's a variant of Python.


I'm genuinely disappointed by the predictability of encountering negativity and criticism towards new programming languages, even when the cynics represent a small minority. My address is to those who tend to be critical, cynical, and skeptical. It particularly troubles me when individuals adopt an air of entitlement and phrase their questions as, "Why should I use this? Prove its value to me." I would like to propose that this approach runs counter to the hacker ethos, as it immediately puts such questions in a negative light. There are constructive and useful ways to inquire about new languages, but all too often, I witness people ridiculing and deriding the work that others have shared. If this were our reaction to every new (even experimental) endeavor within the hacker and broader community, we would miss out on exploring fascinating possibilities. Many, if not most, of the technologies we use today began as small kernels or mere experiments. Through the dedication of individuals or small groups of passionate people, they evolved into essential components of our technology stacks. So, while it's perfectly valid to inquire about the compelling features of a language or why one might choose to use it, there are ways to frame such questions without sounding cynical and derisive.


Strongly agree. The "Why should I use this?" posts piss me off to no end...

As someone who often learns by perusing both toy and production projects, almost any kind of code or language idea can be useful to me for learning, so I'm thankful for those projects.

Doesn't matter if it is production quality or experimental, or if the quality is good or bad. The funny thing is that HN has this meme about "the scientific process also being about negative results", but when it's software, people immediately treat it like a product, as if having more things in the world was a negative thing.

I will forever upvote those projects and star them on Github. And I am grown up enough to figure out by myself what they have to "offer".


100% and well said. I feel exactly the same way.


Yes! It's like I should not play the piano, because I could get better music on Spotify. If I play, I play for fun. Also, if I were to make a program language, it would probably be for fun, and to learn. That is a good thing! Having a hobby and learning at the same time is worth so much.


I agree, and while I have gotten a few gentle inquiries about why one might choose this language, it’s mostly a self-criticism I’ve had. It’s one of those impulses that can drive me to achieve more than I might otherwise, but finding the balance is tricky.


Right. I get your perspective. It's important to aim for greater utility and purpose, but it's also crucial not to overdo it at all times, as it might result in a less enjoyable experience and potentially worse ergonomics. Personally, I find Cassette to be delightful. Keep up the exploration!


Every time I sit down to write a toy language I get stuck on two conveniences: syntax highlighting and auto-formatting. I feel like they're table stakes for a programming language in 2024, but they're _just_ annoying enough that I lose interest. Any tips?


Basic syntax coloring is easy: just reuse your tokenizer. You already need a tokenizer for your compiler or interpreter. Assign colors to keywords, strings, numbers, and comments. For this simple syntax coloring you don't need to parse, only tokenize, and for pretty much all languages you can do it on a per-line basis.

Auto-formatting is also easy: just don't do it. Does a toy language really need it? I have two languages with syntax coloring and zero languages with auto-formatting. I think syntax coloring is table stakes but auto-formatting is not. You can have an interesting toy language without auto-formatting.


I dunno, there are a few things I like highlighted that you can’t easily do with just a tokenizer, like parameters or function calls.

> Auto-formatting is also easy: just don't do it.

I agree with this, except that auto-closing grouping symbols is extremely useful and turns out to be pretty easy to support.


Auto formatting for work is an angel, for code you love it is the devil.

Writing code that you love is like crafting it. You align subjects and data in beautiful flows of if/else or case/switch. You put multiple statements on a line if they encompass one "thought"

Try writing without a formatter when you are the sole author.

As for syntax highlighting I agree. You can get 80% of the way there with a vim regex of keywords, but it's one of the main things I'm solving by writing my own editor.


> for code you love it is the devil

This doesn't have to be true! Zig's `zig fmt` doesn't wrap on column count but instead lets you insert breaks with a ",". While this does introduce a level of user discretion which can diminish the braindeadness of autoformatters, I find that it works a lot better because now I can choose where the reasonable place to break is. There may technically be more wiggle room for debate, but now you're spending less time debating variable names or whatever to get it to format not-awfully.


Maybe it's just cause I want to stick to a certain width, but I can't remember the last time I disagreed with the autoformatter.


Have you tried for any length of time?

For example, there's lots of little places where aligning keywords helps clarify code

https://github.com/civboot/civlua/blob/main/ds/ds.lua#L89

Formatters HATE putting multiple statements on a single line, but when they go it makes it so much easier to parse (for a person)


Yeah, I used to not have an autoformatter, and still occasionally I'm working in an environment without access to one. I don't get how this example is clearer than a multi-line if, or perhaps a ternary operator (idk if lua has that).


My problem is that when designing my own language, I decided on GC, lambda syntax, async/await, weak typing, and... oops, it's basically just Javascript. Sure it'd have tons of smaller differences vs JS, but it's too demotivating.


It is still a great learning exercise IMO. Knowing which features are good/familiar to use, but difficult to implement, lets you explore other avenues, like news_to_me and the backslash for lambda [1].

For me, for example, I was gonna go with async/await in my toy language, but didn't like the implementation and decided to explore a monad-like direction.

[1] https://news.ycombinator.com/item?id=38851863


I can see this learning exercise applying to other things, only it takes a lot of time and commitment. So far I've also learned a lot on other projects that I was able to carry out more fully. But everyone has their thing.


Javascript (for all its warts) does in many ways seem to be converging on a certainly local maximum for ergonomic language design. Perhaps this is because it is used so much in the 'wild west' of browser programming? Where things can move quickly, with polyfill for backwards compatibility (a modern marvel to my eyes, being able to use new language features on old platforms!)


Yes, it's an example of not letting perfection get in the way of good. They made something accessible, and the finer details got worked out later.


The other thing is, JS was designed with the web use case in mind. If I ever make a language, it'll be for some new use case that really needs one, perhaps some extension of SQL. And it'll prioritize ease of use in that case over "purity" or other principles.


Js lacks progressive typing, that could be an interesting feat


TS tried, and I didn't like the end result.


When you start, your language is just for you so the question is are syntax highlighting and auto-formatting table stakes for you? If yes, then I'd suggest you learn how to write a tree-sitter grammar and integrate with your editor of choice. This will also get you up and running with a basic AST rather quickly and you can decide whether or not you want to write your own parser or just use the tree-sitter generated ast for your compiler.


This was a super annoying aspect of this project actually, since you basically have to write an additional parser in whatever syntax highlighting format your editor uses (sublime text in my case). The only thing I really learned is the easier the syntax is to parse, the better.


Gnome has a syntax highlighting sub-system that editors like Xed and Pluma use, with .lang files somewhere iirc, regex based, can do keyword and literal highlighting quite nicely. Limited to Gnome of course, but good for experimentation. Maybe Windows/Mac/other Linux has something similar.

Edit: for VS Code:

https://code.visualstudio.com/api/language-extensions/syntax...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: