|
| 1 | +- Start Date: 2014-07-03 |
| 2 | +- RFC PR #: (leave this empty) |
| 3 | +- Rust Issue #: (leave this empty) |
| 4 | + |
| 5 | +# Summary |
| 6 | + |
| 7 | +This RFC proposes to add optional parameters to Rust functions. |
| 8 | + |
| 9 | +# Motivation |
| 10 | + |
| 11 | +Currently in Rust there are a lot of functions that do the same thing, but take a different number of parameters. |
| 12 | +The current design forces those functions to have different names. |
| 13 | +This causes the standard library to have badly-named functions. |
| 14 | + |
| 15 | +# Detailed design |
| 16 | + |
| 17 | +Optional arguments are an implicit form of overloading. |
| 18 | +Java has a very complicated overloading design that includes overloading by static types. |
| 19 | +Overloading on types mixed with type inference might be very confusing. |
| 20 | +However, overloading based on arity is very simple and clear. |
| 21 | +Java also forces the writer of the function to write out a new function signature for every possible variant. |
| 22 | +A nice syntax for optional parameters is preferable to the Java approach. |
| 23 | + |
| 24 | +So `to_str_radix(&self, radix: uint) -> String` can be now written as `to_str(&self, ?(radix: uint))` |
| 25 | +Since this is sugar for full overloading, a function declared with an optional parameter like this satisfies both |
| 26 | +```rust |
| 27 | +pub trait ToStr { |
| 28 | + fn to_str_(&self) -> String; |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +and |
| 33 | + |
| 34 | +```rust |
| 35 | +pub trait ToStrRadix { |
| 36 | + fn to_str(&self, radix: uint) -> String; |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +traits. |
| 41 | + |
| 42 | +Inside the body of the function, the arguments will be pattern matched something like this: |
| 43 | + |
| 44 | +```rust |
| 45 | +let rad = match args { |
| 46 | + [_, radix] => radix, |
| 47 | + _ => 10 |
| 48 | +}; |
| 49 | +``` |
| 50 | + |
| 51 | +This allows for default arguments or actually doing completely different in each case. |
| 52 | + |
| 53 | +This will let Rust get rid of the sheer multitude of functions that only differ by a few parameters like |
| 54 | +`concat` and `connect`; `split` and `splitn`. You can even go further and have a boolean indicating whether to |
| 55 | +use terminator semantics and put that into `split`, eliminating `split_terminator`. |
| 56 | +You could also have another boolean indicating whether it is reversed, eliminating `rsplitn`. |
| 57 | + |
| 58 | +In this way, the library design is better, allowing auto-completion on `split`. |
| 59 | +There are less names in the std library. Some naming problems go away. |
| 60 | + |
| 61 | +The easiest design is to allow all trailing parameters to be optional. |
| 62 | +That means that no mandatory parameter can come after an optional one. |
| 63 | +This design still allows to simplify naming in the standard library before 1.0 ships and the names are set in stone. |
| 64 | +Further refinements like trailing varargs, keyword arguments are possible in a backwards-compatible way. |
| 65 | + |
| 66 | +# Drawbacks |
| 67 | + |
| 68 | +Currently, you are able to write a function that differs by name to achieve the same effect. |
| 69 | +This works for `slice_from` and `slice_to` and `slice`. |
| 70 | +They are aptly named for what they do and can be easily autocompleted. |
| 71 | +However, just one `slice` with two optional args (defaulting to 0 and the length of the string) |
| 72 | +is much more elegant and doesn't clutter up the standard library with extra functions. |
| 73 | + |
| 74 | +Of course, as I mentioned earlier, this also interacts with traits since now you satisfy two traits with one function. |
| 75 | +This probably interacts with closures and/or lifetimes in some way as well. |
| 76 | +So the correct standard library design must be weighed against adding yet another feature to Rust. |
| 77 | + |
| 78 | +# Alternatives |
| 79 | + |
| 80 | +Another proposal is to somehow represent optional arguments as some kind of an Option type. |
| 81 | +The drawback of this proposal is that Option is a library type. It would have to be baked into the language instead. |
| 82 | + |
| 83 | +Another alternative is to keep the full overloading syntax. This eliminates having to destructure the args array. |
| 84 | +While this makes it a pain to rewrite all the possible variants, it's extremely explicit and clear. |
| 85 | +If you want either one or three arguments only, it won't accept two. |
| 86 | +For any function with k mandatory parameters and n total parameters the current proposal accepts all arities between k and n. |
| 87 | + |
| 88 | +An alternative to trailing optional arguments is keyword arguments. This allows optional arguments in any place as long as |
| 89 | +the following required arguments or following optional arguments are called by their keywords to resolve ambiguities. |
| 90 | +This proposal has the downside of a more complicated argument resolution system (allowing some arguments to be called by position |
| 91 | +and some by keyword). It can also be implemented in a backwards-compatible way post 1.0 so it's not a 1.0 priority. |
| 92 | + |
| 93 | +# Unresolved questions |
| 94 | + |
| 95 | +If destructuring the arguments array is necessary, should there be some kind of a keyword for them. |
| 96 | +Is there any way to implement it without using a keyword, other than Java-style overloading? |
| 97 | + |
| 98 | +If varargs are included in the proposal, then the `main` function could be written as |
| 99 | + |
| 100 | +```rust |
| 101 | +fn main(...arguments: String) |
| 102 | +``` |
| 103 | + |
| 104 | +which could be nice. But then again, using std::os::args() is not a huge problem. |
0 commit comments