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

auto-tupling and auto-unit'ing for variable arity fns #258

Closed
wants to merge 8 commits into from

Conversation

pnkfelix
Copy link
Member

Summary

Add support for default and variable-arity functions via a small language feature and a simple programming pattern. The language feature is solely a pair of changes to the treatment of function call-sites:

  • If there are excess arguments at a given call site, then automatically turn convert excess arguments into a tuple of the final argument and the excess arguments. I call this "auto-tupling."
  • If there are insufficient arguments at a given call site, then automatically replace each of the omitted arguments with the unit value (). I call this "auto-unit'ing."

The above two transformations can be used in tandem with the trait system as a way to express optional parameters and multiple-arity functions.

(rendered)

@Valloric
Copy link

#257 is both a simpler proposal (from the user's perspective) and would result in code that is easier to read and understand. This RFC suffers from trying to optimize for the ease-of-use of the compiler writer instead of the language user.

The first step for API design is to write out the example calls & uses of the API and then to come up with an implementation that would suit that; this RFC did it backwards.

@jfager
Copy link

jfager commented Sep 24, 2014

So the win over current Rust is that you need one less pair of parentheses? The dance of having to define one-off arg traits strikes me as a much larger headache.

@pnkfelix
Copy link
Member Author

@jfager I assume your critique is directed solely at auto-tupling? (auto-unit'ing gets rid of many () entries.)

Anyway, my thinking wasn't just "ah, this looks nicer without that extra pair of parentheses" -- it is also about forward-migration, where a library can go from version 1 to version 1.1 by replacing a sequence of concrete trailing arguments with one or more traits, and (assuming those traits have appropriate implementations), the client source code will not need to be changed in response (just recompiled).

@pnkfelix
Copy link
Member Author

@Valloric I'll admit that implementation simplicity is one of my concerns. But I also think there is virtue in exploring how much value one can get out of such a small change.

Its entirely possible that #257 will be deemed an acceptable change to the language. Based on my cursory skimming of #257, I am wondering whether both this and #257 are potentially-compatible changes that could both be applied to Rust.

Using a trait to express the variable-arity arguments provides the client with more flexibility; but maximizing flexibility is not always the right choice anyway.

@jfager
Copy link

jfager commented Sep 24, 2014

@pnkfelix I'd guess that the large majority of uses would only have one trailing parametric arg intended for overloading, so even for auto-uniting it would generally only be saving one pair of parentheses.

When there are multiple trailing parametric args, you could save more sets of parens, true. But working with multiple trailing parametric args seems like it could be dangerous (assuming I'm understanding the rules correctly). Consider a variation on your api evolution example:

#[cfg(version_1)]
fn foo<A:TraitA>(a: A) { ... }
impl TraitA for int { ... }
impl TraitA for (int,int) { ... }

#[cfg(version_2)]
fn foo<A:TraitA, B:TraitB>(a: A, b: B) { ... }
impl TraitB for int { ... }
impl TraitB for (int,int) { ... }

foo(1,2)  // version 1:  foo((1,2): A), version 2:  foo(1: A, 2: B)

@pnkfelix
Copy link
Member Author

@jfager Hmm, interesting point. Assuming the person writing the library also defined the TraitA and TraitB, that library then has control over impl's like int and (int,int) (and any other type derived directly from the type constructors in libstd).

But nonetheless, I do agree that there is a risk here, namely when a client has implemented one of the traits for their own types, e.g. impl TraitA for (ReportFormat, GuiWindow), and then it would not be sound to go from version_1 to version_2.

So it seems like I overstated the forward-compatibility powers of this proposal: You get one shot at adding some number of trailing parametric args. After that that point, all future extensions must be done through the single final trait. So that makes the auto-unit'ing less useful than I had hoped.

@Valloric
Copy link

@pnkfelix

I appreciate exploring how far we could get without extensive changes to the language, but the root of the problem remains that no user, when asked to provide an example of how they would like to use optional/keyword args, would come up with "I want a to write a trait for every function for which I want to have keyword args and then I want to impl that trait in various ways and write many lines of code to get something I can do with a few chars in any other modern language." And that's not a straw-man, this proposal does require writing way more code to get optional/keyword args than other languages.

I understand that this approach is simple to implement in the compiler, but there's a handful of rustc developers and thousands of Rust users (and there's every intent that the number of users grows to millions).

I'm sorry, but you're optimizing for the wrong thing.

I am wondering whether both this and #257 are potentially-compatible changes that could both be applied to Rust.

That is probably a bad idea. There should be one and only one obvious way to do it.

@pnkfelix
Copy link
Member Author

closing as postponed, filing with RFC issue #323

@pnkfelix pnkfelix closed this Sep 25, 2014
@pnkfelix pnkfelix added the postponed RFCs that have been postponed and may be revisited at a later time. label Sep 25, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
postponed RFCs that have been postponed and may be revisited at a later time.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants