-
Notifications
You must be signed in to change notification settings - Fork 212
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
Private to this
#3816
Comments
Note that #2918 proposes that every private instance member should be made private to (Note that non-private instance members can also be private to |
Maybe I misunderstand what you mean by private to class A{
A(this.privateMember);
private final privateMember:
} without the need to use initializers to assign constructor parameters to I would even argue that library privacy that we get with |
Right, a I'm not convinced that those two concepts need to be tied together that firmly. For instance, it would make sense to me that operator That wouldn't be a problem, though, if the two features are provided separately: We could then choose to make any particular About this example: class A {
A(this.privateMember);
private final privateMember:
} We can do this today: class A {
final _member:
A(this._member);
} Some people really don't like the idea that However, with named parameters we do have a difficulty: It is a compile-time error for a named parameter to have a name that starts with We have a proposal that has substantial support from the language team (I think we just didn't have enough time to get it done, and I think something like that will happen): #2509 (comment). If that proposal is accepted then we can do this: class A {
final _member:
A({this._member}); // Invoked as `A(member: someValue)`.
} With these small tools in mind, we shouldn't need to move elephants like privacy around willy-nilly just so we can have a nicer parameter declaration syntax.
True. We could consider things like package wide scopes (that is, "private to the set of libraries that are located in the |
I think your example of the IMHO we only need library privacy because we have no Having a And having a |
I think library privacy ( Being private to class A<X> {
final X Function(X) this.transform;
X value;
A(this.transform, X initialValue) : value = initialValue;
void foo() {
...
value = transform(value); // Type safe!
...
}
}
void main() {
A<num> a = A<int>(42);
a.transform(a.value); // Would throw, but is now a compile-time error.
} The point is that we can safely use expressions involving the type I think the ability to restrict a given member to be private to I haven't had an urgent need for a member to be |
A Protected comes up when you write libraries with base or skeleton classes that others are expected to build on, to create public facing APIs for some third party. There are ways, usually involving library private members and public extension members forwarding to the private members, where the second author then doesn't expose those extensions. But it's cumbersome, and if the third party author happens to import the extensions for another reason, they'll still be there. |
Consider a non-covariant member, as described in dart-lang/sdk#57371. That is, roughly, an instance member of a class whose return type has a non-covariant occurrence of a type parameter from the enclosing class/mixin/enum/etc.
For example, in
class A<X>...
it could be a method or getter whose return type isvoid Function(X)
, or a variable whose declared type isList<X> Function(X)
.Such members are dangerous, in the sense that any reference to the member will give rise to a run-time type error if the statically known value for said type parameter differs from the run-time value:
In this example, the statically known value of
X
ina
isnum
, but the run-time value isint
. Those two types differ, soa.fun
throws. We can try to call it with a value which is actually ok for the run-time value ofX
(likea.fun(10)
), but we won't even reach the point where the type correct actual argument is passed to the function, because the expressiona.fun
will throw before we even get hold of the function object.I've created a proposal for a lint, dart-lang/sdk#59050, which would flag every non-covariant member.
However, a non-covariant member can be used in a type safe manner with an extra constraint: When the receiver of the access is
this
, the given type variable is in scope, and type checking can be performed safely:We can easily enforce that all accesses to a given member must occur with
this
as the receiver, we just need to specify in the declaration of the given member that it has this constraint.As a strawman syntax, I'll use
this.
in the declaration of an instance member in order to indicate that this member is "private tothis
".The ability to constrain the allowed set of receivers to
this
can be useful in other ways, too. For example, this particular notion of privacy could be useful based on software engineering considerations (like maintainability, readability, enforcement of application domain specific constraints, etc.).Note that being private to
this
and being private are orthogonal concepts (where the latter is the normal, Dart privacy which is specified via names of the form_...
). That is, we can have declarations that are not private at all, that are private tothis
, that are private (in the normal sense), or that are private and private tothis
; each of those 4 combinations have their own properties.One reason to use privacy to
this
which is technical as well as relevant from a software engineering perspective is that it is much safer to use a private member (in the usual sense) if it is also private tothis
:At the invocation of
_foo
, it is known thatthis
has type_B
or a subtype thereof, and it is possible to detect through analysis of the current library whether or not we can know that every subtype of_B
has an implementation of_foo
.The name
_foo
is only accessible in the same library, and this means that we can check every invocation, to see that it occurs in a location where it is guaranteed thatthis
has an implementation of_foo
. That's not true if_foo
is invoked in the body ofA
because some other library could create a concrete subtype ofA
that does not have an implementation of_foo
. If that is true then this invocation is safe; if it is not known to be true then we may encounter a 'no such member' failure at run time.The point is that if an instance member is private to
this
then it is a lot easier to establish some level of trust in the assumption that said member actually exists at each call site, up to a situation where it is a firm guarantee.Based on these considerations, I think it may be worthwhile to support the notion of instance members that are private to
this
.The text was updated successfully, but these errors were encountered: