5 ms·
No Semicolons Needed
- gcanyon 7mo agoCan anyone give a good reason why supporting syntax like: y = 2 * x - 3 is worth it?
- whateveracct 7mo agoin Haskell, supporting that is how you get neat composition such as applicative style formatted like this: f <$> x <*> y <*> z
- szmarczak 7mo agoIt's not. Your eyes can deceive you by guessing the correct indentation. Indentation should never be used for grammar separation. Explicit characters such as } ] ) are clearer and unambiguous.
- bmandale 7mo agoClearer for the computer, but not for the human. Many errors, some severe, have been caused by a human only looking at the indentation and not realizing the braces don't match.
- szmarczak 7mo ago> human only looking at the indentation and not realizing the braces don't match. If it ever gets to that point, a refactor is obligatory. Don't give the human tools to make easy mistakes. Any grammar can be abused, so blame the human for not writing clean code.
- TheOtherHobbes 7mo agoJavascript's delimeter soup ((){([]{})}); can become near impossible to parse barebrained, especially when mixed with indents and semicolons. Semicolons are just noise. They're absolutely redundant. Some brackets are necessary, but whitespace/indent languages make it clear there's a lot of redundancy there too. The goal is to minimise errors and cognitive load. The fewer characters the better.
- szmarczak 7mo ago> whitespace/indent languages make it clear there's a lot of redundancy there too. The only purpose for whitespace indentation is to make the code easier on the eyes. A space shouldn't have an impact in terms of execution, that would be too hazardous. It's too easy to randomly insert a space rather than a character.
- xigoi 7mo ago> It's too easy to randomly insert a space rather than a character. What are you doing with your code? I never find myself just randomly inserting characters.
- szmarczak 7mo ago> I never find myself just randomly inserting characters. Hasn't it ever occured to you trying to insert a space at your mouse but your cursor wasn't there? People sometimes forget to click (or think the cursor is already there), myself included. Characters are easier to spot because they are not invisible and random letters cause compile errors. If it has never occurred to you, then good for you. However I do not see what the benefit of not using closing brackets would be.
- xigoi 7mo agoI don’t use the mouse when editing code, so this particular mistake does not happen to me. > I do not see what the benefit of not using closing brackets would be. Less visual noise. And the ability to use braces for other syntax.
- szmarczak 7mo ago> I don’t use the mouse when editing code, so this particular mistake does not happen to me. Fair point. > Less visual noise. It doesn't solve this problem of your eyes guessing the correct indentation, especially when using two spaces (I hate two spaces even with braces). You could set up your IDE so it highlights the block and prints a hint at the end what block is ending, however you lose this once you open a plain text editor. The point of using braces for this is that you can count them. Also, if you were to print the code without braces on a paper, it would be a hard time reading, since the paper is much smaller than a 27" monitor. > And the ability to use braces for other syntax. There's other ways. For example, {} in Swift can be also used for ResultBuilder. And if you need the braces without knowing the type upfront, you can prefix it e.g. ${}.
- Blikkentrekker 7mo agoThat's just because most languages go by braces and have optional intendation that is just ignored by the compiler. I'd reckon that in a language where stuff is done by indentation but optional braces exist that are just ignored so many errors would also have been caused by braces being misplaced by the programmer to queue other programmers who thought some scope happened as a consequence but the compiler disagreed due to the indentation, which by the way was caused by tabs and spaces being mixed in the code and it not properly showing up for another programmer with tab with set differently.
- bmandale 7mo ago> tabs and spaces being mixed in the code Python banned this in python3. Problem solved.
- szmarczak 7mo ago> and not realizing the braces don't match. Make your IDE highlight the current section or display a hint showing starting bracket. For example, C++ devs do #endif // #if ... Too many brackets? Refactor - problem solved.
- silon42 7mo agoIMO, that is the only acceptable situation where semicolons can be removed from the language... if you need to add indentation rules, you've failed.
- marcosdumay 7mo agoBy "is worth it" you mean it's worth the work? Because it's very little extra work. If you want to know if it's a good syntax, AFAIK it's the only way to do a semicolon-less language that doesn't break all the time.
- justsomehnguy 7mo agoMostly eye-candy, especially for some long one-liners. In PowerShell you can do that by explicitly instructing what the next line is actually a continuation of the previous one: $y = 2 * $x ` - 3
- zephen 7mo agoObviously, that's a really short expression. So, the question is, if you have a long expression, should you have to worry too much about either adding parentheses, or making sure that your line break occurs inside a pair of parentheses. It boils down to preference, but a language feature that supports whatever preference you have might be nice. priority = "URGENT" if hours < 2 else "HIGH" if hours < 24 else "MEDIUM" if hours < 72 else "LOW"
- duped 7mo agoif object.method() || other_object.field.condition() || (foo > bar && baz < qux)
- marcosdumay 7mo agoLooks at 11 languages, ignores Haskell or anything really different...
- librasteve 7mo agoor Raku
- jasperry 7mo agoThose are functional languages that generally don't use statements, so it makes sense to leave them out of a discussion about statement separators. If you think more people should use functional languages and so avoid the semicolon problem altogether, you could argue that.
- marcosdumay 7mo agoYet, the author ends with a half-backed clone of the Haskell syntax.
- Blikkentrekker 7mo agoFunctional hardly matters Haskell has plenty of indentation which is by the way interchangeable with `{ ... }`, one can use both at one's own pleasure and it's needed for many things. Also, famously `do { x ; y ; z }` is just syntactic sugar for `x >> y >> z` in Haskell where `>>` is a normal pure operator.
- deleted 7mo ago[deleted]
- jfengel 7mo agoOnce I learned Haskell, everything else looks pretty much identical. Java, C, C++, Smalltalk... At least Lisp looks a little bit different.
- Animats 7mo agoClassic mistakes in language design that have to be fixed later. - "We don't need any attributes", like "const" or "mut". This eventually gets retrofitted, as it was to C, but by then there is too much code without attributes in use. Defaulting to the less restrictive option gives trouble for decades. - "We don't need a Boolean type". Just use integers. This tends to give trouble if the language has either implicit conversion or type inference. Also, people write "|" instead of "||", and it almost works. C and Python both retrofitted "bool". When the retrofit comes, you find that programs have "True", "true", and "TRUE", all user-defined. Then there's the whole area around Null, Nil, nil, and Option. Does NULL == NULL? It doesn't in SQL.
- tadfisher 7mo agoThat's what's nice about coarse-grained feature options like Rust's editions or Haskell's "languages", you can opt in to better default behavior and retain compatibility with libraries coded to older standards. The "null vs null" problem is commonly described as a problem with the concept of "null" or optional values; I think of it as a problem with how the language represents "references", whether via pointers or some opaque higher-level concept. Hoare's billion-dollar mistake was disallowing references which are guaranteed to be non-null; i.e. ones that refer to a value which exists.
- dfawcus 7mo agoAttribute (qualifier), or storage class? https://www.airs.com/blog/archives/428 https://www.airs.com/blog/archives/428 The use of 'const' in C is very much a mixed blessing; I certainly have experience of the 'const poisoning' issue. Possibly it would have been better as a storage class. For bool, yes it was a useful addition. Especially for the cases where old code would have something like: #define FLAG_A 1u #define FLAG_B 2u int has_flag_B (something *some) { return some->field & FLAG_B; } and that was then combined with logic expecting 'true' to be 1; which could sneak in over time.
- Ferret7446 7mo ago> Does NULL == NULL? It doesn't in SQL. That's because SQL null is semantically different. Most nulls are a concrete value (null pointer). SQL null is the relational null ("not known"). It's closer to NaN (but still different)
- sheept 7mo ago> I would love to see a language try to implement a rule where only an indented line is considered part of the previous expression. Elm does this (so maybe Haskell too). For example x = "hello " ++ "world" y = "hello " ++ "world" -- problem
- em-bee 7mo agohow to handle expressions that need more than two lines?
- sheept 7mo agoBecause formatters are increasingly popular, I think it'd be interesting to see a language that refuses to compile if the code is improperly formatted, and ships with a more tolerant formatter whose behavior can change from version to version. This way, the language can worry less about backwards compatibility or syntax edge cases, at the cost of taking away flexibility from its users.
- librasteve 7mo agoThis article makes a strong case for every language to use ‘;’ as a statement separator.
- jasperry 7mo agoIndeed it does, by showing how many different and confusing types of parsing rules are used in languages that don't have statement terminators. Needing a parser clever enough to interpret essentially a 2-d code format seems like unnecessary complexity to me, because at its core a programming language is supposed to be a formal, unambiguous notation. Not that I'm against readability; I think having an unambiguous terminating mark makes it easier for humans to read as well. If you want to make a compiler smart enough to help by reading the indentation, that's fine, but don't require it as part of the notation. Non-statement-based (functional) languages can be excepted, but I still think those are harder to read than statement-based languages.
- hajile 7mo agoLisps aren’t necessarily functional, but don’t need semicolons either.
- II2II 7mo agoThe syntax of languages like Lisp and Forth are so fundamentally different that they don't need an explicit statement separator. You don't have to think about many other things either, or I should say you don't have to think about them in the same way. Consider how much simpler the order of operations is in those languages.
- wvenable 7mo agoLisp has explicit "statement" terminators (just aren't semicolons)
- hajile 7mo agoAll the lisps I know of have only expressions (no statements).
- bmandale 7mo ago> I would love to see a language try to implement a rule where only an indented line is considered part of the previous expression. After python, it seems like every language decided that making parsing depend on indents was a bad idea. A shame, because humans pretty much only go by indents. An example I've frequently run into is where I forget a closing curly brace. The error is reported at the end of the file, and gives me no advice on where to go looking for the typo. The location should be obvious, as it's at exactly the point where the indentation stops matching the braces. But the parser doesn't look at indents at all, so it can't tell me that.
- vips7L 7mo agoScala 3 decided to go with indents.
- elfly 7mo agoYou are not telling the whole story. You can mix indentation and braces to delimit blocks. It's insane.
- macintux 7mo agoAs a casual observer who has written perhaps a dozen lines of Scala in his life, I feel like Scala approaches any “pick one” decision with “why not both?”. Functional or OO? Yes.
- Blikkentrekker 7mo agoI like how Haskell does it. One can do both but not mix, as in either indent or use `{ ... }`.
- vips7L 7mo agoI personally think this put the final nail in the coffin.
- Pay08 7mo agoKind of. It supports an end operator as well, and imo everyone should be using it. I actually really like the `end name` approach as opposed to the Lua-style plain ends.
- IshKebab 7mo ago> how does Gleam determine that the expression continues on the second line? The fact that it isn't obvious means the syntax is bad. Stuff this basic shouldn't be ambiguous. > Go's lexer inserts a semicolon after the following tokens if they appear just before a newline ... [non-trivial list] ... Simple enough! Again I beg to differ. Fundamentally it's just really difficult to make a rule that is actually simple, and lets you write code that you'd expect to work. I think the author's indentation idea is fairly reasonable, though I think indentation sensitivity is pretty error-prone.
- kayson 7mo agoAre we really saving that much by not having semicolons? IDEs could probably autocomplete this with high success, and it removes ambiguity from weird edge cases. On the other hand, I've not once had to think about where go is putting semicolons...
- gethly 7mo ago[flagged]
- lightingthedark 7mo agoIt's interesting seeing all of the different ways language designers have approached this problem. I have to say that my takeaway is that this seems like a pretty strong argument for explicit end of statements. There is enough complexity inherent in the code, adding more in order to avoid typing a semicolon doesn't seem like a worthwhile tradeoff. I'm definitely biased by my preferences though, which are that I can always autoformat the code. This leads to a preference for explicit symbols elsewhere, for example I prefer curly brace languages to indentation based languages, for the same reason of being able to fully delegate formatting to the computer. I want to focus on the meaning of the code, not on line wrapping or indentation (but poorly formatted code does hinder understanding the meaning). Because code is still read more than it is written it just doesn't seem correct to introduce ambiguity like this. Would love to hear from someone who does think this is worthwhile, why do you hate semicolons?
- duped 7mo agoStart from the perspective of the user seeing effectively: > error: expected the character ';' at this exact location The user wonders, "if the parser is smart enough to tell me this, why do I need to add it at all?" The answer to that question "it's annoying to write the code to handle this correctly" is thoroughly lazy and boring. "My parser generator requires the grammar to be LR(1)" is even lazier. Human language doesn't fit into restrictive definitions of syntax, why should language for machines? > Because code is still read more than it is written it just doesn't seem correct to introduce ambiguity like this. That's why meaningful whitespace is better than semicolons. It forces you to write the ambiguous cases as readable code.
- estebank 7mo agoI used to hate semicolons. Then I started working in parser recovery for rustc. I now love semicolons. Removing redundancy from syntax should be a non-goal, an anti-goal even. The more redundancy there is, the higher the likelihood of making a mistake while writing, but the higher the ability for humans and machines to understand the developer's intent unambiguously. Having "flagposts" in the code lets people skim code ("I'm only looking at every pub fn") and the parser have a fighting chance of recovering ("found a parse error inside of a function def, consume everything until the first unmatched } which would correspond to the fn body start and mark the whole body as having failed parsing, let the rest of the compiler run"). Semicolons allow for that kind of recovery. And the same logic that you would use for automatic semicolon insertion can be used to tell the user where they forgot a semicolon. That way you get the ergonomics of writting code in a slightly less principled way while still being able to read principled code after you're done.
- stack_framer 7mo agoI never actually type semicolons in my JavaScript / TypeScript. In work projects, my IDE adds them for me thanks to the linter. In personal projects, I just leave them out (I don't use a linter, so my IDE does not add them), and I've never had a problem. Not even once. Semicolon FUD is for the birds.
- jfengel 7mo agoI occasionally run into problems with JS weird parsing rules. My favorite is: return x Which does not return. It returns undefined. Typescript helps a lot with that. A linter will probably flag it as well. Still, JS went way out of its way to accept just about anything, whether it makes sense or not.
- galaxyLogic 7mo agoThat is what I lament too. So I've started to use the comma-operator to make sure my return statements don't care about line-breaks. I often write: return 0, x; I find this a mildly amusing discovery for myself because it took me a long time to figure out a useful use for the comma-operator.
- ProllyInfamous 7mo agoCormack McCarthy proved to me that when structured correctly conversive language does not need any quotation marks (while remaining entirely comprehensible). But " " still exist (for us/mere mortals) because few can write so clearly. I know nothing about coding (beyond changing others' variables to fit my installation), but would imagine this parallels many coding environments (e.g. yours).
- Joker_vD 7mo agoPerhaps having unary minus (and especially unary plus) is just a bad idea in general; just mandate "0 - expr". To make negative constants work properly, you still have to either special case literals "256", "65536", etc. and ideally check whether they got negated or not, or introduce a special syntax just for them, like "~1" of ML for negative one, or "-1" (which you are not allowed to break with whitespace) of some other language I've forgotten the name of. While we're at it, probably the unary bitwise complement could go as well? Obviously, "^(0-1)" would suck to write but since 99% of the time bitwise "not" used in expressions/statements like "expr &~ mask..." or "var &= ~mask", I feel like simply having binary "and-not" operator that looks like "&~" or "&^" (Golang) is just better. Also, a small prize (a "thank you!" from a stranger on the Internet i.e. me) to someone who can propose a good syntax for compound assignment with reversed subtraction: x ^= 0-1 # in-place bitwise complement x ^= true # in-place logical negation x ?= 0 # in-place integer negation???
- teo_zero 7mo ago+1 on the convenience of a "mask" operator that perform the and-not. It's an operation that's used more often than others which do have the privilege of having their own symbol, like xor.
- xigoi 7mo ago> Also, a small prize (a "thank you!" from a stranger on the Internet i.e. me) to someone who can propose a good syntax for compound assignment with reversed subtraction: I would do away with operator-assign operators and instead introduce a general syntax for updating a variable that can be used with any expression. x = _ + 1 # increment x x = 0 - _ # negate x output = sanitizeHtml(_) index = (_ + 1) % len(arr)
- Joker_vD 7mo agoThank you! Having a syntactical construct to reference the value of the lhs of the assignment's operator in its rhs without recalculating it is a pretty nifty trick: it works because there is only one lvalue on the lhs of an assignment, so there is no ambiguity to what it refers to. And it could even be extended to work with multivalued assignments, although less neatly. Amazing! Thank you again!
- teo_zero 7mo agoIt's very subjective, and I don't want to say that semicolons are good or bad, indentation is good or bad, etc. But I think a language should decide whether white space is significant or not. If it's not, don't add exceptions! Operators changing meaning when surrounded by spaces in otherwise context-free languages are an abomination!
- xigoi 7mo ago> Operators changing meaning when surrounded by spaces in otherwise context-free languages are an abomination! How does that make the language not context-free?
- i_don_t_know 7mo agoThe Haskell language report precisely defines how layout determines structure: https://www.haskell.org/onlinereport/haskell2010/haskellch10.html#x17-17800010.3 https://www.haskell.org/onlinereport/haskell2010/haskellch10... Any language that uses layout to determine structure should have a similarly precise definition.
- Mawr 7mo ago> The first thing that I dislike about this is that it encourages thinking of semicolons being inserted instead of statements being terminated It might, but that's irrelevant since you never think about semicolons in Go at all. > I like these formatting choices, but I'd prefer if the "wrong style" was still syntactically valid and a formatter would be able to fix it. Your preference likely comes from some idealistic idea of "cleaniness" or similar, which isn't very convincing. Forcing everyone to use the same style is a huge win, to the point that it's a mistake to do anything else, as seen in the description of what Odin does. Completely wrong priorities there and refusal to learn from the past. "Code formatting" isn't some inherent property of code that we must preserve at all costs, just a consequence of some unfortunate syntactical choices. There's no inherent reason why a language needs to allow you freedom to choose how to "format" your code. And there are in fact a lot of reasons why it shouldn't.