Skip to content

[Class Modifiers] Should base be removable within the same library? #3108

@leafpetersen

Description

@leafpetersen

We chose in the design of class modifiers to enforce that base transitivity applies even within the same library. This isn't necessary - we could allow you to re-open classes to implementation within the same library, while still allowing enforcement of the same invariants. The argument against that was that it might be too easy to accidentally expose an interface that you didn't intend to.

Subsequently, we've had several use cases show up where there is some desire to not have base transitivity within the same library.

This issue describes one possible use case for a non-transitive base within the same library.

@jakemac53 ran into this again today when trying to design an approach to writing a final class while providing a mockable interface for testing. He found one clever but convoluted pattern using a sealed class with a factory constructor, implemented by a private implementation class and visible for testing public interface.

A simpler and more intuitive pattern would be something like the following:

base class FooService {}

@visibleForTesting
abstract interface class FooServiceForTesting implements FooService {}

This is forbidden by the current transitivity rules.

While this one use case is not definitive, it is interesting that we seem to be encountering uses for this. We could choose to change this - it would be non-breaking to do so. Should we consider dropping the requirement to make base transitive within the same library?

cc @dart-lang/language-team

Metadata

Metadata

Assignees

No one assigned

    Labels

    class-modifiers-laterIssues related to "base", "final", "interface", and "sealed" on classes and mixins, tbd later

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions