-
Notifications
You must be signed in to change notification settings - Fork 44
Add a mechanism to define the default flags of members #402
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
Conversation
The refactoring of how modifiers are applied by default very much LGTM! I also see you opted for ergonomic defaults (classes/interfaces/methods I'm not sure about the utility of the public API to change the defaults though, especially with the ergonomic defaults. If I think about what I might want to do, I can imagine:
That's all I can think of. I can't see anyone wanting to add any other modifier by default. If we really need to expose an API, something like this might be enough? public interface DefaultsConfigurator {
/**
* Classes and interfaces are package-private by default. If not called, they are {@code public} by default.
*/
void typesPackagePrivate();
// alternatively, we could have: types(AccessLevel)
/**
* Methods on classes have the given {@code accessLevel} by default. If not called, they are {@code public} by default.
* Methods on interfaces have a pre-determined access level that cannot be changed.
*/
void methods(AccessLevel accessLevel);
/**
* Fields on classes have the given {@code accessLevel} by default. If not called, they are {@code private} by default.
* Fields on interfaces are always {@code public static final}.
*/
void fields(AccessLevel accessLevel);
/**
* Classes are {@code final} by default. If not called, they are not.
* Interfaces are never {@code final}.
*/
void classesFinal();
/**
* Methods on classes are {@code final} by default. If not called, they are not.
* Methods on interfaces are never {@code final}.
*/
void methodsFinal();
/**
* Fields on classes are {@code final} by default. If not called, they are not.
* Fields on interfaces are always {@code public static final}.
*/
void fieldsFinal();
} I realize this is purpose-built and not entirely regular, and would probably have to change later with the introduction of member classes (which I'm not sure we need, frankly). On the other hand, it is a lot smaller and doesn't give rise to a huge number of combinations noone is ever going to use. |
- The mutual-exclusion mechanism was faulty due to `ACC_VOLATILE` and `ACC_BRIDGE` sharing a bit (setting `FINAL` would clear `BRIDGE`) - Fix missed builder delegation in static native builder
I think the general API is simple enough, and having it be internally uniform keeps things consistent and makes it easier to add new flags in the future (value types? who knows). The problem with specific methods for categories is the same as the categories themselves: it's a little tricky to get them right, and useful categories might overlap: for example once we introduce nested classes, if I set "classes" to "package-private" I might be surprised that my nested classes didn't get affected - or I might be surprised if they did. By spelling out each thing specifically, we'll never have to deal with these kinds of opinions. And, we keep things internally simple too, since adding creators for new kinds of things would require new modifier locations but otherwise modifiers would just work. |
I don't particularly like the API, but it's small enough for me to not bother anymore :-) |
Add a mechanism to define the default flags of members. Fixes #222.
This is ready for review now. I dropped the idea of categories as it just wasn't working.
I've made a couple usability improvements. If a flag is always required by some specific kind of member or entity, then adding that flag is always allowed (as a no-op). If a flag is forbidden by some kind of member or entity, then removing that flag is also allowed (as a no-op).
I've added some missing flags and fixed some logical inconsistencies around interface default vs private methods and native methods. I've moved the logic about mapping modifiers to their corresponding allowed members to the
ModifierLocation
enum, so it's all centralized in one place. I've also moved the initial defaults to this enum. I've also introduced logic for mutually-exclusive modifiers likeFINAL
/ABSTRACT
orFINAL
/VOLATILE
; setting one will clear any flags which are mutually exclusive.The implementation mechanism for setting the initial modifiers now centralized (for the most part).