Base class with private members

418 views
Skip to first unread message

George Moschovitis

unread,
Oct 10, 2014, 4:35:41 PM10/10/14
to mi...@dartlang.org
It seems to me that Dart's peculiar library-level privacy system is rather problematic. 
For example, you cannot hide implementation details within a base class as the sub-classes can't access it's private members.
This leads to a bloated public interface.

Use case: a UI framework can't define a base Widget class with private methods, as they are not accessible from sub-classes (e.g. a FancyButton widget defined in a client application).

Any workarounds?

-g.

PS: This looks like an effective solution: https://code.google.com/p/dart/issues/detail?id=6119


Filipe Morgado

unread,
Oct 10, 2014, 5:25:00 PM10/10/14
to mi...@dartlang.org
I'd love to know a good workaround as well.

Official answer is probably to favor composition over of inheritance. But it rarely works in practice and has been biting me quite a lot.

Without language support, I don't think there's an easy solution.

Starts with underscore => library scope
Anything else => public
Maybe introduce a new prefix for protected members? I don't see any ASCII character that would do it.

Петър Събев

unread,
Oct 10, 2014, 6:38:39 PM10/10/14
to mi...@dartlang.org
This is the one thing I don't like too. Really need a solution for this...

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Don Olmstead

unread,
Oct 10, 2014, 7:17:59 PM10/10/14
to mi...@dartlang.org
With UI stuff I tend towards using mixins heavily to avoid this. I think it would be nice to have an @protected metadata that would at least warn when someone calls something marked as protected.

Lasse R.H. Nielsen

unread,
Oct 10, 2014, 8:19:00 PM10/10/14
to mi...@dartlang.org
Protected access is hard to define for a dynamic language.
That's why Dart's private names are statically and syntactically defined - when you write x._foo, the meaning of _foo only depends on the library it is in.
It doesn't depend on any inheritance chain or knowledge about the object being accessed.

I haven't found a good alternative. The choice I'd go for is to have package private fields and static access methods on the base implementation class. That way subclasses that know that they extend the base class can use the static methods to get access to the private parts, and other code can't see it directly.

It's not really protected inheritance, but it also doesn't leave public members visible. Non-subclass code will know that it's doing something iffy when it uses the static members that carry big warnings saying "ONLY USE FROM SUBCLASSES".

But then, experience tells me that it won't stop anybody in practice :)

/L


--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.



--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

George Moschovitis

unread,
Oct 11, 2014, 12:26:29 AM10/11/14
to mi...@dartlang.org
What's the problem with introducing the @protected annotation and adding special handling for this in the editor?

George Moschovitis

unread,
Oct 11, 2014, 1:59:20 AM10/11/14
to mi...@dartlang.org
How do Mixins help here? Can you elaborate?

George Moschovitis

unread,
Oct 11, 2014, 2:17:38 AM10/11/14
to mi...@dartlang.org
I haven't found a good alternative. The choice I'd go for is to have package private fields and static access methods on the base implementation class. That way subclasses that know that they extend the base class can use the static methods to get access to the private parts, and other code can't see it directly.

Can you give a small example?

Lasse R.H. Nielsen

unread,
Oct 11, 2014, 7:51:59 AM10/11/14
to mi...@dartlang.org
On Sat, Oct 11, 2014 at 8:17 AM, George Moschovitis <george.mo...@gmail.com> wrote:
I haven't found a good alternative. The choice I'd go for is to have package private fields and static access methods on the base implementation class. That way subclasses that know that they extend the base class can use the static methods to get access to the private parts, and other code can't see it directly.

Can you give a small example?

abstract class ListDelegate<T> implements List<T> {
  List<T> _base;
  ListDelegate(this._base);
  /// USE ONLY IN SUBCLASSES.
  static List protectedBase(ListDelegate delegate) => delegate._base;
  int get length => _base.length;
  ....
}

then another library can do:

class MyListDelegate<T> extends ListDelegate<T> {
   MyListDelegate(List<T> base) : super(base);
    
   someExtraOperation() {
      var base = ListDelegate.protectedBase(this);
      doSomethingWithBase(base);
   }
}
  
without exposing the base field as public.
Malicious code can still get to the base, if it knows about ListDelegate, but it won't see it just by looking at the object - but malicious code running in your isolate can do anything anyway. 
But if someone deliberately breaks the abstraction, they can't claim that they didn't know.

/L

 

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Eric Leese

unread,
Oct 12, 2014, 2:41:57 AM10/12/14
to mi...@dartlang.org
Object-protected inheritance could be defined in Dart.  Feature request is at https://code.google.com/p/dart/issues/detail?id=3193.  The reason it works is because the type of this is always statically known in Dart and so it can be statically determined when a protected method is being called or being overridden.  You would not be able to call a protected method on a different object of the same class.

George Moschovitis

unread,
Oct 12, 2014, 5:36:24 AM10/12/14
to mi...@dartlang.org
That's awful!

George Moschovitis

unread,
Oct 12, 2014, 5:38:49 AM10/12/14
to mi...@dartlang.org
I don't really need full, runtime protected fields. The @protected annotation solution (as described here:  https://code.google.com/p/dart/issues/detail?id=6119) would be enough.
And actually it feels quite Dartish, similar to optional typing: like types, privacy is reduced to a static, compile/development time concern.

-g.

Filipe Morgado

unread,
Oct 12, 2014, 2:11:04 PM10/12/14
to mi...@dartlang.org
Fully agree.

On Sunday, 12 October 2014 10:38:49 UTC+1, George Moschovitis wrote:
I don't really need full, runtime protected fields. The @protected annotation solution (as described here:  https://code.google.com/p/dart/issues/detail?id=6119) would be enough.
And actually it feels quite Dartish, similar to optional typing: like types, privacy is reduced to a static, compile/development time concern.

-g.

Fully agree.

Lasse R.H. Nielsen

unread,
Oct 12, 2014, 2:32:17 PM10/12/14
to mi...@dartlang.org
On Sat, Oct 11, 2014 at 6:26 AM, George Moschovitis <george.mo...@gmail.com> wrote:
What's the problem with introducing the @protected annotation and adding special handling for this in the editor?

I'm not sure how it would work.

If you have 
  class Base {
    @protected
    void add(element);
  }

  and

  someOtherFunction(var x) {
    x.add(42);
  }

will the call "x.add(42)" cause a warning? Or will you only get warnings for cases where x is statically typed as Base or a subclass of Base?

The former makes no sense, and the latter only works if you type annotate everything.

/L
-- 

Anders Holmgren

unread,
Oct 12, 2014, 3:18:43 PM10/12/14
to mi...@dartlang.org
"the latter only works if you type annotate everything"

That's true of most things isn't it? If you want warnings you need to type annotate things or have the analyser determine the propagated type. 
Would this be any different?

I have been struggling with this issue a lot at the moment with code that's all within the one package. Basically there is code that I want subclasses to be able to access / override but I don't want objects using the class to have access to.

I seem to be faced with three options
  1. Massive libraries using 'part of' 
  2. Making things public that shouldn't be
  3. Duplicating code
None of these are attractive. I have mostly settled for option 3 and trying to limit the duplicated code by factoring the meat of them into reusable helpers

As I am wanting to override code the object based protected approach wouldn't work

George Moschovitis

unread,
Oct 12, 2014, 4:25:11 PM10/12/14
to mi...@dartlang.org
"the latter only works if you type annotate everything"

That's true of most things isn't it? If you want warnings you need to type annotate things or have the analyser determine the propagated type. 
Would this be any different?

Exactly. If the analyzer can't deduce a type (explicit or propagated) I wouldn't expect a static warning. 
Again, looks like the standard Dart trade-off  to me.

-g.

Alex Tatumizer

unread,
Oct 12, 2014, 7:18:07 PM10/12/14
to mi...@dartlang.org
@Lasse:
Please recall that the complaint was about private members not visible from subclasses. Unless I misunderstand the issue completely (which might happen, of course), there's an obvious solution that doesn't lead to any paradoxes.

First, let's observe that the the following definition:
someFunc(var x) {
  x._foobar();
}
doesn't cause any warning in dart editor, though _foobar is nowhere to be seen in this library at all.
However, the absence of warning doesn't mean it will work in runtime, because, according to spec
"Any attempt to access a private member declaration from outside L will cause a method, getter or setter lookup failure"

And indeed, if we define class X with private method _foobar in a different library, and call someFunc(new X()) - it will fail with noSuchMethod exception.

Keeping that in mind, let's forget the word "protected" - it has some connotations from java which are not relevant here.
Let's find another word. Just for the sake of argument, let's name it "@visibleFromSubclasses". When applied to private member, it makes it visible from methods of subclasses ("visible" in a specific sense- see below). When applied to public members, it does nothing at all.
Examples:
class Base {
    @visibleFromSubclasses
    void _bar() { ...}
  }
class Derived extends Base {
   foo() {
      _bar(); // OK - compiler can prove the access is OK
      myClosure() {
          _bar(); // OK - compiler can prove the access is OK
      }
   }
}
someFunction(var x) {
   x._bar(); // no warning, but will fail in runtime, like it does now. 
}

The difference is: when compiler can prove by static analysis that, due to annotation, private member is accessible from the point of invocation, it generates special code that prevents checking for the same
library in runtime. If it can't prove that, it treats it like access to normal private member, which may cause noSuchMethod in runtime.

Does it make sense?


Filipe Morgado

unread,
Oct 12, 2014, 7:32:38 PM10/12/14
to
I'd like to add that it's not only about accessing private members, but mostly about overriding non-public methods (methods that are called by private superclass code).

Lasse R.H. Nielsen

unread,
Oct 13, 2014, 3:07:16 AM10/13/14
to mi...@dartlang.org
On Sun, Oct 12, 2014 at 9:18 PM, Anders Holmgren <andersm...@gmail.com> wrote:
"the latter only works if you type annotate everything"

That's true of most things isn't it?

Not package private names - they just work everywhere.
If we try to make a "private" access control, I would expect it to work just as well.

I'm worrying that an annotation that can only warn if it sees someone knowingly using a protected value from outside a subclass, isn't really going to catch the cases that really matter, and the name is suggestive of a more restrictive.
 
If you want warnings you need to type annotate things or have the analyser determine the propagated type. 
Would this be any different?

It is different from private members, and that is what it is going to be compared to.

I can see a real solution, but I'm not convinced that annotations is sufficient.
 
I have been struggling with this issue a lot at the moment with code that's all within the one package. Basically there is code that I want subclasses to be able to access / override but I don't want objects using the class to have access to.

What is the exact problem you are trying to solve?
- Cooperating programmers misusing a protected method, i.e., in your own code base? Deliberately or accidentally?
- Foreign code accidentally using a protected method, e.g., in a library using mirrors?

The annotation will not help with the second problem.
It will only work for the accidental case of the first problem. Deliberate access is always possible (even with a perfect "protected" implementation, because you can always make a subclass in Dart:  
  class Trick implements Yourclass { static getIt(YourClass o) => o.protectedMember; }


I seem to be faced with three options
  1. Massive libraries using 'part of' 
This doesn't solve the first problem where the misuse is in your own code, if all your code is in one library anyway.
  1. Making things public that shouldn't be
Again, what is the problem with the method being public?

Would it be sufficient to have the public facing library exposing the public interface, and an implementation library with the implementation. Public methods in the implementation that are not in the interface, will cause warnings for any user only importing the public interface versions. Subclasses can do the same thing, only exposing the public interface.

Example:

library foo;
import "fooimpl.dart";
abstract class Foo<T> {
  factory Foo(T thing) = FooImpl;
  T get thing;
}

library fooimpl;
import "foo.dart";
class FooImpl<T> {
  T thing;
  FooImpl(this.thing)



library subfoo;
import "foo.dart";
import "subfooimpl.dart";
abstract class SubFoo extends Foo<int> {
  factory SubFoo(int value) = SubFooImpl;
  void increment();
}

library subfooimpl;
import "fooimpl.dart";
import "subfoo.dart";
class SubFooImpl extends FooImpl<int> implements SubFoo {
  SubFooImpl(int value): super(value);
  void increment() { thing++; }
}
  1. Duplicating code
Yes, that's sad. 
 
None of these are attractive. I have mostly settled for option 3 and trying to limit the duplicated code by factoring the meat of them into reusable helpers

As I am wanting to override code the object based protected approach wouldn't work

What is the "object based protected approach"?

/L

Lasse R.H. Nielsen

unread,
Oct 13, 2014, 3:32:47 AM10/13/14
to mi...@dartlang.org
On Mon, Oct 13, 2014 at 1:18 AM, Alex Tatumizer <tatu...@gmail.com> wrote:
@Lasse:
Please recall that the complaint was about private members not visible from subclasses. Unless I misunderstand the issue completely (which might happen, of course), there's an obvious solution that doesn't lead to any paradoxes.

First, let's observe that the the following definition:
someFunc(var x) {
  x._foobar();
}
doesn't cause any warning in dart editor, though _foobar is nowhere to be seen in this library at all.
However, the absence of warning doesn't mean it will work in runtime, because, according to spec
"Any attempt to access a private member declaration from outside L will cause a method, getter or setter lookup failure"

And indeed, if we define class X with private method _foobar in a different library, and call someFunc(new X()) - it will fail with noSuchMethod exception.

Yes. Private names are really different names for each library they are used in. The VM implements library private names by adding a library-dependent suffix to the name, so they really are different vaiable names.
 
Keeping that in mind, let's forget the word "protected" - it has some connotations from java which are not relevant here.
Let's find another word. Just for the sake of argument, let's name it "@visibleFromSubclasses". When applied to private member, it makes it visible from methods of subclasses ("visible" in a specific sense- see below). When applied to public members, it does nothing at all.
Examples:
class Base {
    @visibleFromSubclasses
    void _bar() { ...}
  }
class Derived extends Base {
   foo() {
      _bar(); // OK - compiler can prove the access is OK
      myClosure() {
          _bar(); // OK - compiler can prove the access is OK
      }
   }
}
someFunction(var x) {
   x._bar(); // no warning, but will fail in runtime, like it does now. 
}

The difference is: when compiler can prove by static analysis that, due to annotation, private member is accessible from the point of invocation, it generates special code that prevents checking for the same
library in runtime. If it can't prove that, it treats it like access to normal private member, which may cause noSuchMethod in runtime.

Does it make sense?

It makes sense. It won't work with the way library private names work, but if we ignore that, and say that "@protected _x" is a different type of variable than a library private one, then it might be made to work. For that reason, I'd prefer to not use a prefix "_" for the name.

Does it work through interfaces? Probably not. This is purely about implementation sharing through inheritance.

That means it should only work through this references
It's not OK if your Derived class had:
  static myStaticClosure(Derived x) => x._bar();
That use of "_bar" could be on a class which doesn't extend Base.


So, I'm getting to a possible implementation where:

  class A { protected int x; }
  class B extends A {
    foo() => this.x;  
  }

introduces a field *not* named "x", but named, e.g., "protected@x" or something similar syntactically impossible.
Having a "this.x" or "super.x" access in a subclass extending A (and not overridden to be public) is changed to "this/super.protected@x".

It still collides with non-protected names with the same "name".
class A { protected String x; }
class C { int get x; }
abstract class D extends A implements C {
   bar() => this.x;   // inherited from A or overridden in C?
}
In this case the "x" should refer to the one in "C". A subclass might implement C's "x' getter, and then D's bar method should work.
It would be better if protected names were really different, like private ones.

How about:

class A { String :x; }  // protected name
class C extends A { bar() => this:x; /`* or :x */}  // Only accessible through "this".

That also means that you don't get access to the member at the class level, you only get access to the member on the same object. I actually *like* that.


Alex Tatumizer

unread,
Oct 13, 2014, 9:38:11 AM10/13/14
to mi...@dartlang.org
That also means that you don't get access to the member at the class level, you only get access to the member on the same object. I actually *like* that.

Yes! BTW, I remember when I was learning C++ I was a bit surprised that "private" is not object-private, but class-private, and there's no way to express object-private at all.
Which is strange. In real world, object would be quite reluctant to share access to field "myMoney" with other objects, even though they might be instances of the same class.


Eric Leese

unread,
Oct 13, 2014, 3:18:46 PM10/13/14
to mi...@dartlang.org
@George
Actually this makes it feel not-Darty to me.  Because now you *have* to type annotate all of your local variables, or all protected methods are public.  Dart is supposed to work fine if everything is a var.  The point of type annotations is to enhance code clarity and to turn run-time errors into compile-time errors; they shouldn't be necessary to make things errors at all.  Library privacy does not rely on type annotations for enforcement and neither would object protection.

@Anders


As I am wanting to override code the object based protected approach wouldn't work

If you a referring to the approach described in feature request 3193, it would work fine with overrides.

Anders Holmgren

unread,
Oct 13, 2014, 8:11:44 PM10/13/14
to mi...@dartlang.org


On Monday, 13 October 2014 18:07:16 UTC+11, Lasse Reichstein Holst Nielsen wrote:



It is different from private members, and that is what it is going to be compared to.

I can see a real solution, but I'm not convinced that annotations is sufficient.

Fair enough. BTW I'm not advocating the annotation approach. I just want protected methods in general
 
 
I have been struggling with this issue a lot at the moment with code that's all within the one package. Basically there is code that I want subclasses to be able to access / override but I don't want objects using the class to have access to.

What is the exact problem you are trying to solve?
- Cooperating programmers misusing a protected method, i.e., in your own code base? Deliberately or accidentally?

This case. Specifically being able to maintain a clear separation between the public contract of a class and the internal implementation details of the class hierarchy without having to introduce interfaces for everything.
 


I seem to be faced with three options
  1. Massive libraries using 'part of' 
This doesn't solve the first problem where the misuse is in your own code, if all your code is in one library anyway.

What I meant was that where I currently have say 5 libraries of components I could merge that into one library so that base classes can be reused.

The classes that are the end users of these components will be in separate libraries. 
 
  1. Making things public that shouldn't be
Again, what is the problem with the method being public?

Would it be sufficient to have the public facing library exposing the public interface, and an implementation library with the implementation. Public methods in the implementation that are not in the interface, will cause warnings for any user only importing the public interface versions. Subclasses can do the same thing, only exposing the public interface.

Yes I agree this as a clean and effective approach (and was intending to include this as option 4 but forgot) but it is also a heavy weight approach. Having to maintain separate interface classes creates a lot of extra work. For some things this makes sense but for others it's a pain. 

The libraries I am dealing with at the moment are models (mainly view models) and I've never been a fan of interfaces for models, particularly as there tends to be a lot of them. As opposed to say services.

Anders Holmgren

unread,
Oct 13, 2014, 8:15:47 PM10/13/14
to mi...@dartlang.org
Yes it was and that is good to know. I'm not overly familiar with object protected inheritance but on the surface it seems sensible to me 
 

George Moschovitis

unread,
Oct 14, 2014, 4:17:56 PM10/14/14
to mi...@dartlang.org
Would it be sufficient to have the public facing library exposing the public interface, and an implementation library with the implementation. Public methods in the implementation that are not in the interface, will cause warnings for any user only importing the public interface versions. Subclasses can do the same thing, only exposing the public interface.

Ah, that's actually a good workaround. Thank you.

-g.

George Moschovitis

unread,
Oct 15, 2014, 3:44:40 AM10/15/14
to mi...@dartlang.org
>   factory Foo(T thing) = FooImpl;

Is this idiom documented anywhere? i.e.

factory ... = ...


Lasse R.H. Nielsen

unread,
Oct 15, 2014, 4:22:36 AM10/15/14
to mi...@dartlang.org
It's what the language specification calls a "delegating factory constructor".
For normal factory constructors it's equivalent to
  factory Foo(T thing) => new FooImpl(thing);
but it is needed for forwarding const constructors:
  const Bar(x) = BarImpl(x);
because you can't have a body in a const constructor.

/L

George Moschovitis

unread,
Oct 24, 2014, 5:56:24 AM10/24/14
to mi...@dartlang.org
Interestingly, TypeScript will add protected members:


seems the concept is not that incompatible with a dynamic language / run-time type system.

Vyacheslav Egorov

unread,
Oct 24, 2014, 7:26:32 AM10/24/14
to General Dart Discussion
TypeScript's type system is not a dynamic - it exists only during compilation. Types are nowhere to be seen after compilation.

class A {
    private secret: string;
    constructor() { this.secret = "haha"; }
}

function foo(o) { return o.secret; }  // no compile time error, no runtime error -> "haha"

var x = new A();
console.log(x.secret);  // compile time error
console.log(foo(x));  



// Vyacheslav Egorov

--
Reply all
Reply to author
Forward
0 new messages