Coder Social home page Coder Social logo

Comments (3)

munificent avatar munificent commented on September 27, 2024

The analyzer may need to traverse several steps up the class heirarchy to check whether a class declaration is valid, but it already does this with the current base modifier:

This is true, but it never needs to traverse across multiple libraries. Traversing the hierarchy within a library is fairly reasonable, I think, because it's all one unit of code. If you can edit any of it, you can edit all of it. If you need to understand any part of it, you may need to understand the whole thing.

Extending that across libraries is something we did consider at some point during the design process, but I felt then and now that it's too brittle and too confusing.

In your example, with what you propose, imagine if at the point in time that class C was authored, A did not have base on it yet. The author of C believes they are writing a class that can be freely implemented, which it can at that point. Later, the author of A adds base, which is a breaking API change. But the author of C might not see the breakage because class C itself wouldn't be broken. It's just that every downstream class implementing C is now an error.

To avoid those kinds of situations, we felt it was better for every class that extends a base class to have to itself be explicitly marked base too. That makes it easier for someone looking at the class declaration to know what they can do with it. With the current design, when A is changed, the author of C discovers immediately that their own class's affordances have changed too and they are required to put base on it and advertise that fact to their downstream users.

You are definitely right that there's a weird edge case where you may need to traverse a chain of classes within a single library to determine if an implements is valid or not. I hope that users rarely run into this.

Figuring out the right set of modifiers, what guarantees they offer, and what constraints they require in order to meet those guarantees, was surprisingly hard given Dart's very permissive history. What we ended up with isn't as elegant as I'd hoped, but it's hard to get a good sense for whether there are tweaks we should make that would be an improvement or not.

from language.

nate-thegrate avatar nate-thegrate commented on September 27, 2024

Thanks for responding here.

What we ended up with isn't as elegant as I'd hoped, but it's hard to get a good sense for whether there are tweaks we should make that would be an improvement or not.

I completely identify with that conclusion.

At this point, I don't feel strongly about how the base keyword should behave—as of today, it isn't used at all in flutter/flutter or in my personal projects—but I'd still like to engage with the ideas shared here.



imagine if at the point in time that class C was authored, A did not have base on it yet. The author of C believes they are writing a class that can be freely implemented, which it can at that point. Later, the author of A adds base, which is a breaking API change. But the author of C might not see the breakage because class C itself wouldn't be broken.

You bring up a good point; I should amend my previous statement:

All of the guarantees from the Class modifiers documentation would still hold, as long as the base class isn't implemented within its own library.

In my mind, you'd be able do the following (though I don't know why you would want to):

base class A {}
class B extends A {}
class C extends B {}
class D implements C {}

and then another library could implement D:

class E implements D {} // compiles without issues

Adding the base modifier to A would break any class that implements A, B, or C without inheriting from A, but the error message would provide a solution:

class F implements B {} // error: the class 'A' can't be implemented outside of
                        // its own library because it's a base class.
class F extends A implements B {} // works!



It's kind of amusing to read the benefits of the base keyword and then watch the Flutter framework completely disregard them.

A new implemented member in a base class does not break subtypes, since all subtypes inherit the new member.

A new implemented member was added to ColorScheme and then cherry-picked into a stable release without any mention of potentially breaking subtypes.


All implemented private members exist in subtypes.

I wasted about half an hour trying to set up the following enum:

enum AppKey implements GlobalKey {
  screen1,
  screen2,
  screen3;

  GlobalKey get _key => GlobalObjectKey(this);

  @override
  BuildContext? get currentContext => _key.currentContext;
}

only to realize that GlobalKey relies on a _currentElement getter to function, and even if I define that getter in my enum, it doesn't work.


I could make a PR that adds the base keyword, but it wouldn't be worth it, since it'd involve adding the keyword to every GlobalKey subclass, and it could invalidate a class that would otherwise work fine:

class MyKey extends GlobalKey implements GlobalObjectKey {
 // ...
}



I feel like the right way to go is to remove the keyword requirement for subclasses:

  • It enables class C extends A implements B
  • In the case of GlobalKey (and other similar classes), it could greatly mitigate debugging frustration without any downsides
  • one less word to type!

At the same time, it just doesn't feel like the benefit is worth the hassle.

Though perhaps in the future there will be another language feature proposal that synergizes with this one :)

from language.

nate-thegrate avatar nate-thegrate commented on September 27, 2024

(hid my above comment because it was long 🙃)

#4041 was the proposal I had in mind to synergize with this one.

Since a base class with a base method guarantees that the method won't be overridden outside the declaring library, I imagine that the base keyword would start to see more use.

The additional flexibility proposed here would allow class C extends A implements B when A is a base class and B inherits from A, which I believe to be highly valuable.

Since the base class modifier's guarantees fail to hold if it were able to be implemented by a non-base class in the same library, I'll go ahead and modify the original proposal to prevent that problem.

from language.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.