Presumably you mean String/&str? (~str hasn't existed for a long time.)
On the contrary, the lack of the string/string-view distinction is widely considered a flaw in the C++ standard libraries. C++14 introduces std::string_view to correct it. Rust's String/str distinction is just the same as C++14's std::string/std::string_view.
Apart from the Rust's usual rule to invent some abbreviations, but only apply them half the time.
Then "types start with an uppercase letter" except when the language creators break their own rule.
Then the fun "sometimes we use () and sometimes we use [] to do practically the same thing".
Then the various insanities with ::.
Then Generics. How many examples of languages which tried to use <> for Generics do we actually need before people learn the lesson?
I really wished some people took Rust, and wrote a new frontend to get rid of all the pointless inconsistencies and other "C did, so it has to be good"-isms (like_all_this_underscore_stuff or the ridiculous abbreviations), because many ideas of Rust are not only good but brilliant and deserve to be put into languages which don't belong to the purely-academic category.
I really wish Rust to succeed, but can we stop this approach of "3 steps forward and 2 steps backward" to language design?
>
Apart from the Rust's usual rule to invent some abbreviations, but only apply them half the time.
Do you have an example?
> Then "types start with an uppercase letter" except when the language creators break their own rule.
They always start with a capital letter, except for built-in types or FFI bindings to libraries such as libc where the original types used a lowercase letter. This convention is exactly the same as Java.
> Then the fun "sometimes we use () and sometimes we use [] to do practically the same thing".
I've never heard this before. Do you have an example? () is used for function calls, grouping, and tuples, while [] is used for array literals and array indexing.
> Then the various insanities with ::.
The double-colon is very useful so that you can tell the difference between module lookup and field projection/method calling. Early Rust used . for module lookup, and it was confusing to tell at a glance whether a function was being called or a method was being invoked.
> Then Generics. How many examples of languages which tried to use <> for Generics do we actually need before people learn the lesson?
Using square brackets like Scala wouldn't actually help with the ambiguity, because it would be ambiguous with array indexing. The only syntax I've seen that actually solves the ambiguity is D's `!()`, which was deemed too unfamiliar. Angle brackets were chosen because they are familiar and aren't really any worse than the other mainstream options.
> I really wished some people took Rust, and wrote a new frontend to get rid of all the pointless inconsistencies and other "C did, so it has to be good"-isms (like_all_this_underscore_stuff or the ridiculous abbreviations)
The underscore naming convention was actually taken from Python's PEP 8. Rust doesn't really have any more abbreviations than most other languages at this point.
> > Then the fun "sometimes we use () and sometimes we use [] to do practically the same thing".
> I've never heard this before. Do you have an example? () is used for function calls, grouping, and tuples, while [] is used for array literals and array indexing.
Maybe referring to the ability to use either type of brace with macros?
Yeah, you can use any type of delimiter with macros, but I think that's an important feature, especially since macros can expand to declarations. Early versions of Rust required parentheses for all macro invocations, and that looked really ugly for anything that looked like a block. Delimiter interchangeability is a feature from Racket that works really well when it comes to macros and I'd hate to give it up.
Agreed. They allow you to naturally create vectors with the bracket delimiter `vec![1, 2, 3]`, create spawn-like macros with the brace delimiter `spawn { code }`, and in the normal case just use parentheses `println!("testing")`
> () is used for function calls, grouping, and tuples, while [] is used for array literals and array indexing.
Array indexing is a function call, because an array is a function from its index set to the set of the values the array stores, or -- equivalent -- a partial function from integers to the value set.
I don't know, I never liked how all FunctionNs are sort of "unofficial" partial functions (because they may throw), and PartialFunctions are then made a subtype of FunctionN, because they have an extra method where you can ask whether they are defined at given points. Especially since throwing seems to be falling out of favor in Scala, being replaced by Try[] return types.
This is an orthogonal issue. Arrays are clearly partial functions. The Try[.]-vs-exceptions issue is to do with the question whether failures should be reflected in types (the Try[.]-option) or not (exceptions). There are good arguments for and against both options, but both options go well with the understanding that arrays are functions and indexing is function application.
In this example the dichotomy is between String (which is guaranteed by the type system to be valid UTF-8) and OsStr (which might be in an unknown encoding or otherwise not decodable to valid Unicode).
This is exactly when you want a systems language to require explicit conversions, rather than converting things silently and possibly losing or corrupting data.
I understand the difficulty in this space; much of it is caused by forcing the Windows unicode filesystem API onto python as its world-view, rather than sticking to the traditional Unix bytes world-view. I'm unixy, so I'm completely biased, but I think adopting the Windows approach is fundamentally broken.
The problem there is overblown - it's basically all due to the idea that sys.stdin or sys.stdout might get replaced with streams that don't have a binary buffer. The simple solution is just not to do that (and it's pretty easy; instead of replacing with a StringIO, replace it with a wrapped binary buffer). Then the code is quite simple
import sys
import shutil
for filename in sys.argv[1:]:
if filename != '-':
try:
f = open(filename, 'rb')
except IOError as err:
msg = 'cat.py: {}: {}\n'.format(filename, err)
sys.stderr.buffer.write(msg.encode('utf8', 'surrogateescape'))
continue
else:
f = sys.stdin.buffer
with f:
shutil.copyfileobj(f, sys.stdout.buffer)
Python's surrogateescape'd strings aren't the best solution, but I personally believe that treating unicode output streams as binary ones is even worse.
On the contrary, the lack of the string/string-view distinction is widely considered a flaw in the C++ standard libraries. C++14 introduces std::string_view to correct it. Rust's String/str distinction is just the same as C++14's std::string/std::string_view.