4 ms·
> ...by the time x.len() gets executed, arg0 already exists... So, I realize that this is the way that Java does it--and, presumably, one still doesn't get fir
by saurik 3y ago
> ...by the time x.len() gets executed, arg0 already exists...
So, I realize that this is the way that Java does it--and, presumably, one still doesn't get fired for doing whatever Java does ;P--but, would it not actually make more sense for the arguments to be evaluated before the target reference, making the argument order more like Haskell/Erlang (but very sadly not Elixir, which makes it awkwardly incompatible with Erlang and breaks some of the basic stuff like fold/reduce)? Particularly so, given that, as far as I can tell from this example, what makes arg0 have the type that it does is the type of the function that hasn't even been called yet? (As in, the semantic gap I am seeing between what the user probably meant and what the compiler wants to do is that "x" shouldn't really be mutably-borrowed until the call happens, and the call here clearly shouldn't happen until after the arguments are evaluated.) (Note: I do not program in Rust currently; I just have spent a number of decades analyzing languages and at times teaching college language design courses. I might be missing something obvious elsewhere that forces Rust to do this, but that one example, in isolation, at least feels like an unforced error.)
- Georgelemental 3y agoIn Rust, `reciever.some_method(whatever)` is supposed to be relatively thin sugar for `TypeOfReciever::some_method(receiver, whatever)`. So the evaluation order should be the same for those two forms.
- saurik 3y agoSure, but I am saying it would actually have made more sense to put receiver as the last such argument--as one might expect from having used Haskell/Erlang--given the other design decisions clearly in play here, as the target reference isn't really the first argument for any obvious reason other than visual effect and some historical baggage from implementations of some object-oriented languages (including Java) with different constraints.
- estebank 3y agoYou're not wrong, but making self be the last argument would cause confusion for almost everyone coming from other languages, and for Rust it is too late to change that now. You could special case the behavior of the method call syntax to operate that way without breaking backwards compatibility (at the cost of making going back and forth between that syntax and the fully qualified call no longer being a straight forward syntactical transformation).
- comex 3y agoIt would still break backward compatibility. As a trivial example, {println!("first"); 1u32}.wrapping_add({println!("second"); 1}); currently prints "first" before "second", but would switch. But this could theoretically be done at an edition boundary.
- codesnik 3y agointeresting. Can you expand on Elixir incompatibility? How is it different?
- fredrikholm 3y agoElixir does: Enum.map(list, func) This is backwards to how partial application works: def mapper(func), do: Enum.map(func) incrementer = mapper(fn x -> x + 1 end) incrementer(list) It's not the end of the world to not have it this way, but it removes a lot of patterns that are common in other functional languages.
- bPspGiJT8Y 3y agoIt doesn't remove or break anything, it just changes the order of arguments to be compatible with Elixir's (|>) operator and consistent data-first design across the language.
- fredrikholm 3y agoDefinitely, I missed to mention that partial application via currying isn't something you do in Erlang either. If you did however, swapping the arguments would break most partial application patterns you see in languages like Haskell, OCaml, Elm and even JS.
- di4na 3y agoyeah but at this point, currying seems to be a loss in ergonomics in most use case we have found in the wild. I love the idea, I love the principle. But the jury is definitely still out for if the pattern of showing it in syntax and semantics actually is beneficial. And yes, I know nearly all the examples you can come with to show how useful it can be. But the cost of having it seems to more than compensate the benefits.
- fredrikholm 3y agoI'm not necessarily a proponent of currying; merely wanted to expand on what OP was pointing at. The reason I like Erlang is because of the BEAM (+ OTP) combined with idiomatic pattern matching, I don't miss currying in neither language.
- tsimionescu 3y agoDoesn't Rust support having a function as a field of a struct? If it does, then the order of evaluation of a.foo(b) would depend on whether foo is a field or a "free-standing" function of a, which seems horrible. Also, there is a simple elegance in having the order of evaluation match the order the symbols are written that should require a very hight bar to reverse, in my opinion at least.
- MereInterest 3y agoIt does, but Rust also has separate namespaces for methods and variables. That is, a.foo(b) will always be a method foo and never a field foo, because the syntax is that of a method. In order to access a function object, then call it, you would use (a.foo)(b). The parentheses cause the contents to be parsed as a variable expression.