Skip to content

Language proposal for getting rid of the interface ambiguity of a class with private members #4666

@acarstoiu

Description

@acarstoiu

I have reviewed the discussion in #4348 and pondered for a solution to the problem of the two interfaces that a class with own private members has:

  • inside the containing library, the interface includes the private members
  • outside, it does not.

This flaw is what makes possible that code from the same library, reachable from outside (through exports), taking as input an object of the said class, may discover that the private members are missing from the received object because its type is simply an implementation the public interface.

Illustration (common knowledge)

/* This is 'a.dart'. */

class I {
  int get a => 10;

  void _do() {
    print("Doing stuff in I");
  }
}

class II {
  void _do() {
    print("Doing stuff in II");
  }
}

void doWith(I i) => i._do();
/* Run this file.*/

import "a.dart";

class AI /*extends II*/ implements I {
  @override
  int get a => 11;

  void _do() {
    print("Doing stuff in AI");
  }
}

void main() {
  doWith(AI());
}

The code above throws NoSuchMethodError.
Off topic, can anyone explain why the code works and prints Doing stuff in II if the comment delimiters around extends II are removed? 🤨 Is the compiler happy with any implementation of the private method _do(), as long as it originates from the same library, namey the totally unrelated class II

Proposal

Just go bold with the considerations made in this doc section (yeah, I discovered afterwards that my idea wasn't that original): any class (or mixin) with own private members should be implicitly marked with the base modifier. As this modifier is infectious (i.e. it applies to all inheriting classes, be them direct or indirect descendants), the containing library's code will never get unpleasant surprises with objects passed from outside.

If the class in question is not exported (including private), no harm is done. If the class is exported, any implementation outside the containing library will turn into broken code and require refactoring, which is not trivial when the implementing class already extends some other class (than Object).

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureProposed language feature that solves one or more problems

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions