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

Positional and optional parameter syntax is unwarranted #6496

Closed
DartBot opened this issue Nov 2, 2012 · 18 comments
Closed

Positional and optional parameter syntax is unwarranted #6496

DartBot opened this issue Nov 2, 2012 · 18 comments
Assignees
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). closed-not-planned Closed as we don't intend to take action on the reported issue type-enhancement A request for a change that isn't a bug

Comments

@DartBot
Copy link

DartBot commented Nov 2, 2012

This issue was originally filed by Don.J.Olm...@gmail.com


Dart introduces additional syntax to support positional and named arguments. This goes against various other languages that support optional and positional arguments where no additional syntatic sugar is needed, and creates an additional hurdle to learn the language.

In C# arguments can be passed by name or by position. As an example from http://msdn.microsoft.com/en-us/library/dd264739.aspx, If you had the following method

static int CalculateBMI(int weight, int height)

It could be invoked in the following ways

CalculateBMI(123, 64);
CalculateBMI(weight: 123, height: 64);
CalculateBMI(height: 64, weight: 123);
CalculateBMI(123, height: 64);

However it cannot be invoked like this, as positional arguments cannot follow a named argument
//CalculateBMI(weight: 123, 64);

For optional arguments the same rules apply
static public void ExampleMethod(
  int required,
  string optionalstr = "default string",
  int optionalint = 10)

ExampleMethod(3, optionalint: 4);
ExampleMethod(3, "a string", 4);

However it can not be invoked positionally without specifying all the values up to that point
//ExampleMethod(3, ,4);

So in C# all methods can be invoked with either named or positional arguments. No additional syntax is required. Optional parameters have their values specified by using assignment in the declaration.

Dart syntax for named/optional parameters is different and provides no additional gain. See http://rosettacode.org/wiki/Named_parameters for examples on other language's implementation, such as Python which provides a similar implementation.

@kevmoo
Copy link
Member

kevmoo commented Nov 2, 2012

I'll double-down on C# syntax. While I try hard not to be a blind fan boy "do what Anders does", in this case I think the C# impl is easier and more flexible.

@DartBot
Copy link
Author

DartBot commented Nov 2, 2012

This comment was originally written by jirkad...@gmail.com


I would love to see the design reasons explained behind the current positional and optional parameter syntax. I somehow feel there might be some additional gain over the C♯ style.

@jmesserly
Copy link

+1, I found the new behavior very surprising:

* syntax is weirdly different: [bool foo = 42] vs {bool foo: 42}.

* cannot combine optional positional and named. This means if I publish an API with an optional positional argument, I can never add a named argument later (or vice versa!).

The only rule we could come up with is: never use optional positional arguments, unless you only have 1, and you don't think you'll ever need more (for example: String.substring). Everything else should use optional named arguments.


Maybe this is a different issue but: the "?" prefix operator is completely broken. You can't even wrap a function anymore, without exponential explosion:

// if "bar" uses ? inside -- callers beware!
bar({x, y, z}) { ... }

foo({x, y, z}) {
  doStuff();
  if (!?x && !?y && !?z) bar();
  if (!?x && !?y && ?z) bar(z: z);
  if (!?x && ?y && !?z) bar(y: y);
  if (!?x && ?y && ?z) bar(y: y, z: z);
  if (?x && !?y && !?z) bar(x: x);
  if (?x && !?y && ?z) bar(x: x, z: z);
  if (?x && ?y && !?z) bar(x: x, y: y);
  if (?x && ?y && ?z) bar(x: x, y: y, z: z);
  doOtherStuff();
}

Madness...


Added Area-Language, Triaged labels.

@dgrove
Copy link
Contributor

dgrove commented Nov 2, 2012

Set owner to @gbracha.

@munificent
Copy link
Member

I agree with John. I'm glad the new behavior solves the one problem it set out to solve (unintentionally baking a parameter name into your public API) but I don't understand why we prioritized solving that problem over all of the problems the new behavior creates and the existing problems that it doesn't solve.

@DartBot
Copy link
Author

DartBot commented Nov 2, 2012

This comment was originally written by Don.J.Olms...@gmail.com


I know you discussed this on the mailing list Bob, but I'm still at a loss as to how baking a parameter name into your public API is a bad thing. If you subclass and override a method you should be using the same names as the method you're overriding. If you're using a named parameter and the name changes your code should break.

With this particular change in the HTML library there's a TON of code breakage for little to no benefit. There is really no precedence for this change in any other language and it makes things more complicated than necessary [] for optional {} for named. Other languages just have = and then the parameter is optional, thus negating the need for [], and some go the extra mile and provide for named parameters, making everything being able to passed in by the parameter name and not requiring {}.

@munificent
Copy link
Member

how baking a parameter name into your public API is a bad thing

It isn't. Baking a parameter name into your public API unintentionally is. With the old syntax, let's say you wanted to have some optional positional parameter:

  foo([bar]) { ... }

Find and dandy, but you've also made that parameter named. So now, like it or not, "bar" is part of foo's public API and you're stuck with it.

This is the problem they were trying to fix with the new syntax. Personally, I think this is a pretty small problem. When C# added optional parameters they made them all named too. I don't know why Dart's designers chose to care about this and change a bunch of other things in the process of fixing it.

@DartBot
Copy link
Author

DartBot commented Nov 2, 2012

This comment was originally written by ladicek@gmail.com


I always felt like there is a tiny little thing about optional parameters in Dart that doesn't suit me, but I couldn't find the words. This is it. Totally agree with Don.

@DartBot
Copy link
Author

DartBot commented Nov 4, 2012

This comment was originally written by sig...@gmail.com


In the context of Don's C# comparison, and Bob's comment about \*unintentionally\* baking a parameter name' in the public API: the C# way \*does\* exactly that, probablyintentionally'! Philosophically, I am for that approach -- every part of your public API is public, including parameter names! Design with care!

Therefore, as far as this issue is concerned, I vote for the C# style. There should not be a separate syntax for declaring named parameters. Alternatively, please provide a syntax for required named parameters. Mandatory disambiguation :-).

@gbracha
Copy link
Contributor

gbracha commented Nov 7, 2012

Added this to the M2 milestone.
Removed Type-Defect label.
Added Type-Enhancement, Accepted labels.

@floitschG
Copy link
Contributor

I clearly disagree with comment 9 (which states that every argument name should be part of the signature), but I do feel restricted when designing the core-library.
In particular not being able to specify positional and named arguments is annoying.
For example, we now have:
class List {
  // Creates an extendable list of the given length.
  List([length = 0]);
  // Creates a fixed-sized list of the given length, filled with [fill].
  List.fixedLength(length, { fill: null });
  // Creates an extendable list of the given length, filled with [fill].
  List.filled(length, fill);
  ...
}

Clearly we would prefer to have similar signatures for the extendable and the fixed-length constructors:
class List {
  // Creates an extendable list of the given length, filled with [fill].
  List([length = 0], { fill: null });
  // Creates a fixed-sized list of the given length, filled with [fill].
  List.fixedLength(length, { fill: null });
  ...
}

@gbracha
Copy link
Contributor

gbracha commented Nov 28, 2012

Removed this from the M2 milestone.
Added this to the Later milestone.

@kevmoo
Copy link
Member

kevmoo commented Feb 17, 2013

I take it back. I don't want Dart to support the C#-style positional/named arguments model.

The C# model does not have a way to require users to use names. They can just provide args in the correct order.

So as an API author, the only way I can modify the args list is to add new items at the end to ensure nothing is broken. If I remove an argument somewhere in the middle I don't just break folks who specify that arg, but potentially any user that specifies arguments up to that point in the arg list.

The Dart model, while a tiny bit more typing up front, is much better for future-proofing APIs and minimizing the impact of breaking changes. Well played.

From my G+ post: https://plus.google.com/u/0/110066012384188006594/posts/2ZfpJkNcV4a

@DartBot
Copy link
Author

DartBot commented Jul 25, 2013

This comment was originally written by ha...@gmail.com


One piece of missing functionality for me is: right now there is no way to have a named parameter that is non-optional. The only way to make it mandatory is by dropping it's name and giving it a position... I'd love the ability to give named parameters in any order and still being able to declare that one or several of those HAVE to be given when you call the method (again no matter in what order)

@DartBot
Copy link
Author

DartBot commented Jul 25, 2013

This comment was originally written by hachre...@gmail.com


Wouldn't a syntax like this be viable?

someMethod(String name: required, num age: required, String address, int postalCode, String countryCode: "US");

Here the String field name and the num field age would be set as required. If the call to the method doesn't declare them it's an exception. We can use that spot that would normally be used to give a default value because we require a set value on the method call.

The field address and postalCode are optional and have no default value. And finally the field countryCode is optional and has the default value "US".

The positions of any of those parameters would not matter. The moment you use this syntax you should no longer be able to use the positional syntax in the same method declaration to avoid problems.

No good?

@kasperl
Copy link

kasperl commented Jul 10, 2014

Removed this from the Later milestone.
Added Oldschool-Milestone-Later label.

@kasperl
Copy link

kasperl commented Aug 4, 2014

Removed Oldschool-Milestone-Later label.

@gbracha
Copy link
Contributor

gbracha commented Aug 25, 2014

I think the language is far enough along now that it is unlikely we'll change this.


Added WontFix label.

@DartBot DartBot added Type-Enhancement area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). labels Aug 25, 2014
@kevmoo kevmoo added closed-not-planned Closed as we don't intend to take action on the reported issue type-enhancement A request for a change that isn't a bug and removed resolution-wont_fix labels Mar 1, 2016
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). closed-not-planned Closed as we don't intend to take action on the reported issue type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

8 participants