Skip to content

Allow optional defaults to be properties of mandatory positional parameters #951

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
HarvsG opened this issue May 4, 2020 · 3 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@HarvsG
Copy link

HarvsG commented May 4, 2020

Describe the new syntax or language feature you'd like to see incorporated into
Dart. Ideally you can relate this to a request issue filed separately.

let's say I have some class:

class Product{
  final String id;
  final String title;
  final String description;
  final double price;
  final String imageUrl;
  bool isFavourite;

  Product({
    this.id,
    this.title,
    this.description,
    this.price,
    this.imageUrl,
    this.isFavourite=false,
  });

_editedProduct = Product(id: null, title: null, description: null, price: null, imageUrl: null)

And in my buisness logic I want to update each element of the class at different times and in an unknown order (e.g with user input). As the properties are final, each time I have to create a new product with the other, unedited, fields saved fed back into the class

Lets say in an anonymous function associated with the user inputting the id.

onSubmit:  (value) {
     _editedProduct = Product(
     id: value,
     title: _editedProduct.title,
     description: _editedProduct.description,
     price: _editedProduct.description,
     imageUrl: _editedProduct.imageUrl);
}

If I wanted to do the same with the other fields, I could write

onSubmit:  (value) {
     _editedProduct = Product(
     id: _editedProduct.id,
     title: value,
     description: _editedProduct.description,
     price: _editedProduct.description,
     imageUrl: _editedProduct.imageUrl);
}

...

onSubmit:  (value) {
     _editedProduct = Product(
     id: _editedProduct.id,
     title: _editedProduct.title,
     description: value,
     price: _editedProduct.description,
     imageUrl: _editedProduct.imageUrl);
}

And so on...

This leads to a lot of duplicated code.

It would be great if I could define a function like this:

  Product editProduct(Product productToEdit,
      {String id = productToEdit.id,
      String title = productToEdit.title,
      String description = productToEdit.description,
      double price = productToEdit.price,
      String imageUrl = productToEdit.imageUrl}) {
    return Product(
        id: id,
        title: title,
        description: description,
        price: price,
        imageUrl: imageUrl);
  }

Then to update any one paremeter I could simply run:

_editedProduct = editProduct(_editedProduct, price = 4.55)

I see no reason why this shouldn't be possible. If a positional argument is mandatory (it is by definition) and the class is given (it is) then there is no reason why it would be error prone to access the properties of the positional argument in the definitions of the optional argument(s).

Current errors:

The default value of an optional parameter must be constant.dart(non_constant_default_value)
Undefined name 'productToEdit'.
Try correcting the name to one that is defined, or defining the name.

Proposed Fix:

  1. To allow the use of non-constant positional arguments
  2. (If required) to bring the name definition of madatory parameters forward in time to always predate the definition of optional parameters so it is in memory and ready to use.

A workaround is to do something like:

Product _editProduct(Product productToEdit,
      {String id,
      String title,
      String description,
      double price,
      String imageUrl}) {
    Map<String, dynamic> temp = {
      'id': productToEdit.id,
      'title': productToEdit.title,
      'description': productToEdit.description,
      'price': productToEdit.price,
      'imageUrl': productToEdit.imageUrl,
    };
    print(temp);
    ({
      'id': id,
      'title': title,
      'description': description,
      'price': price,
      'imageUrl': imageUrl
    }).forEach((k, v) {
      if (v != null) {
        temp[k] = v;
        print(v);
      }
    });
    print(temp);

    return Product(
        id: temp['id'],
        title: temp['title'],
        description: temp['description'],
        price: temp['price'],
        imageUrl: temp['imageUrl']);
  }

Which could then be called as:

onSaved: (value) {
                      _editedProduct = _editProduct(_editedProduct, title: value);
                    },
@HarvsG HarvsG added the feature Proposed language feature that solves one or more problems label May 4, 2020
@HarvsG HarvsG changed the title Allow optional defaults to be properties of manadtory positional parameters Allow optional defaults to be properties of mandatory positional parameters May 4, 2020
@eernstg
Copy link
Member

eernstg commented May 4, 2020

Note that #140 requests the same thing in a slightly more general form. I've added a reference to this issue there, to keep related things together.

@HarvsG
Copy link
Author

HarvsG commented May 4, 2020

Thanks @eernstg, that is helpful. I think the change in #140 is necessary for this solution but may not be sufficient. As the second error that is given is:

Undefined name 'productToEdit'.
Try correcting the name to one that is defined, or defining the name.

Proposed fix 2:

(May already be the case) to bring the name definition of madatory parameters forward in time to always predate the definition of optional parameters so it is in memory and ready to use.

@eernstg
Copy link
Member

eernstg commented May 5, 2020

@HarvsG, that's a matter of scoping: If we change parameter default values such that they can be expressions in a more general sense (rather than being constant expressions), there will be more declarations that can be in scope. In particular, we could allow default value expressions to refer to other parameters (as in your example).

However, we probably don't want to require that implementations must solve any recursive equations, or that they must run iterations until a fixed point is reached. We never promise that static analysis will detect non-termination, but we might want to prevent things like void foo([int x = y + 1, int y = x + 1]). So we might choose to prevent any references to parameters, or at least enforce that the dependency graph has no cycles.

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

2 participants