Skip to content

Named parameters in constructors for private fields isn't straightforward. #1613

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

Closed
mayurdhaka-suryasoftware opened this issue May 5, 2021 · 3 comments
Labels
request Requests to resolve a particular developer problem

Comments

@mayurdhaka-suryasoftware
Copy link

mayurdhaka-suryasoftware commented May 5, 2021

My use case is the following (illustrated via a contrived example):

class Point {
  // Note these variables are private
  final double _x;
  final double _y;

  // Note that I am using named variables.
  Point({first, second}) {
    this._x = first;
    this._y = second;
  }
}

That is, I have two private variables that I would like to keep final as well (because of all the benefits of immutable references).

I would like to offer a named constructor for my class as shown above. However, I have not found this to be possible. (Perhaps I am missing something?)

This is possible in Swift, for example:

struct Point {
    private let x: Double;
    private let y: Double;

    init(first: Double, second: Double) {
        x = first
        y = second
    }
}

I have found a workaround however:

class Point {
  final double _x;
  final double _y;

  Point._internal(this._x, this._y);

  Point({first, second}) : this._internal(first, second);
}

Basically, I would like to work with my class in the original way I'd imagined (private and final members), and also expose a nice initialisation API to consumers.

@mayurdhaka-suryasoftware mayurdhaka-suryasoftware added the request Requests to resolve a particular developer problem label May 5, 2021
@Cat-sushi
Copy link

You can write,

class Point {
  final double _x;
  final double _y;

  Point({first, second}): this._x = first, this._y = second;
}

You can also write,

class Point {
  late final double _x;
  late final double _y;

  Point({first, second}) {
    this._x = first;
    this._y = second;
  }
}

@lrhn
Copy link
Member

lrhn commented May 5, 2021

Do use the initializer list version when possible. You can even omit the this:

Point({double first, double second} : _x = first, _y = second;

We don't allow you to have named parameters using private names. It would make that parameter unspeakable from other libraries. (We could probably allow it in private methods, but decided that it's just not that useful, so the effort needed to make an exception was not worth its own weight. It's only really constructors with initialing formals where it matters, because you want to write this._x, and you'll just have to write a normal parameter and an initializer list entry there).

The late final double _x introduces a setter to the interface. Since it's a private name, that won't affect users of the class, but it is an unnecessary overhead. Using late is like using dynamic — occasionally necessary, but something which should be avoided when it's not necessary, and when used, it should be well encapsulated so your class's clients won't see it.

@mayurdhaka-suryasoftware
Copy link
Author

Do use the initializer list version when possible.
This is basically what I wanted, thanks!

@Cat-sushi @lrhn
Thanks for the help.

Closing this now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

3 participants