Hacker News new | past | comments | ask | show | jobs | submit login

I like Rust, and I'm probably missing something, but do I feel that some things should be easier. At times the language (or standard library, I suppose) feels a bit unwieldy. For example, trying to coerce a string from certain types:

    let path = Path::new(&app_path)
    println!("file name: {}", path.file_name().unwrap().to_str().unwrap());
Hopefully this is just a case of unfamiliarity, but surely something like should be easier?



If you were willing to allow for potential escape characters and acknowledge (to the user) the fact that the path might not have a file name, you could write:

    println!("file name: {:?}", path.file_name());
or just for escape characters, but only if the file name existed:

    if let Some(name) = path.file_name() {
        println!("file name: {:?}", name);
    }
Note that the unwrap() isn't boilerplate, in either case: if you are using `unwrap()` you are implicitly saying that you know for a fact that the file name is present (the first time) and a valid UTF-8 string (the second time), which isn't guaranteed in the general case on all platforms. If you wanted to write this more robustly, and these weren't guaranteed, you would need to explicitly take care of those cases.

I/O has lots of tricky error cases, and Rust usually requires you to acknowledge that. You can avoid dealing with those cases with unwrap(), or you can explicitly handle them. Personally, I much prefer this to being surprised only when the weird error case unexpectedly turns up because I never considered the situation in question, and that's generally how Rust handles things, but it depends on the task. It may make Rust less appropriate for quick scripting tasks, for example, where the domain is well-defined and the script is not likely to be reused (but I find that those scripts have an annoying way of getting reused anyway).


However, rust would be relatively well-suited for a "dirty quick scripting task". You could make a more traditional wrapper for the operations you like to use that assumes these rare edge cases don't happen, and panic otherwise.

This is sort of rust's philosophy; being explicit. Rust has no problem with failing, it just has a problem with failing without you telling it to. If you write a wrapper that implies you are willing to fail on these cases, then you're being explicit by choosing to use these functions instead :)


Yes, it's true. Code like this is going to be more verbose. Often, it's due to Rust being a systems language and exposing low-level details to you, combined with the type system ensuring safety. In this instance, `Path` is actually fairly complex. From the RFC: https://github.com/rust-lang/rfcs/blob/master/text/0474-path...

        > The design of a path abstraction is surprisingly hard. Paths work
        > radically differently on different platforms, so providing a
        > cross-platform abstraction is challenging. On some platforms, paths
        > are not required to be in Unicode, posing ergonomic and semantic
        > difficulties for a Rust API. These difficulties are compounded if one
        > also tries to provide efficient path manipulation that does not, for
        > example, require extraneous copying. And, of course, the API should
        > be easy and pleasant to use.
So, in this case, you have to call `file_name` to get the filename, but that returns an `Option`, since it might not be a file, it could be a directory. The `unwrap` says "crash if it's not a filename." You then have an `OsStr`, which is a string type that handles the kinds of cross-platform issues alluded to in the above paragraph. `to_str` will then attempt to turn it into a `&str`, but because `&str` must be unicode, if the conversion fails, it _also_ returns an Option, which is the last unwrap.

In systems programming, details matter. As such, our stdlib APIs try to expose those details. I expect some people will write higher-level abstractions that hide all this if you don't care as much.

Tradeoffs tradeoffs tradeoffs...


"Often, it's due to Rust being a systems language and exposing low-level details to you, combined with the type system ensuring safety."

I'm not convinced it's being a "systems language" (in the sense I think you mean). The last three languages I've learned to fluency have all, in various ways, been very concerned about errors: Erlang, Haskell, and Go. Yes, they have widely varying opinions about what to do with them, but they all agree that you have to be fairly constantly worried about them. You can't sweep them under the rug; you need a strategy, and you need to deal with the resulting issues head on.

Despite their differences, what I feel like I've learned from them is that historically speaking, the vast majority of popular languages and their communities have been downright cavalier about errors. It's often in all the little details rather than a consistent, stated design goal, but the presence of various nils and nulls, APIs that will happily return empty strings for paths instead of errors, and all kinds of APIs and libraries that seem to be subconsciously written with the belief that returning an error is a failure on the part of the library and will go to what now seem to me to be absurd lengths to somehow keep klunking along in the presence of already-manifested failure. Even for languages that think they're being really good with exceptions, I find that when I go back to them, they end up using the exception support to "permit" themselves to be sloppy and hope the exceptions will pick up the pieces... and they often don't. Not because of some theoretical weakness, but because allowing developers to think they don't have to think about the error cases means precisely that they don't!

People are used to errors not poking them in the face until deploy time. It seems to me there's a strong, broad motion towards developing languages that will in one way or another force you to deal with them at compile time. It's a culture shock for people, but, I'll tell you this, get really good at Rust or any of these other languages and go back to any of those other languages, and you will find your code changes in those other languages to suddenly look a lot more like your Rust does anyhow, which means this putative disadvantage of Rust evaporates anyhow. Once you see how sloppy you were being, it's hard to go back in good conscience.


Great comment. I have run into this problem exactly in inherited codebases at my last couple of jobs:

> libraries that seem to be subconsciously written with the belief that returning an error is a failure on the part of the library and will go to what now seem to me to be absurd lengths to somehow keep klunking along in the presence of already-manifested failure.

It's a big problem with hairy repercussions if this idea is allowed to take root.


> The last three languages I've learned to fluency have all, in various ways, been very concerned about errors

Yeah, maybe I should revise my statement a bit: systems languages, overall, tend to expose more details. I meant this in a broader context than errors. As a simple example, manual memory management exposes more details than GC. There are many languages that care dearly about errors, as you've rightfully pointed out.

I broadly agree with the rest of your post. Error handling is hard and tedious, and programmers don't like doing it. I myself had an embarrassing bug in `rustbook` where I did `let _ =`. I only intended to start off that way! Programming is hard. But using Haskell, Rust, and other languages like this have certainly changed my code in other languages.


> surely something like should be easier?

That would be nice, but as others hinted that wouldn't actually work:

* there are paths without a file_name (`/`) so it returns an Option to make that evident

* to_str attempts to convert the OS-dependent thing to a Rust string. Rust strings are valid unicode, but many filesystems don't have such strict requirements[0]. Again Rust returns an Option to makes that evident although there's a "to_string_lossy" method which will simply replace invalid sequences with U+FFFD if you don't really care

The Rust philosophy is generally to expose these issues upfront and force the developer to consider them (and either handle or explicitly ignore them). It is indubitably less convenient than e.g. Python 3's `PurePath(app_path).name` returning an str, but you'll have had to decide what happens in case of failure.

Paths are really a good example of something which looks simple, should be simple, and is actually anything but simple for historical and technical reasons, especially in a cross-platform context.

[0]

* Unix paths are the most troublesome: they're arbitrary bags of (non-NUL) bytes, they don't have to be in a known encoding, they don't have to be in any encoding.

* Windows paths are not guaranteed to be Unicode either: they're UTF-16 code units aka UCS2 + surrogates, and the surrogates may be unpaired, leading to invalid Unicode.

* OSX paths are guaranteed to be valid Unicode.


Also, OSX applies unicode normalization to the filenames, which can cause some interoperability problems with unix, e.g. you try to copy files forth and back between the systems and end up with two copies of a file, with identical-looking filenames that differ in their unicode normal form.


To add to the other comments, Rust prefers to make error cases explicit. We have memory safety. You can opt out of it, but you have to opt out explicitly. We have exhaustive match. You can use a wildcard, but you need to explicitly do so. We have nullables and Results. You need to explicitly acknowledge the error/null case, or use `unwrap()` to say that you don't mind a panic at this point.

This leads to verbosity at times, but usually its a good verbosity.


I'm sure I'm not the first (or the hundredth) to say this, but `unwrap` has always struck me as a horribly innocuous spelling of "yes, feel free to crash here".

I presume there is (or could be) a standard lint to prevent this getting into production code, but it still feels kind of icky.


We almost changed it to `assert` but that made some people _really_ upset.


Dammit, I kept wondering why it wasn't named unwrap_or_panic/unwrap_or_assert but it could be worse at least unwrap is a less friendly name then scala's get.


`.expect()` is slightly better (you can give it a string that will become a part of the panic message)


Just my 2cs, but the complexity of this code is here to remind you there are a lot of cases you have to take into account :

    let path = Path::new(&app_path);
    if let Some(ostr) = path.file_name() {
       if let Some(str) = ostr.to_str() {
           println!("file name : {}", str);
       } else {
          println!("WARNING : file name is not a valid unicode sequence ! (file name : {:?}", ostr);
       }
    } else {
      println!("Path is either a root directory or a dot entry, it has no filename");
    }


I would say it is familiarity, but in another sense. You can use something like

    path.file_name().and_then(|f| f.to_str()).unwrap()
but that really doesn't buy you much.

Where familiarity comes in I believe is in what that line communicates to me: There might not be a file name (like having '/' as path), and that getting a string slice out of it might fail (the kind of string the platform uses for paths might not be UTF-8 compatible).

Plus, the unwrap()s tell me that whoever wrote the code considered it an assertion failure if one of those is happening.

I read a lot more Rust than I write, and it really helps that the code communicates a lot. And with knowing about OsString/OsStr beforehand, I only had to lookup when file_name() returns None, the rest is rather implicit by convention, or familiarity.


I wish `and_then` were named `flat_map` so badly.


We have `flat_map` for iterators. (`and_then` works for Options, which are basically nullables)

You can convert an Option to a zero-cost iterator and then use `flat_map` though.


I think unwrap calls are mainly meant for quick and dirty stuff and if you find yourself doing it it may be the wrong solution.


That would be:

    let path = Path::new(&app_path);
    println!("file name: {}", path.display());


No, I just want the file name.


The 'String', '~str' dichotomy is really unfortunate.


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.

Scala gets this right.


> Scala gets this right.

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.


I don't think anything's much orthogonal to partiality of functions in languages with strong type systems, unfortunately :)

You wrote that array indexing is "a partial function from integers to the value set". If we're to take the suggestion seriously, then the practicality of it depends on how partial functions are represented in the language. Which itself is certainly not orthogonal to the Try-vs-exceptions issue.


I'm not sure I can agree. I didn't say that the type of the array function is independent of the choice of error propagation mechanism. If you think an array is a partial function from integers to some value domain, say A, then in the exceptional POV the array type is int -> A, and in the Try[.] POV the array type is int -> Try [ A ].

I was talking about the mechanism for array indexing. In both cases, indexing is function application. So the choice of error representation is orthogonal. This is even more evidence that we should not use a different operator for array indexing as Rust does alas.


OK I can agree with that, I think I was taking what you wrote as a wider endorsement of Scala's approach than what you intended.


What about '{}'? It's a nice pair of opening/closing characters.


[flagged]


It's so sad, because I yet to see a single place where they're addressed.


It's not sad, because the examples are never brought up.

It's akin to saying Go is horrible because of all the templates and leaving conversation.


Yes, but getting 8 downvotes in two comments ... why should I care?


Who cares about downvotes? It's just arbitrary points.


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.

[1] http://www.researchgate.net/profile/Bonita_Sharif/publicatio...

Could you improve your post with examples and scientific studies demonstrating your points and post it to http://internals.rust-lang.org/ or http://users.rust-lang.org/ ?


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.
I hope this cleared some things up. :-)


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.


What multiple Rust proponents? Where? What people consider [] superior to <>? How many?

Your text have an air of superiority but your arguments leave a lot to be desired or to be more frank [Citation needed].


    > 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.

  >      impl Index<usize> for MyFunnyArray {
               type Output = u32;
               fn index<'a>(&self, _index: usize) -> &u32 {
                   &self.arr[random::<usize>() % 3]
               }
           }

           impl IndexMut<usize> for MyFunnyArray {
               fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut u32 {
                   self.arr[random::<usize>() % 3] = random();
                   &mut self.arr[random::<usize>() % 3]
               }
           }
Sure, you can write that, but you can also write:

      fn getIndex(&self, index: usize) {
           self.arr[random::<usize>()%self.arr.length]
      }
Rust won't protect you from stupid mistakes. The only question is whether it will allow you to override index syntax.

      myArray[3]
      myArray.getIndex(3) 
I actually prefer this small token of power, as opposed to having to write:

     date1.compareTo(date2) < 0
     date1.equalsTo(date2)
     date1.index(at)
That gets tedious fast.

     > 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.


[flagged]


Wow. That response was... Childish.

I might agree Rust might need improvement in some areas but I don't agree with your sentiment or tone.

Not to mention you are quite puzzlingly wrong on many accounts.


> Not to mention you are quite puzzlingly wrong on many accounts.

I'd love to see an example where this is the case.


The most egregious is [] is used for Thing A/ Thing B.

Another is Python underscore syntax being less readable.


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.


rather than converting things silently and possibly losing or corrupting data

Exactly. Python3 went down the "silently converting" route, and it's not pretty[1]. I would go so far as to call it harmful.

http://lucumr.pocoo.org/2014/5/12/everything-about-unicode/

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.


There is no ~str, but when there was it was largely identical to what String is now.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: