Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upArity-based parameter overloading #153
Conversation
apoelstra
reviewed
Jul 3, 2014
| ``` | ||
|
|
||
| So `to_str_radix(&self, radix: uint) -> String` can be now written as `to_str(&self, radix: uint) -> String` while | ||
| `to_str(&self) -> String` still exists. This will let Rust get rid of the sheer multitude of functions that only |
This comment has been minimized.
This comment has been minimized.
apoelstra
Jul 3, 2014
Contributor
It's really unclear how this would work, since ToStr and ToStrRadix are completely separate traits, and most of the things that implement ToStr have no concept of "radix".
I also don't see any subjective benefit to giving these functions the same name. Right now if you look in the documentation for numeric types you will see implementations of the ToStrRadix type (as well as ToStr for any which do this "default base 10" thing, though a quick glance through did not find any examples). You can click on the ToStrRadix trait to get documentation for what to_str_radix does and on ToStr to get documentation for .what to_str does. I don't see how you can sensibly merge this documentation, so your function merging is only skin deep, so to speak.
This comment has been minimized.
This comment has been minimized.
iopq
Jul 3, 2014
Author
Contributor
Just because they share the same name doesn't mean they have the same documentation. Ditto for traits. Those are two separate functions.
apoelstra
reviewed
Jul 3, 2014
| ```rust | ||
| fn split<Sep: CharEq>(&self, sep: Sep) -> CharSplits<'a, Sep> | ||
| fn split<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitsN<'a, Sep> | ||
| ``` |
This comment has been minimized.
This comment has been minimized.
apoelstra
Jul 3, 2014
Contributor
Actually these functions can already be eliminated by using take() on CharSplits. In fact the implementation of CharSplitsN is basically a copy of the implementation of take() plus a copy of the implementation rev() (for rsplit and rsplitn). So it's possible to eliminate this duplication today without any new language features. Just drop splitn, rsplit and rsplitn because they're redundant.
This comment has been minimized.
This comment has been minimized.
bstrie
Jul 3, 2014
Contributor
@apoelstra, that sounds like a good plan regardless of this RFC. File a bug so that it isn't forgotten. :)
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
apoelstra
Jul 3, 2014
Contributor
I should probably mention here that in the referenced bug report, @alexcrichton explained that I was wrong on this point: split().take() and splitn() in fact have different semantics.
This comment has been minimized.
This comment has been minimized.
arcto
commented
Jul 3, 2014
|
I don't see why these two functions could not co-exist:
|
This comment has been minimized.
This comment has been minimized.
wolenber
commented
Jul 3, 2014
|
I've always thought a good way of handling optional arguments would be a special case for the Option type. If I have a function: fn example(a: int, b: int, c: Option<int>) -> int { }I should be able to call it in two ways. example(5, 10); // Calls example with 5, 10, None
example(5, 10, 15); // Calls example with 5, 10, Some(15)Again this works on the arity of the call-site, but allows a single function signature to handle the situation. |
This comment has been minimized.
This comment has been minimized.
|
@wolenber that would need a check at runtime in the function to check if the third parameter is passed. One of the advantages of overloading is that there is no runtime cost. |
This comment has been minimized.
This comment has been minimized.
|
Functions aren't just items, they are also values. Suppose you wrote:
Presumably that would be an error. How would you disambiguate it? |
This comment has been minimized.
This comment has been minimized.
arcto
commented
Jul 3, 2014
|
This comment has been minimized.
This comment has been minimized.
|
That's ambiguous: let int = 10;
let my_fn = foo(int); |
This comment has been minimized.
This comment has been minimized.
|
I've never heard of a language that overloads based on arity. Can you cite a precedent, or is this entirely original? |
This comment has been minimized.
This comment has been minimized.
|
@glaebhoerl, do there exist no other languages with both overloading and first-class functions? |
This comment has been minimized.
This comment has been minimized.
utkarshkukreti
commented
Jul 3, 2014
|
@bstrie Clojure? |
This comment has been minimized.
This comment has been minimized.
arcto
commented
Jul 3, 2014
|
@sfackler: Wow, I didn't know you could redefine But it seems that in this case the local definition shadows the other? |
This comment has been minimized.
This comment has been minimized.
wolenber
commented
Jul 3, 2014
|
@aochagavia I admit it would add a runtime cost, but it's a purely optional feature that doesn't need to be used. In inner loops where it matters, it could easily be avoided. Outside of them, it's some nice syntax sugar. |
This comment has been minimized.
This comment has been minimized.
|
@utkarshkukreti, in what way does Clojure handle the case that @glaebhoerl presents above? |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
@bstrie C++, and there it would be disambiguated by writing (IIRC) |
This comment has been minimized.
This comment has been minimized.
arcto
commented
Jul 3, 2014
|
@bstrie: doesn't that disambiguate the example? |
This comment has been minimized.
This comment has been minimized.
|
@arcto, er, nevermind, I'm dumb. :) Those are indeed two different namespaces. |
apoelstra
referenced this pull request
Jul 3, 2014
Closed
Redundant methods in `core::str::StrSlice` #15379
This comment has been minimized.
This comment has been minimized.
pczarn
commented
Jul 3, 2014
|
Let's disambiguate it... with type inference? let my_fn = foo;
my_fn(1, 2); // infer arity from here
// alternatively
let my_fn: fn(int, int) -> int = foo;
// and with partial type inference
let my_fn: fn(_, _) -> _ = foo;Ambiguous usage would cause: |
huonw
reviewed
Jul 3, 2014
| Nobody will be confused by which method is being called when they differ by how many arguments they have. | ||
|
|
||
| ```rust | ||
| fn concat(&self) -> String { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Thanks for submitting the RFC. Whilst overloading (of some kind) may be something we add to Rust in the future, it is something that has been discussed before and there is broad agreement that it wouldn't be added before 1.0. Therefore, this RFC is extremely likely to be closed as postponed. |
This comment has been minimized.
This comment has been minimized.
|
If you postpone it until after 1.0, you can't redo your standard library to have overloading, so there's no point. |
This comment has been minimized.
This comment has been minimized.
|
1.0 is not stabilising all libraries, just the language itself. (We have fine grained library stabilisation via stability attributes.) |
This comment has been minimized.
This comment has been minimized.
arcto
commented
Jul 3, 2014
|
This needs to be postponed because a lot of thought will be needed in order to get it right. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
bill-myers
commented
Jul 4, 2014
|
I think this might not be the best approach. The fundamental advantage of optional arguments is that they guarantee that f(x) behaves like f(x, a) for some a, while this RFC allows f(x) to behave in an arbitrary fashion completely unrelated to f(x, y). This means that instead of only having to learn how f(x, y) behaves, one must separately learn about how f(x) behaves, while with optional arguments you just need to learn what the default values are. [Note that you can in fact actually reproduce any arity-based overloading using just default arguments (by using Option types for arguments and Either-like enums for returns), but bad design is far more obvious with default arguments since the function will have an ad-hoc if or match to switch behaviors] And at this point, it's not clear why full C++-like overloading should not be allowed as well, since its main drawback (the fact that functions are no longer identified just by their name) is already suffered. Optional arguments might be a good idea though. |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
Jul 4, 2014
combined with multiple dispatch traits or the new 'where' RFC, you might be able to recover C++ style overloading. (make some intermediate functions to shuffle arguments into the self for dispatch) You'd probably also be able to setup a macro for generating curried versions, which appeals to some |
This comment has been minimized.
This comment has been minimized.
CloudiDust
commented on active/0000-arity-parameter-overloading.md in 6b3072d
Jul 4, 2014
|
Nitpick: |
This comment has been minimized.
This comment has been minimized.
alexchandel
commented
Jul 5, 2014
|
Isn't this equivalent to generic function specialization? e.g. fn foo<T>(a: T);
fn foo<int>(a: int) { /* etc */ }
fn foo<uint>(a: uint) { /* etc */ }This seems similar to generic trait implementation, which gives you |
This comment has been minimized.
This comment has been minimized.
|
I'm not making a particular statement about the libraries, but I could make the argument that unwrap/1 can fail while unwrap/2 cannot. They have completely different signatures and you can annotate/document them separately. All overloading does is allow you to use the same name. |
This comment has been minimized.
This comment has been minimized.
|
@iopq, I think if two functions have different semantics, then they should not be using the same name. As people would have wrong expections. They don't have "completely" different signatures in my opinion. Yes we can document them, but it's better if we can tell the difference directly from the names. |
This comment has been minimized.
This comment has been minimized.
|
@iopq, and I agree with @bill-myers that optional/default arguments are better. |
This comment has been minimized.
This comment has been minimized.
|
Closing. There are a number of approaches to overloading, but it is a non-essential feature and the Rust team does not want to address overloading at this time. Thank you. |
brson
closed this
Jul 10, 2014
This comment has been minimized.
This comment has been minimized.
|
filing with RFC issue #323 |
iopq commentedJul 3, 2014
A better proposal to have better names of functions in the standard lib.