Plus, it's not like semicolons are any big deal. If they are in a language, you add them and move on. Dead simple to add, minimal noise, instantly familiar to most C-derivative programmers. The only comminity that regularly complaints about them are hipster (for lack of a better term) javascript programmers.
But your post would still be decently readable if you just made a new paragraph for each sentence ;)
I like Python. I think Python's whitespace-based blocking is interesting. But it is not the most interesting part of the language, and anybody who obsesses over that kind of stuff is just bikeshedding.
Developers always seem to be complaining about having to type this or that, when they should be much more concerned with what they have to read!
Really, I couldn't care less about typing a few extra characters. I can type pretty fast anyway and usually spend more time thinking than I do typing. What I do care about is being able to tell exactly what some code does by glancing at it, without worrying too much about whether someone wrote = instead of ==. Rust seems to be setting itself up for loads of those kinds of errors by trying to make the syntax terse at the expense of making it readable.
I have high hopes for Rust and will reserve judgement until it is stable; from what I've seen it's still in a high state of flux. However for now, I much prefer the KISS approach taken by Go, in spite of a couple of things missing from the language (that will probably get there in the end).
We've written hundreds of thousands of lines of Rust and this has never been an issue. The typechecker will catch any misuses of semicolons.
> What I do care about is being able to tell exactly what some code does by glancing at it, without worrying too much about whether someone wrote = instead of ==.
The typechecker will catch misuses of = versus == as well. So assuming that the code you're looking at passes the typechecker, you don't have to mentally distinguish between = and ==.
> However for now, I much prefer the KISS approach taken by Go, in spite of a couple of things missing from the language (that will probably get there in the end).
They're different languages. Go does not have memory safety without garbage collection, and will never have it while remaining backwards compatible. But that was an explicit design goal of Rust. That is why Rust has the lifetime and unique pointer support, which allows Rust to support safe low-level programming in a way that wasn't possible before.
That the last value in a block is the value of the expression is something that makes a lot of code much more readable, as it frequently obviates the need for additional temporary variables.
I was sceptical until I actually used it. Now I’m converted; though I still also like Python’s pure statement-oriented approach in various ways, I prefer Rust’s model.
> This is like optimising for the least readable code possible. I imagine it's going to be a nightmare in practise.
I have pushed a reasonable amount of code to the rust repo, my own libraries, and some to servo, and it has never been an issue, in fact it has been the opposite (proof: https://www.ohloh.net/accounts/bjz and https://github.com/bjz/).
> What I do care about is being able to tell exactly what some code does by glancing at it, without worrying too much about whether someone wrote = instead of ==.
Rust solves this by having assignment expressions always returning `()` from assignment expressions and not having implicit conversions. The issues with `==` vs `=` completely vanish.
https://github.com/rust-lang/rust/blob/master/src/librustc/m...
Personally I think most other things in Rust (namespaces, constant as_slice() unwrap() etc.) are currently too verbose, although I'd say that also impedes readability.
I do agree with the rest of your first paragraph though.
Or maybe they find terser syntax to be more readable. If verboseness was always more readable, if not necessarily more "writable", than terseness, then no one would have a problem with Java since it has good IDE support, including autocomplete and generation of boilerplate code. But it turns out that it's not just a matter of being lazy typists.
That is two separate levels. When you first glance a page of code the first time in 1 second, you should tell what the structure of the program is. How many blocks (for/while/if) it has. How many functions, how big they. You haven't yet had time to read each individual character. That is one level.
Here variable and ambiguous indentation rules get in the way. If there is non-uniform, non-standard indentation then you have to start reading individual lines in detail. If there is standard indentation then it doesn't even matter about little commas and semicolons, it is a level higher than that.
Then past that it is about individual functions, classes, modules, and what have you. Then it becomes about == vs = or . vs , and so on. If there is ambiguity there it could be harder. Like in Python I added a , at the end of a some variable. So that turns it into a tuple. And it resulted in a strange exception down the line. In C the = vs == is notorious. But there are others. None of this make the task impossible, but just slightly harder. The problem is that if this is done many many time over the course of a lifetime of a piece of code. Maybe it take 10 extra seconds for reader to understand the code, that multiplied by thousands of times will add up.
I'm pretty comfortable writing complex regular expressions, but I don't know many other developers that are and I certainly don't like trying to grok anything longer than about 10-15 characters that I didn't write in the preceding 15 minutes. This is a perfect example of where terseness is fine for simple problems, but it does not scale.
I already mentioned Go because it has a pretty terse syntax, but one that is very carefully optimised for readability. One of the things the designers of Go are careful about is not adding too many operators, keywords, or usage rules to the language, which keeps everything nice and simple.
Rust OTOH seems to have a metric boatload of operators that work in different ways depending on the specific context. That's a recipe for a ton of cognitive load, which isn't helpful for writing code, but reading suffers even more.
I don't yet know enough about Rust to say whether this is as bad as operator overloading in C++. As I said, I will reserve judgement until 1.0 because it's entirely possible things will change drastically before then.
What operators does Rust have that Go does not? I believe Rust has no more operators than Go.
You're right.
Prefer "x = y + z" to "ADD y TO z GIVING x".
Prefer "[[NSThread alloc] initWithTarget:t selector:s object:o]" to "pthread_create(&p, &a, &f)".