rfcs
rfcs copied to clipboard
Wishlist: functions with keyword args, optional args, and/or variable-arity argument (varargs) lists
A portion of the community (and of the core team) sees one or more of the following features as important for programmer ergonomics:
- keyword-based parameters (as opposed to position-based parameters),
- optional parameters (where one provides a default value for them, usually in the parameter list),
- variable-arity functions (which can be seen as a generalization or variation on optional parameters, depending on how you look at it).
This issue is recording that we want to investigate designs for this, but not immediately. The main backwards compatibility concern is about premature commitment to library API's that would be simplified if one adds one or more of the above features. Nonetheless, We believe we can produce a reasonable 1.0 version of Rust without support for this.
(This issue is also going to collect links to all of the useful RFC PR's and/or Rust issues that contain community discussion of these features.)
Nonetheless, We believe we produce a reasonable 1.0 version of Rust without support for this.
depends on how you see it. the API will definitely be well-considered given the constraints of no default/kw arguments.
but once those are added, i’m sure the API will be considered lacking, especially in areas where new defaults render old functions obsolete.
a good example (if the new syntax sugar wouldn’t exist) would be ImmutableSlice
:
fn slice(&self, start: uint, end: uint) -> &'a [T];
fn slice_from(&self, start: uint) -> &'a [T];
fn slice_to(&self, end: uint) -> &'a [T];
slice_from
and slice_to
will be immediately obsolete once you can just leave out start
or end
from slice
. i bet there are hundreds of examples more.
@flying-sheep so then you deprecate such methods, just like today, no?
@pnkfelix I think his argument is that we don't want to be stuck with a ton of deprecated cruft in the stdlib, but I'm still personally not too sympathetic to the need to have default arguments before 1.0.
yeah, that’s my argument. either cruft, or lengthy deprecation formalities and rust 2.0 a year after 1.0 (semver requires a major version bump for breaking changes)
While I'd prefer to have optional/keyword args before 1.0, I believe the problem with deprecated functions crufting up the API can be substantially lessened by removing such functions from the generated API docs. This is how the Qt project (and D AFAIK) handles API deprecation; the deprecated stuff continues working but developers writing new code don't see it.
Of course, the generated docs should have a setting/link/button to show the deprecated API items but it should be off by default.
I think this is also a good idea in general; just a couple of days ago I accidentally used a deprecated function because it seemed like a good pick and I didn't notice the stability color.
Rustdoc's handling of deprecated items definitely needs some improvement - see rust-lang/rust#15468 for some discussion.
See the "Struct sugar" RFC for another take.
I'd like to see some of these RFCs revived in the near future, if someone has time to do so.
Agreed, there's a whole bunch of different keyword arguments proposals floating around and there's been a few discussions which seemed to die off a few months ago... would love to hear the current standpoint on this.
Ok, 1.0 released, even more, can we please discuss it again? especially default arguments.
This issue is open, it's free to discuss.
This issue is open, it's free to discuss.
(though its possible an https://internals.rust-lang.org post might be a better UI for undirected discussion ... we didn't have the discuss forums when we set up these postponed issues...)
I'd love to see keyword arguments. I opened a thread on /r/rust with some comments about them before finding this issue. I guess /r/rust is an appropriate place for "undirected discussion" too?
In any case, this should be done in such a manner that it does not cause very inconsistent libraries, perhaps by letting the named parameters be optional? For example the names could be given by the argument name. Such that, the function:
fn func(a: u8, b: u8) -> u8;
can be called both with and without named parameters, for example:
func(a: 2, b: 3)
or something along this, while still being able to do:
func(2, 3)
Also, this feature could easily be misused by taking named parameters instead of structs, which, I think, is a bad thing.
I think it's because supposedly people are thinking about some kind of heterogenous variadicity (like the case of println, which is currently done with macros), and that isn't possible with arrays.
I see, but that's why we got macros. If you want heterogenous variadicity, you gotta go with macros, after all the Rust macro system is very powerful.
I agree, macros are appropriate for this.
When I was first learning Rust pre-1.0, hearing that keyword arguments were not going to be implemented for 1.0 seemed like a terrible choice. From a background in Ruby/Python/JavaScript, keyword arguments are a very common and natural way to create nice APIs.
However, after actually using Rust for a while, I've actually grown to like the struct/builder pattern much more than keyword arguments. The problem with making keyword arguments easy is that it encourages functions that do too much by taking a bunch of different options.
If, instead, you are restricted to positional arguments, then you're more inclined to keep functions small, with a smaller surface area for their signatures. If there a small number of variations on the behavior of a function, these can exist as different named functions (e.g. alternate constructors.) If there really are a large number of variables needed for a function, pulling those variables out into a dedicated struct provides basically all the benefits of keyword arguments, plus the possibility of reuse.
I think if keyword arguments are added, they should just be syntactic sugar for functions that take a struct argument.
If you want heterogenous variadicity, you gotta go with macros, after all the Rust macro system is very powerful.
And then you have to limit the length of your heterogeneous lists to ~10 to avoid horrible metadata bloat. Macros help, but it's still a half-measure.
@jimmycuadra I agree. Functions should be small and compact, however sometimes you want to be able to know the argument order without looking up the signature (which keyword arguments solve), even though structs and other type constructions should always be prefered over named parameters, when dealing with larger amount of inputs.
One thing that's important to me is consistency with the current call syntax (such that it's up to the caller whether to use named arguments or not). This can be achieved in the way I described in my previous comment.
@petrochenkov The problem you outline is a problem with macros, not a need for method variadicity.
Also, this feature could easily be misused by taking named parameters instead of structs, which, I think, is a bad thing.
No, using structs instead of named arguments is a bad thing. And using array instead of arguments is a horrible thing.
I agree, macros are appropriate for this.
For named arguments? Or for optional arguments? Writing macros for EACH function, export/import it - it's very over-verbose.
I think if keyword arguments are added, they should just be syntactic sugar for functions that take a struct argument.
No way. Better not implement it at all than this.
Functions should be small and compact
Let each user decide how their functions should look. Don't roll into Go-ideology "we don't have it because you don't need it and we know better".
Really frustrated to see such comments. All modern languages except Go have it, but Rust "don't need it, because macros". What a shame.
No, using structs instead of named arguments is a bad thing.
Not true. Structs are strongly typed (hence less prone to errors) and makes it possible to efficiently reuse codes. Your functions shouldn't take a large number of arguments anyway.
And using array instead of arguments is a horrible thing.
This is not true. Using arguments instead of arrays is a horrible thing.
For named arguments? Or for optional arguments? Writing macros for EACH function, export/import it - it's very over-verbose.
It not very often you run into lack of variadic functions, and when you do, you can write a macro, and when generic integers lands, you can just use arrays. Often functions takes a fixed number of arguments anyways.
Also, note that the macro syntax will soon be revised.
Let each user decide how their functions should look. Don't roll into Go-ideology "we don't have it because you don't need it and we know better".
One of Rust's design philosophies is that Rust should not lead the user into bad code, bugs, and logic errors (this is the reason why we don't have increments, for example). We're all lazy after all, but there is no reason to encourage being lazy.
Your functions shouldn't take a large number of arguments anyway.
I will decide it, not you.
Structs are strongly typed
function arguments too.
Often functions takes a fixed number of arguments anyways.
If your functions often take fixed number of arguments, all other users should obey?
One of Rust's design philosophies is that Rust should not lead the user into bad code
And again - what is bad code will decide user, not some very arrogant community members.
If your functions often take fixed number of arguments, all other users should obey?
I'm just saying that introducing syntactic sugar for such a small special case is not worth it. This job is better suited for macros.
And again - what is bad code will decide user, not some very arrogant community members.
Sure, user should not be forced to not writing bad code, but neither should they be encouraged to.
Just a friendly reminder everyone: let's try to keep conversation civil and constructive! Thanks.
Are keyword-based arguments must be mandatory for all or it is up to me?
@KalitaAlexey I'm not exactly sure what you're asking, but I supose you mean "Is it mandatory to provide the name of the parameters to the function, if we get keyword arguments". And the answer is no, because that would break backwards compatibility.