It says a lot about Rust's culture. If they are not only _not_ interested, but actively hostile towards input, why should I bother?
Just look at the replies. Sure, it's possible to hand-wave issues away by setting the standards low enough with "Java did that mistake, too", "we just copied that from Python", "this looked more familiar" ... I think no one disagreed with that.
It's 2015, and having marketing along the lines of "we only made half of C++' mistakes" just doesn't cut it for me anymore.
For other people it might be good enough, but I'm worried that Rust won't get enough traction if the language is not drastically better on average than its incumbents, but just messy in different ways.
First off, Rust != Hacker News. You might have been downvoted by someone unaffiliated by Rust on HN. For example I'm affiliated with Rust community but didn't down-vote you.
Second, let's review your post:
You never supplied examples to your comment of using some abbreviation only half of the time.
Your point about Rust using [], () and {} for functions is wrong, because it only ever uses () for function calls, others can appear in macro.
Your example of using <> vs [] is a subjective choice, that doesn't have any scientific or even majority consensus. To make matters worse, one of Rust's side goal is to somewhat ease migration of C++ programmers to Rust. I actually agree with you on this point, but I realize most people would find this syntax confusing due to habit of writing array literals using brackets.
On the other hand underscore python style that is proven by a study[1] to be a better choice for readability you consider the less usable one.
It is perfectly fine that many design choices in Rust evolved from "let's copy what $random_language did", but mentioning the drawbacks of that kind of approach to language design suddenly requires "scientific studies demonstrating your points"?
Are you kidding me? That's exactly what I meant with "Rust people are actively hostile toward input".
It is even more "I don't want to hear what you say" than it appears on the first look, because we both know that counting all "scientific studies" about language design probably wouldn't require more fingers than a human usually has.
So all we have is some empirical knowledge. You even got some findings for free! Things no one ever said:
- "Having two different ways to call/invoke/execute stuff
made it much simpler to learn the language."
- "Making the casing of types inconsistent really helps
when reading code."
- "Dropping random characters in functions and types made
me feel at home coming from C! I would be terribly
confused if ptr was called pointer, vec vector, fmt
format, iter iterator or rt runtime. The only thing I
don't like is FromStr, it should really by FrmStr
instead! .. I love str's rsplitn btw!"
- "Calling Strings Strings and String views str ... that
makes a lot of sense!"
- "Having used both <> and [] extensively, <> is much
more readable."
- "It was a really great idea to have special syntax for
arrays, so the language designers could overload []
with two completely different meanings."
- "Having both () and [] available is great because you
can write code where foo(x) and foo[x] do different
things!"¹
- "Not having varargs really worked out! Nevermind that
most popular macros exist solely to emulate varargs!"
- "Despite most macros not needing the do-whatever-
you-want syntax, let's require ! for all of them. This
way, macro writers don't have any reason left to try
making their macros behave predictably! Isn't it great
that they can just claim 'you knew that all bets where
off when you wrote that !, so stop complaining!'
instead of fixing their macro?"
- "Fucking up Generics so badly that it requires
different ways of writing them depending on the
context really paid off. It's certainly not an issue
which is hit by every person writing something Generic
for the first time."
- "Inventing unnecessary differences between modules and
objects is great, because it forces you to think
whether you need to use . or :: and breaks use-sites
of that code when migrating from one to the other."
- "Given all the lessons of terribly broken dependency
management systems out there – let's just ignore them
all and put every package in a global namespace ...
what could ever go wrong?"
The language could have been much better if Rust devs wouldn't have been so insecure and defensive, but now it's too late anyway.
So why bother evoking any more excuses in different places? Rust-the-bad-parts is basically unchangeable now.
So what's left? I think it's only honest if Rust devs would be more open about the mistakes they made, and wouldn't require outside expertise to point out the issues.
¹ WAIT ... that's actually what Rust devs said when they defended having both () and [].
but mentioning the drawbacks of that kind of approach
to language design suddenly requires "scientific
studies demonstrating your points"?
Are you kidding me? That's exactly what I meant with
"Rust people are actively hostile toward input".
For what is worth, I only meant it in case of underscore, since underscore syntax has scientific proof it's more readable, if you are aware of a better or another study, please list them. Also I asked for examples.
But here let me look at your complaints:
1) Not sure what you mean in this case, could you elaborate
2) Type casing is inconsitent. All types are CapitalCamelCase. Only special built-in literals are lower case.
3) Fair point, a bit subjective, but fair. I like the terse syntax tbh.
4) Well, String represents mutable and str represents immutable strings, which also double as string views.
5) Fair point, I prefer [] for generics, but again it still falls under subjective.
6/7) I'm unsure what you mean. [] is used for indexing arrays or slicing a piece of it. I think Python had something similar.
If you have foo(x) that's always AFAIK calling function. foo[x] means it's calling index or slice operator on a foo. In either case it's taking a portion of foo.
7) see 6
8) That's actually a fairly good point. I think some kind of optional parameters or varargs were planned, but unsure of current situation
9) Not getting what you mean here? Whenever you add extensibility to language via macros or custom operators, you get weird language DSLs that are incomprehensible. At least putting macro_name! tells you next part is DSL and what's its name is, so you can look it up.
10) Fucking up generics? What?
11) Not sure what your point is? Rust doesn't have objects. It has structs and it has traits. Modules are merely way to organize code. I think you are probably referring to OCaml like modules/objects, but unsure what.
12) Fair point. I'm unsure what alternatives you have in mind? Using URLs?
1) You basically have both () and [], wasting one of the scarcest
resources in syntax (brackets).
Some people might argue that getting a value from an array is totally
different from getting the same value from a function or a map, and
deserves special syntax. If we look at languages which did away with
this made-up difference we see that pretty much no person is missing
it.
Even if you disagree with this reasoning and consider arrays to be
something very special, deserving its own syntax – guess what? Rust
developers introduced the traits Index and IndexMut, so all the great
ideas about some type being special and knowing what happens when you
read [] went straight out of the window.
If we dig deeper and try to understand why they did something so
astoundingly mis-designed, we basically hit an interesting issue:
They overloaded their [] operator to do two completely different
things, depending on whether there is an & in front.
Thing A: return the value at the given index
Thing B: return an address pointing into the indexed data
This of course doesn't translate well into the () syntax, given that
Rust devs are proud that they don't support overloading.
(I guess []'s overloading doesn't count for some reason ... and doing
the little dance with traits doesn't count either.)
Taking a step back, if it would have been considered acceptable to
pick two different names for doing two different things, the whole
issue wouldn't exist, e. g.:
Thing A: values(1)
Thing B: values.at(1)
2) Yes, we agree. Having different sets of rules for a) language
designers and b) language users has shown consistent results:
It never worked out.
3) Yes. I have nothing against terse syntax, it should just be
consistent. (I favor not abbreviating things though, because it's
difficult to be both terse and consistent, considering that things
can be abbreviated in more than one way.)
4) Yes, I know what they do. I just thought it was a nice example of two
related constructs having different casing style and abbreviation
style.
6/7) See 1). The sad thing is that [] can do whatever the developer
wants. All guarantees went out of the window with Index/IndexMut.
9) What I meant was that not every macro wants to define some weird
language DSL. There are plenty of things which only exist as macros
because the language lacks varargs. (vec! for instance.)
If the language ever adds varargs, vec! can't just stop being a macro,
because that would break source compatibility: They would need to keep
the macro version of vec and introduce a new non-macro version of vec,
and hope people migrate from vec! to the "new" vec.
It's a design which makes the common 90% suffer for the benefit of the
most complex 10%. Sometimes it is worth it, but in this case I think it is
not.
10) I had the combination of picking a symbol which is both hard to read and
hard to parse in mind.
Every language that chose <> has weird cruft and therefore it shouldn't
haven been too surprising that Rust is also suffering issues, but in
Rust's case the problems have been shokingly severe. There are loooong
discussions about it if you want to read them. (So it's not just me.)
11) Sorry, I meant structs.
12) URLs are an option. There are also alternatives. I think the essence is
that it's possible to deal with these issues without entering Java's
tld.mycompany.mycontinent.mygroup.myproject.mydogsmiddlename madness.
Re 1, 6 & 7, as we've discussed before: languages that do away with the () vs. [] distinction don't have the same restrictions as Rust, e.g. Scala doesn't have explicit addresses for objects, meaning `&x[i]` in Rust (get the address of the `i`th element) has no first-class equivalent in it. It isn't possible to implement this by just overloading `()` without introducing dramatic new language features.
On this note,
They overloaded their [] operator to do two completely different things,
depending on whether there is an & in front.
is entirely wrong: `x[i]` is literally equivalent to `x.index(i)` or `x.index_mut(i)` depending on mutability, so the `&x[i]` form is the same as `&x.index(i)`, and `&` is a no-op. There's no special magic other than a slightly subtle desugaring.
No Rust dev is proud that there's no overloading... that sentence doesn't even make sense, as every operator can be overloaded, including the () call syntax.
Now I agree that there's often room for improvement in designs, but hammering on a relatively minor syntactic point (especially one that follows many, many other languages) for months seemingly without understanding the current design and the reasons for it is quite tiresome.
1) Sure, pair symbols are a bit rare. But they aren't as rare as you set them to be. Symbols like / | or \ can act as substitute for bracket like syntax.
> If we look at languages which did away with
this made-up difference we see that pretty much no
person is missing it.
Eh, not sure what languages are these and how you think they relate to Rust. Keep in mind Rust goal almost from the start was something that is familiar to a people that worked with Gecko engine. With that in mind, I can't think of a similar family language that did this.
You know what happens when you call Index/IndexMut. To say it isn't so, is outright fallacious.
Also Rust takes the probably best road of allowing limited operator overload, which IMO so far proved better than allowing no operator overload or allowing custom operator overload - which is subject to weird rules and/or leads to heavily overloaded code.
Also [] always does same thing. For given Index value it returns value found at that index. & is not an address. AFAIK address are never allowed unless you drop into unsafe. It's a borrow reference to Output value. Index returns immutable version, while IndexMut takes mutable version and returns mutable output value.
2) No we don't. I think having user and built-in defined types is perfectly ok. In any non-Lispy langugage there are special literals, which can't be handled by user defined ways, unless you allow for some funky grammar.
4) Related yes, same no. In same way i32 and u32 are related but not the same. As I said in previous question having some subset of language be unable to modify is IMHO a good thing.
6/7) They can't. You can tell by mutability of array which one will be called and which one will be returned. You CAN'T EVER change type of mutability of result.
9) Whenever I see macros/operator overload/syntax being given too much freedom, it always ends up with incomprehensible DSL-s that you can't disentangle from regular code.
10) Subjective opinion. And it could be trivially solved with better type aliases.
12) I don't think it's a big problem and a fix to Cargo that adds a special unique identifier should be trivial to implement, although not necessarily forward/backward compatible.
> Nobody claims that <> isn't "familiar". People are claiming
> that <> isn't very good, and they are correct with that.
> Those languages which made <> "familiar" picked <> because
> they added templates/generics/... after the fact and tried
> to bolt them onto an existing language without breaking all
> existing code.
What people are claiming this? Is there some argument
<Type, <Type<Type>>>
is much better than
[Type, [Type[Type]]]
in monospaced fonts? I agree I prefer it, but I know it comes down to subjectivity and familiarity. Not the most compelling reasons.
> As you might see, they are called i32 and u32, not i32 and UnsignedInt4Bytes.
Correct, because they are both built in literals. String isn't a built in literal. You can't have:
u32::new()
>Not sure what you suddenly try so say with "you can't
>modify this", "you can't mutate that".
>As shown in 1) [] can do whatever the developer implements.
>Sure, the usual language rules apply, I think nobody
>disagreed on that.
No matter how many time you call Index on your array it stays the same. What kind of trippy Index you want to implement is still there, only with uglier syntax.
> Yes, that's exactly the concern I'm raising here, because that's what Rust is encouraging.
It's not. All macro invocations are fenced in by macro calls. All syntax extensions are followed by extension calls. Could macros/syntax extensions do horrible things? Sure. So can regular code.
Not only are all your points about Rust incorrect, but numerous people in both this thread and past threads have repeatedly told you why they your points are incorrect and yet you persist in believing that they have been unaddressed. At this point it's safe to say that observers have caught on to your campaign of indefatigable misinformation and find it easier to downvote your comments than to waste any more of their time making arguments that you will proceed to blithely ignore.
In fact, it says a lot about Rust's culture that people were willing to engage you constructively in the first place despite your acerbic and technically-naive ramblings.
Just look at the replies. Sure, it's possible to hand-wave issues away by setting the standards low enough with "Java did that mistake, too", "we just copied that from Python", "this looked more familiar" ... I think no one disagreed with that.
It's 2015, and having marketing along the lines of "we only made half of C++' mistakes" just doesn't cut it for me anymore.
For other people it might be good enough, but I'm worried that Rust won't get enough traction if the language is not drastically better on average than its incumbents, but just messy in different ways.