42 comments

[ 2.9 ms ] story [ 74.0 ms ] thread
Language syntax is like the weather. When it's good (or when you're acclimated to it, I guess) you don't notice it. When the weather is perfect you don't even feel like the atmosphere even exists. When a language is so ingrained in your mental models, you don't even notice syntax, you just see semantics.
In the follow up article, I wrote something like this in the conclusion:

> Designing a language is more than just getting the syntax right, and denotation semantics are a lot more important in most ways, but that does not mean syntax does not matter. When you get syntax right, people won’t even know you’ve done anything at all. But when you’ve got it wrong (and have actually tried using the language), they will complain instantly.

Follow-up Article: https://www.gingerbill.org/article/2026/02/21/does-syntax-ma...

A lot of programming is taste, and syntax gives you a very quick judgement about how good the language designer's taste is. How familiar they are with what we know about which syntax works well, and so on. For example if you're designing a language in 2026 that uses `type name` instead of `name: type`... that is highly suspicious.

Also syntax is the interface through which you interact with the language, so bad syntax is going to be something annoying you have to deal with constantly. Sure you'll be able to write good programs in a language with bad syntax choices, but it's going to be less fun.

> Odin’s rules, which are very similar to Python’s, are to ignore newline-based “semicolons” within brackets (( ) and [ ], and { } used as an expression or record block).

Honestly I always thought that was a bit crap in Python and I'm surprised anyone thought this was a sensible thing to copy. Really, just use semicolons. As soon as an "easy" rule becomes even vaguely difficult to remember it's better to bin it and just require explicitness, because overall that is easier.

Did you even read the article, even the heading of that section? You know there is a huge majority that do not want semicolons whatsoever, so saying people should just suck it up is actually a determent to the adoption of the language because of people's general tastes.
As Ken Iverson noted in "Notation as a Tool of Thought"[1], yeah the syntax absolutely matters. The same program might resonate and make sense in one language but be incomprehensible if translated 1:1 in another.

Computer languages are for humans to understand and communicate.

1. https://www.eecg.utoronto.ca/~jzhu/csc326/readings/iverson.p...

Syntax is what keeps me away from Rust. I have tried many times to get into it over the years but I just don't want to look at the syntax. Even after learning all about it, I just can't get over it. I'm glad other people do fine with it but it's just not for me.

For this reason (coming from C++) I wished Swift were more popular because that syntax is much more familiar/friendly to me, while also having better memory safety and quality of life improvements that I like.

A languages syntax and its error messages are its user interface. Yes you can have a good tool that you don’t enjoy looking at. You can also have a good tool that’s frustrating to learn because its user interface isn’t clear and doesn’t do what you expect. Can I not hope for something that does what I need, is easy to use, and looks good?

I dislike the “you can change the syntax” argument because that just doesn’t happen. Closest thing is a new language that compiles to another.

I have really just one wish when it comes to syntax: no syntactically significant whitespace. Space, newline, tab, etc. should ALL map to the same exact token. In practice this also means semicolons or something like them are needed as well, to separate expressions/statements. I dislike langs that try to insert semicolons for you, but at least it's better than the alternative.

the way python treats whitespace is a huge design mistake that has probably wasted like a century (if not more) worth of time across all users, on something really trivial.

Semantics are where the rubber meets the road, certainly; but syntax determines how readable the code is for someone meeting it the first time.

Contrast an Algol-descendant like C, Pascal, Java, or even Python with a pure functional language like Haskell. In the former, control structure names are reserved words and control structures have a distinct syntax. In the latter, if you see `foo` in the body of a function definition you have no idea if it's a simple computation or some sophisticated and complex control structure just from what it looks like. The former provides more clues, which makes it easier to decipher at a glance. (Not knocking Haskell, here; it's an interesting language. But it's absolutely more challenging to read.)

To put it another way, syntax is the notation you use to think. Consider standard math notation. I could define my own idiosyncratic notation for standard algebra and calculus, and there might even be a worthwhile reason for me to do that. But newcomers are going to find it much harder to engage with my work.

An article about diversity of language syntax that somehow only deals with C-adjacent curly-brace languages (and,tbf, Odin).

This is a blinkered viewpoint. If you want to talk about syntax, at least mention the Haskell family (Elm, Idris, F*, etc), Smalltalk, and the king of syntax (less) languages, LISP (and Scheme), which teach us that syntax is a data structure.

The article does no such thing and just focused on declaration syntaxes and semicolons. I can class literally any language into the three categories for declaring variables.

* Haskells are name-focused languages. * Smalltalk is a name-focused language. * LISPs are qualifier-focused languages.

I think you might have a blinkered viewpoint in how you have interpreted the article.

I think you oversimplify things a bit.

Are those names erased during compilation? It has a massive impact.

If you have indirect calls, how are those resolved? That matters a lot.

What is even the language, after the code is compiled/interpreted. Does it disappear like in many languages? Do you have some parts available, but not all (like in PHP)? Or do you have full runtime at hand and you can mold it like in Smalltalk? There are languages with no runtime, languages with some runtime, and languages with full image in place. Each has massively different pros and cons.

When you say Haskell and Smalltalk are name focused, you are technically right, but developer experience is extremely different.

The syntax of a language is the poetry form, it defines things like meter, scansion, rhyming scheme. Of course people are going to have strong aesthetic opinions on it, just as there are centuries of arguments in poetry over what form is best. You can make great programs in any language, just like you make beautiful poetry in almost every form. (Leaving an almost there for people that dislike Limericks, I suppose.) Language choice is one of the (sometimes too few) creative choices we can make in any project.

> Another option is to do something like automatic semicolon insertion (ASI) based on a set of rules. Unfortunately, a lot of people’s first experience with this kind of approach is JavaScript and its really poor implementation of it, which means people usually just write semicolons regardless to remove the possible mistakes.

Though the joke is that the largest ASI-related mistakes in JavaScript aren't solved by adding more semicolons, it's the places that the language adds semicolons you didn't expect that trip you up the worst. The single biggest mistake is adding a newline after the `return` keyword and before the return value accidentally making a `return undefined` rather than the return value.

In general JS is actually a lot closer to the Lua example than a lot of people want to believe. There's really only one ASI-related rule that needs to be remembered when dropping semicolons in JS (and it is a lot like that Lua rule of thumb), the Winky Frown rule: if a line starts with a frown it must wink. ;( ;[ ;`

(It has a silly name because it keeps it easy to remember.)

Python doesn't have automatic semicolon insertion.
Yes it does. You can even type `;` anywhere too, go an try it.

Because of how good the rules are for Python's needs, most people never know that semicolons even exist in Python.

Python actually has optional semicolons.
Syntax, or how humans perceive the syntax, is only a very small part of the problems when designing a programming language. There is a lot more about how a compiler would handle the syntax (efficiently) and about how the syntax affects actual code and ecosystem.

The recent go blog on error handling should make it clear that syntax is often not worth worrying about. https://go.dev/blog/error-syntax

I like the semantics you type in the google search bar when using it for impromptu calculations. You can use ^ to raise to a power, for example. Just type sin 45. It’s all least surprise.
I wonder how many people use REPL of a language of choice as a calculator as I do.
> Lua is an example of such a language, and when a semicolon is necessary is when you have something that could be misconstrued as being a call:

    (function() print("Test1") end)(); -- That semicolon is required
    (function() print("Test2") end)()
Tangential, but I sidestepped this ambiguity in a language I've been designing on the side, via the simple rule that the function being called and the opening parenthesis can't have whitespace between them (e.g. "f()" is fine but "f ()" or "f\n()" is not). Ditto for indexing ("x[y]"). If these characters are encountered after whitespace, the parser considers it the beginning of a new expression.

By sacrificing this (mostly unused, in practice) syntactic flexibility, I ended up not needing any sort of "semicolon insertion" logic - we just parse expressions greedily until they're "done" (i.e. until the upcoming token is not an operator).

That sidestepping only introduces significant whitespace, which may not be what people want in the first place. It can be quite common to align call expressions by the parentheses if they span multiple lines for clarity, and you preventing might not be desireable.
I wouldn't like that, because I always put a single space in front of the parenthesis. Mostly for aesthetic reasons, and to distinguish it from function-like macros. Not intended as a criticism, just a data point.
in the era of LLMs, syntax might matter more than you think.

The c form of `type name;` is ambiguous because it could actually be more than one thing depending on context. Even worse if you include macro sheananigans. The alternate (~rust/zig) is `var/const/mut name type` is unambiguous.

For humans, with rather long memory of what is going on in the codebase, this is ~"not a problem" for experts. But for an LLM, its knowledge is limited to the content that currently exists in your context, and conventions baked in with the training corpus, this matters. Of course it is ALSO a problem for humans if they are first looking at a codebase, and if the types are unusual.

I am an S-exp enjoyer, and more for practical reasons than aesthetic ones—I really like the editor tooling that's possible with S-expressions. So I will absolutely choose a Lisp or a lisp if given the option, even at some level of inconvenience when it comes to the maturity of the language itself. I will always write Hy[0] rather than Python, for example.

[0] https://hylang.org

(I am aware of Combobulate[1] for Emacs folks, of which I'm sadly not one.)

[1] https://GitHub.com/mickeynp/combobulate

Major syntactic structures definitely have an influence on my language choices. Outside of compilation and runtime model, modeling the domain (both data and procedures) changes drastically between paradigms. Syntax is what enables or hamstrings different modeling paradigms.

My two biggest considerations when picking a language are:

- How well does it support value semantics? (Can I pass data around as data and know that it is owned by the declaring scope, or am I chained to references, potential nulls, and mutable handles with lifetimes I must consider? Can I write expression-oriented code?)

- How well does it support linear pipelining for immutable values? (If I want to take advantage of value semantics, there needs to be a way to express a series of computations on a piece of data in-order, with no strange exceptions because one procedure or another is a compiler-magic symbol that can't be mapped, reduced, filtered, etc. In other words, piping operators or Universal Function Call Syntax.)

I lean on value semantics, expression-oriented code, and pipelining to express lots of complex computations in a readable and maintainable manner, and if a language shoots me in the foot there, it's demoralizing.

I don't want to be overly negative, but it seems to me that author considers just different flavours of C.

There is a massive difference between Clojure, Prolog, and Forth.

The whole:

    type name = value—type-focused
    name: type = value—name-focused
    var name type = value—qualifier-focused
Is so much deep into details of how syntax might look like.

If you are choosing between Kotlin and Go, it is for the platform, not the syntax. If you decide between Haskell, Idris, Scheme, you do it with the syntax in mind.

Those syntax examples are literally just general examples, not the only way you have to write them. But to categorize the ones you wrote:

* Clojure is qualifier-focused * Prolog is name-focused * Forth is qualifier-focused (`:` is the qualifier in this case)

I never got why compilers don't have pluggable syntaxes.

I mean, once you decide the "flavor" (e.g.: typed, imperative, with a dash of functional and some oop for good measure), you could have more than one syntax and easily switch to whatever the reader wants.

We had an integration language in a product I worked on that had three flavors (you can check it here: https://docs.oracle.com/cd/E13154_01/bpm/docs65/pdf/OracleBP... , page 254)

The original syntax scared some people, so we had the compiler use the same AST with three different parsers: Original, Java and VB. The editor (which had syntax highlighting and auto completion) would let you see the code however you wanted.

You could even have a setting in the IDE that always showed the code as you wanted.

We even respected some weirdness in the spacing and indentation of comments and code when needed.

For some languages, like rust it may be a stretch, but for most vanilla languages, you could easily re-skin them to look much more like something else, that's comfy for whoever is looking at the code.

> I never got why compilers don't have pluggable syntaxes.

Because then you've created dialects and produced the Curse of Common Lisp all over again.

Syntax matters a heck of a lot, and you want consistency and coherency across codebases of the same language, otherwise you don't have a language at all. So wanting it "pluggable" is in fact the worse possible choice you want.

It's also a naïve view to think that concrete syntax can be trivially swapped out with the abstract syntax remaining. For certain things it can usually work (like declaration syntax in the article) but for most things it cannot.

> I am still perplexed by how people judge a language purely by its declaration syntax, and will decide whether to use the language purely based on whether they like that aspect or not.

Throughout the article, OP seems baffled that people have aesthetic preferences. Well, yes, of course we do; dealing with ugly things is the computer's job.

It also comes across like OP hasn't seen a lot of examples of really interesting language syntax, i.e. things outside, shall we say, the extended Algol family. The discussion seems to accommodate brace-less languages like Python, but not e.g. the Lisp or Forth families.

> and thus just becomes a question of ergonomics or “optimizing for typing” (which is never the bottleneck).

It might not be a bottleneck in terms of time needed. But unpleasant syntax is annoying and breaks flow. Thoughts creep in about how you wish the language looked different and that you didn't have to type these other bits. (Which is why a lot of people feel so strongly about type inference.)

> From what I gather, this sentiment of not understanding why many “modern” languages still use semicolons is either:

OP seems to conflate "semicolon" with "visible, explicit token that separates statements. There's no reason it couldn't be some other punctuation, after all. Describing Python's approach to parsing as "automatic semicolon insertion" is wild to me; the indented-block structure is the point and statements are full lines by default. Semicolons in Python are a way to break that rule (along with parentheses, as noted), which are rarely seen as useful anyway (especially given the multiple assignment syntax).

> To allow for things like Allman braces, Odin allows for extra single newline in many places in its grammar, but only an extra single newline. This is to get around certain ambiguities between declaration a procedure type and a procedure literal

Right; and the point of Python's approach is to not need braces in the first place, and therefore sidestep any considerations of brace style. And when you do that, it turns out that you don't need to think nearly as hard about whether a newline should terminate a statement. It's a package deal.

> Maybe I don’t need to be as cynical and it is a lot simpler than all of that: first exposure bias. It’s the tendency for an individual to develop a preference simply because they became familiar with it first, rather that it be a rational choice from a plethora of options.

> However I do think there are rational reasons people do not like a syntax of a language and thus do not use it. Sometimes that syntax is just too incoherent or inconsistent with the semantics of the language. Sometimes it is just too dense and full or sigils, making it very hard to scan and find the patterns within the code.

For what it's worth, before I ever touched Python I had already used (in no particular order) multiple flavours of BASIC, Turing, probably at least two kinds of assembly, Scheme, C, C++, Java and Perl. To be fair, I had also used HyperTalk and Applescript, so maybe that does explain why I glommed onto Python. But BASIC came first.

In my mind, a mid-line semicolon is exactly the kind of sigil described here, and an end-of-line sigil is simply redundant. Multi-line statements should be the explicitly-marked exception, if only because long statements should be less common than shorter ones.

> Throughout the article, OP seems baffled that people have aesthetic preferences. Well, yes, of course we do

I think Bill is astonished not really that people have aesthetic preference but that anybody's real preferences could be different from his. He supposes that, at most, these are false beliefs they should reject to reveal that their sincere preference is identical to his, the only correct preference.

Hello again. That's not my position in the slightest. The point of the article is to express how people will shallowly and naïvely judge something. It might be naïve conception of "aesthetics" but it's not even a good one.

It has nothing to do with people disagreeing with me, I have seen people dismiss numerous languages (not just my own) based on that declaration syntax. Things like "why does Rust not use `type name = value`? why did they have to change things so much from C++?".

Do you think these people are actually serious programmers or just having shallow and dumb opinions on things they know little to nothing about?

> Do you think these people are actually serious programmers [...] ?

I can't possibly tell? The surface aesthetic impression is only that.

I tried my best to be very clear within this article that I am talking about two specific things: DECLARATION SYNTAX and SEMICOLONS. This does not extend to anything else. In fact I got so frustrated with people like yourself who are wrongly interpreting the article that way and extrapolating too much that I had to write a new article: https://www.gingerbill.org/article/2026/02/21/does-syntax-ma...

"Does Syntax Matter?" And the first one is "Yes."

And all languages can have their declaration syntaxes categorized into one of the three I mention. This is not limited to ALGOLs. And I have come across "really interesting language syntax". I am not talking about that in this article.

----

Ergonomics does matter and it's not just about optimizing for typing either. It's actually all about coherency and consistency, something I go into depth into the following article on syntax.

----

I am not "conflating" a semicolon with statement terminators, I am using that as shorthand as most languages that most people encounter (not all languages, obviously) will use semicolons. Python's approach to parsing is a form of automatic semicolon insertion, even if most people don't think of it that way.

----

And I do not like Python's approach requiring significant whitespace of "blocks" through indentation. I much prefer using something like braces, or an `end` keyword, etc, literally because it prevents the problems that significant whitespace introduces. I am not getting into that argument here; please don't start it.

I personally would prefer to hear more about what is uniquely good about Odin semantically or syntactically than more ad hominem attacks on the intelligence of the critics of the language, which I have seen in multiple recent pieces by this author.
This is the old "syntax does not matter" claim. Syntax is not the most important thing in the world when it comes to programming languages, but it does matter too. I was using perl, then PHP then ruby. There is no comparison here; ruby beats the other two languages hands down. I get to be able to do more, with less syntax and it is easier to read too (provided you write good code; you can write horrible code in any language of course).

Most of the languages that are created anew, end up being a clone of C or C++. Go is one of the few exceptions here; Rust is not an exception. It is basically C++ really, from the syntax - or even worse.

Sadly it is not possible to try to convince people who claim that syntax does not matter, that it does matter. They just keep on repeating that syntax is irrelevant. I don't think syntax it is irrelevant at all. It has to do with efficiency of expression. Clear thoughts. Clear design. It is all inter-connected.

> Rust is not an exception. It is basically C++ really, from the syntax - or even worse.

That's a superficial impression. Yes the resemblance is on purpose, but it doesn't go very deep which suggests you haven't stared at this for more than a few seconds.

I literally had to write an extra article because of the number of people who thought I was saying syntax doesn't matter. It matters a hell of a lot:

https://www.gingerbill.org/article/2026/02/21/does-syntax-ma...

I was trying to be as clear as I possibly could within that article to state I was only focusing on those two specific topics, rather syntax as a whole. How people judge a language based purely on its declaration syntax and nothing else. Where the declaration syntax makes the least difference compared to the rest of the syntax in the language. And still people wrongly interpreted the article.

Hmm... I don't know how serious this wants to be taken

- first example argues that syntax is interchangeable

- but then the author tries to sell me his semis

???

And who even cares in the time of LLMs and auto formatting?

"My hammer has this slight angle and if I hit the nail with just the right motion, it feels really good"

I was trying to be EXTREMELY clear I am talking specifically about DECLARATION syntax only and how for the most part, the concrete syntax for the DECLARTAION syntax is not that important in many languages.

However concrete syntax matters a heck of a lot and cannot be trivially interchangeable.

I had to write a follow-up article to clarify this because of people like yourself wrongly interpreting the article: https://www.gingerbill.org/article/2026/02/21/does-syntax-ma...

This is one of those things that I’m glad remains highly personal and stochastic. Programming languages thrive when people are able and willing to create value with them. People thrive when there are options and they can find a language that sings to them.