y = 2 * x
- 3
is worth it?such as applicative style formatted like this:
f
<$> x
<*> y
<*> zIf 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.
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.
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.
What are you doing with your code? 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.
> 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.
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. ${}.
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.
Python banned this in python3. Problem solved.
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.
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.
In PowerShell you can do that by explicitly instructing what the next line is actually a continuation of the previous one:
$y = 2 * $x `
- 3So, 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" if object.method()
|| other_object.field.condition()
|| (foo > bar && baz < qux)Also, famously `do { x ; y ; z }` is just syntactic sugar for `x >> y >> z` in Haskell where `>>` is a normal pure operator.
- "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.
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.
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.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)
Elm does this (so maybe Haskell too). For example
x = "hello "
++ "world"
y = "hello "
++ "world" -- problemNon-statement-based (functional) languages can be excepted, but I still think those are harder to read than statement-based languages.
One day https://github.com/mathialo/bython one day!
Alternatively, I've several times used 'pass' as block terminator for my personal code.
Sounds like a tool issue. My editor (Neovim with a few plugins) can handle copying/pasting with indentation just fine.
Get the ones that do help you! Problem solved, enjoy your clean reading experience!
https://marketplace.visualstudio.com/items?itemName=hyesun.p...
(Sublime has the same, so does vim see comment above, so do many real IDEs)
Or do you mean something different?
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.
You can mix indentation and braces to delimit blocks.
It's insane.
Functional or OO? Yes.
tabs vs spaces is very painful still when copying code that is in a different format. it's not just tabs and spaces, but the width of the tabs and the spaces. Even with VSCode extensions and sublime text extensions I've struggled a lot recently with this.
I commented on a sibling thread just now, but it is still very easy in python to mess up one level of indentation. When I caught bugs of that sort, it was introduced either when copy pasting, when trying to make a linter happy and doing cosmetic cleanup, or when moving code around levels of indentation, like introducing a try/except. I had one recently where if I recall correctly I moved a continue statement under or out of a try/except when messing around with the try/except logic. it was perfectly valid, and didn't stand out much visually, pydnatic and other checkers didn't catch it either. It could have happened with a '}' but it's easier to mess up a level of indentation than it is to put the '}' at the wrong level. a cosmetic fix results in a logic bug because of indentations in python. with curly's, a misplacement of that sort can't happen because of indentation or cosmetic/readability fixes.
what the curly approach asserts is a separation of readability and logic syntax.
The interpreter/compiler should understand your code first and foremost, indenting code should be done, and should be enforced, but automatically by the compiler/interpreter. Python could have used curly braces and semi-colons, and force-indented your code every time it ran it to make it more readable for humans.
That's somewhat a quality of service issue though. Compilers should look at where the braces go out of kilter vs indentation and suggest the possible unmatched opening brace.
There are many other examples. It exists to give people freedom. Also, while humans only go by intendation it's very hand for text editing and manipulation without requiring special per-language support to move the cursor say to the nearest closing brace and so forth.
There are, of course, other ways to handle this. For instance, "else if <cond>:" could've been made legal à la Golang:
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .space is for spacing, tabs are for tabulation, they are not in any human language I know of used as terminators of statements. You know what is the equivalent of an indent or a semicolon in english? a period. <-
We have paragraph breaks just like this to delimit blocks of english statements.
A semi-colon is used to indicate part of a sentence is done, yet there is still related continuation of the statement that is yet to be finished. Periods are confusing because they're used in decimal points and other language syntax, so a semi-colon seems like a good fit.
If I had my pick, I would use a colon to indicate the end of a statement, and a double colon '::' to indicate the end of a block.
func main(): int i - 0: do: i=i+1: print(i): while(i<10):: ::
another downside of indentation is it's award to do one-liners with such languages, as with python.
There is a lot of subjectivity with syntax, but python code for example with indents is not easy for humans to read, or for syntax validators to validate. it is very easy for example to intend a statement inside a for loop or an if/else block in python (nor not-intend it), and when pasting around code you accidentally indent one level off without meaning to. if you know to look for it, you'll catch it, but it's very easy to miss, since the mis-indented statement is valid and sensible on its own, nothing will flag it as unusual.
In my opinion, while the spirit behind indentation is excellent, the right execution is in the style of 'go fmt' with Go, where indenting your code for you after it has been properly parsed by the compiler/interpreter is the norm.
I would even say the first thing a compiler as well as interpreter do should be to auto-indent, and line-wrap your code. that should be part of the language standard. If the compiler can't indent your code without messing up logic or without making it unreadable, then either your code or the language design has flaw.
Have you never seen a nested table of contents?
1. Introduction
2. Fruit
2.1 Apples
2.1.1 Red apples
2.1.2 Green apples
2.2 Oranges
3. Vegetables
3.1 Carrots Arabateciae
Arabaticopoda
Arabaticoquasicae
Bidoroca
Pseudobidoroca
Superbidoroca
Superduperbidoroca
and the hierarchy is still clear.Indentation is fragile.
In that list you can naturally guess what that ordering is, but if the items were not so interrelated it can be confusing. if the top level item is 'Ham' and the indented item under it is 'sandwich' are you wrapping the same phrase 'Ham Sandwich' , because indentation (even in python) is used when wrapping lines, or is sandwich under ham as one of the things done with ham. it is thus error-prone and more confusing, clear and specific punctuation alongside indentation makes it easier to read.
This wouldn't look right:
Introduction
Fruit
Apples
Red apples
Green apples
I'm sure you can work it out, but it doesn't feel natural, or ideal. (i can't get hn to format it without making it all one line so i used double new line).A linter can point out errors based on indentation, and they frequently do. There's no need for the language to do it and then band-aid additional fixes for problems caused by significant white space.
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.
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?
> 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.
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.
Semicolon FUD is for the birds.
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.
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.
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).
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???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)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!
How does that make the language not context-free?
Any language that uses layout to determine structure should have a similarly precise definition.
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.