-
Notifications
You must be signed in to change notification settings - Fork 214
Protected instance members #3825
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
Comments
I don't really understand this paragraph. why can they be shadowed? and why aren't they virtual? class A {
protected void protectedFunc(){
print('in A');
};
void init(){
protectedFunc();
}
}
class B extends A{
@override
protected void protectedFunc(){
print('in B');
}
}
B b;
b.init(); // -> should call B.protectedFunc() and not the one of A |
A virtual method is late-bound, the actual implementation chosen based on the runtime type of the receiver it's called on. An interface method is basically the same in Dart. (Java has separate JVM instructions for interface invocations and virtual instance member invocations because they have separate Now, the question is whether this is the correct design. Your example would print That's actually much more useful. (Aka: Doh! Why didn't I see that.) I'll see when I can find time do an update :) |
I agree that it's a good idea if it prints |
The title still says "non-virtual", but the second edition never mentions the word "virtual" again. In what sense are they non-virtual? It looks like their virtualness is the same as that of normal methods - they are just visible only to subclasses. If that's not the case, some examples could help. |
virtual doesn't only mean visible into subclasses but also overridable at least for my understanding but the "non" should then be removed from the title. |
I know this proposal is not directly related to this, but if we are ever going to have As you yourself say, similar things should look similar. Having the |
I would love to see that. Especially as it looks totally ugly to use _properties as constructor and there is even a lint discouraging it so you need initilizers.
Am 22. Mai 2024, 20:30 +0200 schrieb Mateus Felipe C. C. Pinto ***@***.***>:
… I know this proposal is not directly related to this, but if we are ever going to have protected members, we should probably want to deal with private.
As you yourself say, similar things should look similar. Having the _ prefix meaning private and an actual protected prefix will probably look too asymmetrical, and also be confusing to people non-familiar with the language (IMO, the _ prefix is already confusing).
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.Message ID: ***@***.***>
|
There are different scopes of privacy. "protected" is also kind-of-private, but it's private for the class and all the descendants. Does dart have a concept of package-private sub-packages (libraries)? The fact that the libraries in (should Regardless, I find |
@tatumizer I agree, that it would make sense to have |
Fixed title to not admit first version was non-virtual. Dart currently has no other privacy than library privacy. By first-party privacy I mean access protection against code not written by the same author, but letting the author themselves ignore it. With library privacy, the author gets to decide the granularity. Protecting against the same author, who can change the code, it's not as big a priority. Having class private declarations is more about avoiding accidental name clashes between implementation details, than actually protecting against access, file/library protection is sufficient for the latter. |
I was talking more about syntactic similarities. I actually don't dislike the fact that we have library privacy. You can do anything we can do with what a I was talking specifically about syntax. Having one as a name prefix ( |
A prefix The reason to use a name prefix for library privacy is instance members, and dynamic invocation in particular. If two classes in a superclass chain both introduce a private name, then the two are considered different names.
For With the leading For But all the good name prefixes are taken. |
This means that you're proposing doing "instance protected" versus "class protected" like other OOP languages I'm familiar with do (C++, C#, Java). Is that a deliberate choice? For what it's worth, I have often found it useful to be able to call protected members on other instances of the surrounding class. We essentially have that capability in Dart with private members because of library privacy (although not up the superclass chain of course). So it feels a little strange that you could call a private method on some other instance of your own class, but not a protected method on that same instance. (This also raises the question of whether you can have private + protected methods and whether that is a useful combination.) |
Yes. I have always believed that to be a better match for Dart because of two things: dynamic invocations and not having interface declarations. Class based The alternative would be to just make protected members inaccessible in dynamic invocations, which they are in this design anyway. It just feels like a missing feature then, not a logical design consequence. But possible. Being "inside a subclass" does not give not protection you might expect if one can simply Another difference is that Dart cannot declare an inherited protected member as The way this is specified, access only directly on That does mean no protected static members. Again, when you can implement any class, class-based protected statics it's not much of a protection. You can have private protected members, but it's not really useful. It doesn't make much sense, since outside the library they will just be private and inaccessible. You're only protecting against yourself. |
Uh oh!
There was an error while loading. Please reload this page.
This is an attempt at a full feature specification for protected instance members, as another solution to #835.
Edit: And this is version 2 where the protected members can be overridden by subclasses.
Dart protected instance members
Dart has only one notion of declared access restriction: Library privacy.
Having private names solves two problems: Avoiding internal implementations having name clashes with third-party code, and ensuring what third-party code is able, and not able, to access, which makes it easier to ensure invariants.
Since the author controls the size and scope of a library, and is expected to be fully cooperative with all code they have the power to modify anyway, that’s a rather sweet spot of privacy. By scoping a library to a single class, or to what would be an entire directory of files in another language, the author can choose anything between class privacy and “package privacy”. It’s an accessibility where the author can control the scope.
One accessibility feature that other object oriented languages have, and that Dart cannot emulate with library privacy, is protected access: Instance members of a class which can only be accessed from subclasses which extend that class.
Protected members are useful for reusable libraries. A library can expose a base or skeleton class that third-party subclasses can extend to provide customized classes. However, if the subclass needs to interact with the base class, it can currently only do so if the base class exposes public API, which then contaminates the public API of the subclass with operations that end-users shouldn’t be using.
Dart provides the
@protected
annotation which makes the analyzer warn if a non-subclass invokes the annotated member. That’s not a safe solution, the API is still public and accessible, anyone can choose to ignore the warning.Instance protected members
We add instance members that can only be accessed and invoked by subclasses. Such a member can be declared in a
class
,enum
ormixin
declaration. It’s available to any class which has theclass
orenum
, or an application of themixin
, in its superclass chain. This includes the class itself — and for enums, nothing else.Syntax
The immediate choice is to make
protected
a built-in identifier and use it as a modifier on any instance member declaration:Since protected members cannot be static, we just have to decide where it goes relative to other modifiers. Let’s say after
external
, beforeabstract
, approximately the same place asstatic
.Let’s go with this, it can be changed if we have a better idea.
The grammar is updated to allow
protected
on any non-static, non-constructor member declaration. (Grammar taken fromDart.g
, skipping theaugment
declarations for now. They may or may not need to repeat theprotected
.):Semantics
We ensure that the modifier is only allowed where it makes sense. We introduce the following new rules and changes, with anything not mentioned assumed to work the same for protected members as for any other instance member.
class
,mixin
orenum
declaration. (Not allowed insideextension
orextension type
declarations.)class
,enum
ormixin
declaration declares a protected member, and any superinterface of the containing declaration has a non-protected member signature with the same name. If a member is already public, the protected declaration is misleading and probably an error.protected
.The behavior of a correctly declared protected member is:
A protected member declaration works just like any other instance member declaration, except that the member signature it introduces into the interface is protected, unless any superinterface has a non-protected member with the same name. Protected interface members are special wrt. accessibility and inheritance through
implements
, but otherwise work as normal. An interface member can only be protected if all super-interface members of the same name are protected, otherwise it falls back to being “public”.The combined super-interface of a
class
,mixin
,enum
orextension type
declaration is computed almost like today, except:implements
clause are omitted. (If the implementation is not inherited, nor is the protected interface member signature.)This computation affects the interface of the declaration itself, if it does not declare any members with the same name. It also affects the members available to a mixin through its
on
types. A mixin has a protected member if itson
type does.A protected member is considered inaccessible when accessed through a typed member invocation for any receiver other than
this
. DoingFoo o = ...; o.id();
whereFoo
's interface has a protected member namedid
, is a compile-time error, becauseFoo
does not have an accessible member namedid
.A protected member cannot be invoked through a dynamic invocation either. In a dynamic invocation, if an instance member is found which is protected in the interface of the receiver’s runtime type, dynamic invocation treats it as an inaccessible member and invokes
noSuchMethod
(it’s anoSuchMethod
-thrower).Protected members can only be invoked through
super
orthis
invocations (including the implicitthis.
for plain identifiers that are not in the lexical scope).If invoked through
super
, a protected member works just like any othersuper
member invocation, directly invoking the implementation of the member. Super member invocations do not use the interface of the superclass, but directly invokes the implementation. They ignore whether a member is protected.super
-member invocation can invoke a protected member of anon
type. As usual, anysuper
-member invocation in a mixin requires all concrete superclasses the mixin is applied to to have a valid implementation of that member.If invoked through
this
, a protected member works just like any other instance member invocation, except that it does not consider protected members as inaccessible.Summary
protected
, on any instance member of aclass
,mixin
orenum
, which marks it as protected in the class interface.this
orsuper
. That’s what the flag is used for, disallowing any other invocations.implements
, only through superclass relation.protected
declaration of the same name. Once public, always public.The text was updated successfully, but these errors were encountered: