Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optional parameters #152

Closed
wants to merge 2 commits into from

Conversation

Projects
None yet
@iopq
Copy link
Contributor

iopq commented Jul 3, 2014

RFC for optional parameters added to Rust functions

Since this is sugar for full overloading, a function declared with an optional parameter like this satisfies both
```rust
pub trait ToStr {
fn to_str_(&self) -> String;

This comment has been minimized.

@huonw

huonw Jul 3, 2014

Member

Is the trailing _ a typo?

This comment has been minimized.

@iopq

iopq Jul 3, 2014

Author Contributor

yes, it's a typo

Inside the body of the function, the arguments will be pattern matched something like this:

```rust
let rad = match args {

This comment has been minimized.

@huonw

huonw Jul 3, 2014

Member

What is args? An implicit variable in every function? What is its type?

This comment has been minimized.

@huonw

huonw Jul 3, 2014

Member

Also, this implies that functionality that was previously "executed" at compile time (i.e. calling a different method to get different behaviour) would now, instead, be executed at runtime, as a switch over the number of arguments. Am I interpreting this correctly?

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

Is this something like Javascript's implicit arguments variable in each function?

This comment has been minimized.

@iopq

iopq Jul 3, 2014

Author Contributor

It's a problem, since the contents have different types.

Currently, you are able to write a function that differs by name to achieve the same effect.
This works for `slice_from` and `slice_to` and `slice`.
They are aptly named for what they do and can be easily autocompleted.
However, just one `slice` with two optional args (defaulting to 0 and the length of the string)

This comment has been minimized.

@huonw

huonw Jul 3, 2014

Member

Could we have code examples for how the new slice function would be declared and called? (Having more examples would be good.)

This comment has been minimized.

@huonw

huonw Jul 3, 2014

Member

Sorry, I'll strengthen that: this needs more examples of declaration and of calling (e.g. I don't see any use of the ?(...) syntax other than the isolated mention in the text): this proposing a syntactic/ergonomic change so we need to be able to see what it looks like with clarity.

@jnicklas

This comment has been minimized.

Copy link

jnicklas commented Jul 3, 2014

I'd like to propose an alternate syntax. How about something akin to Java's overloading?

fn concat(&self) -> String {
  self.join(self, ",")
}

fn concat(&self, sep: &str) -> String {
  ...
}

// compile error, because the first parameter's type
// doesn't match the type of `concat` already declared.
fn concat(&mut self, sep: &str) -> String {
  ...
}

// compile error, because the second parameter's type
// doesn't match the type of `concat` already declared.
fn concat(&self, number: int) -> String {
  ...
}

This feels like it has way more precedent, and it's quite clear how the syntax works, and we don't have to answer weird questions like what happens to sep inside the function body in case it is not given.

@huonw

This comment has been minimized.

Copy link
Member

huonw commented Jul 3, 2014

// doesn't match the type of to_str already declared.

s/to_str/concat/?

@jnicklas

This comment has been minimized.

Copy link

jnicklas commented Jul 3, 2014

@huonw yes, copy-paste error, I updated the comment.

}
```

traits.

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

I don't understand what you mean by "satisfies both traits". Rust isn't duck-typed, and therefore you only satisfy a trait if you explicitly implement it. Merely implementing a function with a compatible type signature doesn't allow you to do anything generically.

This will let Rust get rid of the sheer multitude of functions that only differ by a few parameters like
`concat` and `connect`; `split` and `splitn`. You can even go further and have a boolean indicating whether to
use terminator semantics and put that into `split`, eliminating `split_terminator`.
You could also have another boolean indicating whether it is reversed, eliminating `rsplitn`.

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

Just a note here, but boolean flags are an API anti-pattern. I'd rather have separately-named functions.

is much more elegant and doesn't clutter up the standard library with extra functions.

Of course, as I mentioned earlier, this also interacts with traits since now you satisfy two traits with one function.
This probably interacts with closures and/or lifetimes in some way as well.

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

Yes, it would be impossible for any function to return a reference that in any way relied upon the lifetime of an optional input.

However, just one `slice` with two optional args (defaulting to 0 and the length of the string)
is much more elegant and doesn't clutter up the standard library with extra functions.

Of course, as I mentioned earlier, this also interacts with traits since now you satisfy two traits with one function.

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

Another reminder that this is not how traits work in Rust (see above).

use terminator semantics and put that into `split`, eliminating `split_terminator`.
You could also have another boolean indicating whether it is reversed, eliminating `rsplitn`.

In this way, the library design is better, allowing auto-completion on `split`.

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

In what way does the lack of optional parameters impede autocompletion?

This comment has been minimized.

@iopq

iopq Jul 3, 2014

Author Contributor

I could want to "concat by character" and be looking for all functions that start with concat but it's actually connect.


Currently in Rust there are a lot of functions that do the same thing, but take a different number of parameters.
The current design forces those functions to have different names.
This causes the standard library to have badly-named functions.

This comment has been minimized.

@bstrie

bstrie Jul 3, 2014

Contributor

I don't argue that some of our stdlib functions could be better named, but finding better names is not impossible. I also don't argue that optional parameters will allow strictly nicer names some of the time; god knows I've wished for them before. But keep in mind that up till now our stance has been that being forced to name your functions explicitly has been considered a feature, and that the lack of overloading/optional parameters has been an explicit choice (though entirely subjective). To overcome this inertia, you'd be best served by showing before/after comparisons of how real-life stdlib functions would look (both in definition and in usage) if this change were accepted.

This comment has been minimized.

@iopq

iopq Jul 3, 2014

Author Contributor

I think I'd rather resubmit this as Java-style overloading. It's easier with static typing + no nulls. In C# you'd just go with unwrap(default = null) and call it a day. Not so easy in Rust since Option is more syntactically noisy.

@bstrie

This comment has been minimized.

Copy link
Contributor

bstrie commented Jul 3, 2014

@jnicklas, this is such an enormously wide-open design space that I don't want to sidetrack the comments here discussing alternatives. Note as well that this particular RFC explicitly rejects Java-style overloading. Given that people have certainly asked for overloading in the past (especially among C++ developers, our key demographic), I would suggest that you propose an entirely separate RFC if you'd like to discuss it. But if you do so, please make sure it's complete and well-considered; submit a pre-RFC to the mailing list if you'd like to solicit opinions and feedback.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jul 3, 2014

Note that there is a great deal of discussion at rust-lang/rust#6973.

I would encourage this RFC to plan for a backwards-compatible design as it may otherwise be difficult to fit this in before 1.0 is released.

@arcto

This comment has been minimized.

Copy link

arcto commented Jul 3, 2014

@alexcrichton, I believe the reason this should be discussed before 1.0 is that, with overloading, some functions in the standard library could possibly be given better/more consistent names.

@arcto

This comment has been minimized.

Copy link

arcto commented Jul 3, 2014

I agree with @jnicklas in that explicitness makes overloading clearer and simpler - syntactically and semantically, imho. If two functions share parts of the implementation one can always call one function from the other and have the compiler inline the call.

fn foo(a: int, b: int) {...}

fn foo(a: int) {
    ...?
    foo(a, 42);
}
}
// compile error, because the first parameter's type
// doesn't match the type of `concat` already declared.

This comment has been minimized.

@steveklabnik

steveklabnik Jul 3, 2014

Member

We don't currently have any kind of ordering for declarations, right? This introduces some kind of ordering.

@bstrie

This comment has been minimized.

Copy link
Contributor

bstrie commented Jul 3, 2014

@arcto, at least in theory, Rust's libraries and tooling have powerful enough support for versioning that it will be possible to evolve the stdlib independent of the language (though each version of the stdlib will obviously require some minimum Rust version), and you'll trivially be able to make use of multiple versions of the stdlib in the same project if you really want.

I agree that it's crucial to have a good stdlib API for 1.0, but this is just pointing out that our definition of "good API" is allowed to change at our leisure over time, as Rust gains features.

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Jul 3, 2014

Thanks for submitting the RFC. Whilst optional parameters 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.

@kud1ing

This comment has been minimized.

Copy link
Contributor

kud1ing commented Jul 4, 2014

Therefore, this RFC is extremely likely to be closed as postponed.

Can't it just be left open with a milestone?

@huonw

This comment has been minimized.

Copy link
Member

huonw commented Jul 4, 2014

We do give them with a "milestone" (i.e. tagged with postponed), but they are closed to try to keep this repo focused and manageable. (NB. discussion of this behaviour is offtopic for this PR: you can open an issue if you see another way we can manage this without leaving a long tail of good-but-postponed RFCs cluttering the UI.)

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Jul 10, 2014

Closing. While optional arguments are an oft-requested feature, it has long been our position that it is non-essential and can be reconsidered backwards-compatibly at some point in the future. Thank you.

@brson brson closed this Jul 10, 2014

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Sep 24, 2014

This probably should have gotten the postponed label

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Sep 25, 2014

Filing with RFC issue #323

withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017

Merge pull request rust-lang#152 from stepancheg/take-err
Stream::take should count errors too
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.