Skip to content

Support rest parameter syntax like Javascript. #893

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

Open
liudonghua123 opened this issue Mar 24, 2020 · 6 comments
Open

Support rest parameter syntax like Javascript. #893

liudonghua123 opened this issue Mar 24, 2020 · 6 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@liudonghua123
Copy link

I posted a issue about spread syntax support in dart (#891), it was support in dart 2.3 acturally. Now it comes to it's partner rest parameter.

I try to write the following code, but it has syntax error. Is there some simple and clean syntax to achieve the same goal like javascript?

class Person {
  final String name;
  final int age;

  Person({this.name, this.age});

  @override
  String toString() {
    print('name: ${name}, age: ${age}');
  }
}

main() {

  var data = {'name':"hello", 'age':18, 'sex':'male'};
  var person1 = Person(data);
  var person2 = Person(...data);
  var person3 = Person({...data});
}

image

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

@liudonghua123 liudonghua123 added the feature Proposed language feature that solves one or more problems label Mar 24, 2020
@liudonghua123
Copy link
Author

I can add a fromJson factory method. but it does not have a shape or type definition for a map. So it does not validate map during compile time.

class Person {
  final String name;
  final int age;

  Person({this.name, this.age});

  @override
  String toString() {
    super.toString();
    return 'name: ${name}, age: ${age}';
  }

  factory Person.fromJson(Map<String, dynamic> json) =>
      Person(name: json['name'], age: json['age']);
}

main() {
  var data = {'name': "hello", 'age': 18, 'sex': 'male'};
  // var person1 = Person(data);
  // var person2 = Person(...data);
  // var person3 = Person({...data});
  var person4 = Person.fromJson(data);
  var person5 = Person.fromJson({...data});

  var data2 = {'username': "hello", 'age': 18, 'sex': 'male'};
  var person6 = Person.fromJson(data2);
  print(person6); // name: null, age: 18
}

@lrhn
Copy link
Member

lrhn commented Mar 31, 2020

What you are showing here is spread arguments.

Simple spreading a map or list into a parameter list is not going to be statically typable.
Since Dart parameters are typed (unlike JavaScript), that's a serious blocker.

The reason you can just spread an iterable into a list literal is that as long as all the elements have the right type, it doesn't matter how many there are. That does not hold for arguments.
There has been some experiments into combining rest parameters and spread arguments.

If you could define a function as foo(int x, [int... rest]) {...} and it could take any number of integer arguments after x, then we could allow you to also spread into the rest parameter as foo(2, 3, ...moreInts, 5, ...evenMoreInts, 7).
It's not clear what the subtyping rules are for such methods. Is Function([int, int, int...]) the same type as Function([int...]) or not?

In any case, it's something we are aware of, but do not have a clean solution for right now.

@liudonghua123
Copy link
Author

@irhn, How about named parameters and map, in the example above,
If Person(name: 'hello', age: 18) can write using syntax sugar like the following, that's would be nice.

var data = {'name': "hello", 'age': 18};
Person(...data)

or

var data = {name: "hello", age: 18}; // this is incorrect now
Person(...data)

@lrhn
Copy link
Member

lrhn commented Apr 15, 2020

Dart is a statically checked language. Using a value with an unknown run-time structure, like a map, as parameters makes it impossible to statically check the validity of the arguments.

Take the example:

var data = {#name: "hello", #age: 18}; 
Person(...data)

(Using symbols for referring to source names, same as Function.apply and noSuchMethod).
Here it looks easy to see that the map actually has a #name and an #age entry, but that's because the map is written as a literal right next to the application. That's the one situation where you don't actually need spread arguments, because you could just write the arguments directly.

In all actually useful cases, it's not possible to see statically which entries the map has, and which types the values are for each key. The type of the map, Map<Symbol, dynamic> is not strong enough to allow checking the call. You should just use Function.apply(Person, [], data) ... except that we (still) do not allow constructors as functions (#216).

If Dart had typed structs/named tuples, it might be possible to do:

// Static type is the named tuple type `(String name, int age)`
var data = (name: "name", age: 18);
var person = Person(...data);

At this point, the static type of data is specific enough to allow the call to be checked statically.

@SAGARSURI
Copy link

Kotlin has a keyword varargs which can take 0 or n parameters. How are they able to achieve it?
https://www.baeldung.com/kotlin/varargs-spread-operator

@Levi-Lesches
Copy link

Levi-Lesches commented Oct 21, 2021

Varargs specifically (ie, simply collecting many objects into a List as in your linked example) are probably not as complex as the commonly-requested conversion from a Map<String, dynamic> to named parameters.

Here's what @lrhn said in an earlier comment:

If you could define a function as foo(int x, [int... rest]) {...} and it could take any number of integer arguments after x, then we could allow you to also spread into the rest parameter as foo(2, 3, ...moreInts, 5, ...evenMoreInts, 7).
It's not clear what the subtyping rules are for such methods. Is Function([int, int, int...]) the same type as Function([int...]) or not?

I suppose the main pushback would be "why not just pass in a regular List?", especially with the new list-comprehension tools and the spread operator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

4 participants