-
Notifications
You must be signed in to change notification settings - Fork 26
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
Annotation to negate @NullMarked
at a narrower scope
#127
Comments
First, let's set up an assumption. The concern: This annotation would make less sense if defaulting annotations were permitted only at the class level. In that case, the only way for one defaulting annotation to override another would be for one to be located on a class nested inside the other. However, it seems likely that we will allow annotations on other scopes. And even if we don't, there may be at least a little value in providing users with a way to explicitly label every top-level class as either "in the club" or "out of the club." (Users might choose to enforce this with presubmit checks.) So, for purposes of this discussion, let's proceed under the following assumption:
|
With that out of the way... some pros and cons: + makes it possible to "flip the default" for new code in a package/class
+ consistent with a "cascading" pattern we're likely to employ for non-nullness-related annotations
+ lets users explicitly label APIs as "intentionally not annotated for nullness, at least for now" rather than leaving open the question of whether someone just forgot to consider annotating them
- one more thing for users to understand
- one more thing for us to name (previously, previously)
|
It's linked from the previous comment, but for more explicit reference, #87 was arguably filed under the assumption that the answer to this here issue is, yes, there should be a defaulting annotation to undo "in the club". That issue also proposes a solution, |
Filling #137 reminded me that Android wanted
A fuller discussion of that may belong on #71 or a |
I wonder if this will also be useful for generated code: If I want to put |
I've been assuming this would probably be called It seems important to me, for supporting migration. |
I think having such an annotation simplifies migration and other use cases and presents no real additional complexity to the model, and so we should. |
+1 from me as well, that will help for migration but also will help the project and tooling support to be "unplugged" for advanced use cases where the behavior is not the one expected. That will allow to wait until it is identified if:
That will avoid people to be blocked when the tooling is configured to throw errors not warnings which is what we plan to do. |
Ergonomics-wise, I like having an annotation for this among other things to
make it easier to to annotate a package or module `@NullMarked`.
Specifically, it avoids having to remember annotating each new class in a
package or module that has some files that aren't ready to be opted in yet.
Using this annotation on something like an inner class (or a method) could
also be useful but does seem to create some complexity (or at least room
for misunderstanding) if the outer class has type parameters. In
particular, the question becomes how to interpret usages of the outer
class's type parameters in the inner class. Minimally we'll have to define
that case, but I'm also simply not sure what most users will expect to
happen in that case, and how close we can and should get to that
expectation.
|
Good point - I copied it to #43. |
This might be fairly resolvable as a design question, but I suppose the issue can just stay open until we actually check it in and plumb it through all the samples and docs. (In general we might benefit from separating design issues from impl issues more -- and it is already the case that design issues have been marked closed where we still need to go back and make sure we actually worked them into everything where needed.) |
Sorry, there's some history that I failed to record here: This came up in one of our meetings last year, and there were no objections raised to eventually adding it. The meeting conclusion was a bit more subtle than that, though: We said that we'd try to get some actual users on board and then wait for them to report a need for this to us. I personally think that that need is going to arise for all the reasons discussed above. Still, I see some appeal in taking the more empirical approach so as to set a precedent for other feature requests. (I'm confident that we'll get some "biggest pain point" feedback on this if we just wait long enough.) On the other hand, I also see some strategic value in "locking in" this annotation that we're highly confident that we'll need, since that lets us provide users with the annotation, and that advances the conversation to "Which annotation do we need next?" (And it's worth noting that this process will take months.) On the other other hand, I have been pushing to defer issues where practical: Every moment we spend on followup issue #109 (which in turn requires discussion of #200) is another moment not spent on, e.g., preparations for opening up a presence to the Internet at large. (But that's probably a more general prioritization discussion than we should have on this thread. Plus, again, if the process of deciding and implementing these issues is going to take a long time, I'm not sure if that's a point in favor of starting them now or a point against!) For purposes of this GitHub issue, I think I'm personally happy to just turn all the above into a "yes" at this point, especially knowing that all decisions can be revisited given new information -- probably meaning, in this case, a shocking lack of information about anyone who needs this annotation. But if anyone has been reading this and thinking "What happened to what we said last October?" then please do speak up. Again, I'm sorry for not recording that here at the time. (Aside: Good point about design issue vs. impl issues.) |
@NullMarked
at a narrower scope
I believe it has essentially been resolved that we do want this, for a while. My reasoning is this: this is an adoptability feature, which replaces stair-step hurdles with a smoother ramp that's easier to slide up a bit at a time. In particular, this feature would mean that partly-migrated files could nevertheless already have the property that new methods added to them are automatically in the club, and I think this is very good. Furthermore: features that exist to make adoption easier are not good choices for things "we can just add later", because it's in OUR interest to get as much adoption and thus feedback early (before it's too late) as we can. So, the time to make it easy to adopt is now. We'll attempt to decide its exact shape in #109, together with a couple other examples of other sets of exclusive scope-annotations we might add. |
@NullMarked
at a narrower scope@NullMarked
at a narrower scope [working decision: yes]
Just a note that tool providers (including @lazaroclapp) have raised the issue that supporting arbitrary negative/positive containers might be hard to do efficiently. I think that's worth thinking about from an implementation perspective, but I still think the value of this feature is great enough that we should figure out how to make it feasible. |
I gave my thumbs-up emoji to having support for this. 2 quick comments:
|
Just to be clear, I'd like to avoid this annotation if possible, and I certainly would like to keep it out of 1.0. There are a lot of reasons but among other things I'm simply not seeing that this has that much bearing on adoptability. I'm not sure what the protocol is but I'll reopen this issue for now. |
Thanks for the update! One question: Is that...
I'm not sure if I asked that clearly :\ What I'm trying to get a sense of is whether we can tell users "If you annotate non-top-level classes, your performance will be bad" or "If you annotate non-top-level classes, NullAway 'won't work'" (in which case we would have more reason to avoid offering such a feature in the first place). |
Hi @cpovirk, it would be more of a case of "If you annotate non-top-level classes, NullAway performance may deteriorate a bit, for those compilation units only." The annotations would still be supported in those cases, though. My main concern before was avoiding a perf regression for NullAway users who are using NullAway's extant mechanisms (command-line options) for indicating which code is marked, and I now think we can achieve this. |
I'll resummarize the case I see:
As for disadvantages:
Of course, not doing this is a valid option. We can not do it. I'm only explaining why it looks better to do it. |
I suppose one argument against such an annotation is that we expect/want its usage to go to zero in the long term. |
From what I'm hearing the case for this annotation rests on it being critically needed for adoption. But what I've heard so far is that it could be useful in some scenarios for some hypothetical users, and there is a workaround. Specifically the use case, as I understand it, would be someone wanting to mark a class (package, respectively) as
The combination of these two simply makes me think this is at best nice to have. In particular I'm honestly not seeing evidence that the annotation would critically enable JSpecify adoption for a lot of users. As @kevinb9n conceded above, the burden of proof is in introducing the annotation, so I'd suggest we take this to an issue doc and hash it out more completely, instead of through comments addressing one concern or another, as I'm admittedly continuing to do here. |
Uh oh. This led me to
(Note: I'm using "fair to assume" to mean "technically hypothetical, but doesn't really warrant skepticism" and people are obviously allowed to disagree with it, it is just my judgment.) In fact for any fully migrated or new codebase we would basically want them to ban it. But that means we would end up wanting to support them, with something like |
This issue requires restructuring and resummarizing before we can make further progress on it. I'm signing up to do that... in the meantime, anyone is welcome to offer quick thoughts but don't necessarily invest much time in trying to follow all the twists and turns. |
Some thoughts based on the meeting notes (sorry I missed it today) and conversations with Manu:
|
TODO: reopen this with new summary, as this is one of the 3 most vertical issues we have open for 1.0 currently. |
One thing I just said in an internal discussion: Background: One problem with package-level After seeing this in practice, I realized that we could make package-level This would still leave issues with package-level annotations (which are probably discussed somewhere in #30 and/or #34 and/or elsewhere). But if people really want to use package-level annotations (and I'm sure some will), then their lives would get a little better if they had the option of subsequently applying |
I agree this is a good use case for |
Thanks. That makes sense, and it makes me see that package-level Another possible issue is tests written in Kotlin: Kotlin is always applying nullness checking, so there's no option to run it only on prod code. Fortunately, Kotlin code also is "annotated for nullness" :) So the issue would arise only if all the following conditions were met:
Then we could see the Kotlin compiler reject code or insert runtime null checks that cause problems—at least until someone applies (I could also imagine similar problems with a hypothetical Java bytecode rewriter that automatically inserts null checks similar to the ones that Kotlin inserts automatically. But I think we are quite far from the time at which anyone would try that. And anyone who did try it would likely have to make exceptions for code that is clearly test code, among the many, many other exceptions that would likely be necessary in real-world code.) |
Only if the tool runs on test code at all, mind you.
That would be somewhat hard to do within the context of a javac plugin, I think. At least "from the inside" of the plugin. The configuration I describe above is much simpler: the NullAway checker is not anywhere in any relevant classpath when compiling test code. So it isn't, "the tool gracefully handles the prod/test distinction", but "due to how our build system is set up, the tool doesn't even exist when compiling test code". At a high enough level where the build system config + NullAway is "the tool", then your description matches our situation too, though. That said, in the general case: p.s. Re: bytecode rewriters and such: One of the areas were NullAway does have a lot of edge cases handling is in detecting generated code (generated |
We are comfortable with a Working Decision to allow |
@NullMarked
at a narrower scope@NullMarked
at a narrower scope [working decision: yes]
Current decision: Yes, this feature is important to enable incremental migration of legacy code. Argument for changing: None was made other than it may not be necessary. Timing: This must be decided before version 1.0 of the jar. Proposal for 1.0: Finalize the current decision. If you agree, please add a thumbs-up emoji (👍) to this comment. If you disagree, please add a thumbs-down emoji (👎) to this comment and briefly explain your disagreement. Please only add a thumbs-down if you feel you can make a strong case why this decision will be materially worse for users or tool providers than an alternative. Results: This proposal received 6 👍s and no other votes. |
Decision: Yes, JSpecify will have an annotation to negate |
@NullMarked
at a narrower scope [working decision: yes]@NullMarked
at a narrower scope
That is, should we have a
@DefaultNullnessUnspecified
/@NotNullAware
annotation that overrides any@DefaultNonNull
/@NullAware
annotation that is in scope?We have been proceeding as if the answer is "yes" (e.g., in #41). Maybe we can settle that quickly. Doing so would simplify the remaining discussions about partially annotated code. Now seems like as good a time as any to summarize those discussions (building on kmb's table):
@NonNull
annotation ([moved to #230] Decide whether to include a@NonNull
annotation #4; name already chosen in Choose non-null annotation name #44)@NullnessUnspecified
annotation (Ability to apply unspecified-nullness to an individual type usage (e.g. a type-use annotation like@UnspecifiedNullness
) #137; naming discussion in Naming the third nullness annotation (the one that matches the behavior of unannotated code) #32; some use cases we haven't endorsed in Address the "findViewById
problem" (generally nullable, but in *common* specific cases not) #71)I'll try to dump some thoughts before leaving for the day.
The text was updated successfully, but these errors were encountered: