-
Notifications
You must be signed in to change notification settings - Fork 209
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
Is shorting extension methods the right choice? #392
Comments
It is certainly a source of complexity for the reader of a call site if null-shorting treats extension methods differently from instance method, even though it might seem convenient for cases like
Exactly. ;-) Btw, this might imply that it is a code smell to even have a static extension whose |
Short circuiting As mentioned in #393, there is an easy way to escape from shortening: It must also be easy for the reader to understand, and extension methods are made to look like normal methods, so they should work like normal methods. The fact that they desugar to something else is not important to readability. We are not calling a static method the normal way, we are providing a different shorthand for the pipe operator (#43). It makes the type reasoning easier too to treat everything the same.
Which extension applies? If we allow extension methods to break the short-circuiting when they are nullable, then we get unpredictability. If we say that a nullable extension can apply and escape the short-circuiting, then it must be because we check against If we check extensions against (Or, in other words, this code is fine, and if we break it, we are probably doing something wrong). |
Am I correct in remembering that we resolved this in favor of doing null-shorting uniformly? |
Yes. We no longer have the |
Extension methods and NNBD interact in interesting ways around null-aware short-circuiting. We do allow defining extension methods on nullable types, which means we the language tells users "We think it's useful to let you define and call methods on things that may be null." But then the current behavior for null-aware short-circuiting shorts all method calls, extension or not, which means the language tells users "We never think it's useful to call methods on things that may be null."
That feels inconsistent. It also rules out potentially useful features, like:
The model we have for extension methods is that they are simply a nice syntax for passing an argument to a function. The above is semantically very much like:
We do not null-short function calls if an argument is null, so this model implies we should not null-short extension method calls. So, there's an argument that not null-shorting extension method calls is the principled thing to do, and that it's the practical thing to do (for some extension methods).
However, this adds complexity. It means we don't know the control flow of a method chain until we've resolved invocations to see which are extensions and which aren't.
If we never null-short extension methods, then it is anti-useful in other cases:
If we don't short the
.half
, then this code always produces a static error. The user is forced to turn the last.
into?.
which feels tedious and obscures the fact that.x
itself never producesnull
. In other words, it fails for exactly the reasons we are adding null-shorting in the first place.(One argument for never shorting is that extension methods basically overload the
.
to mean "statically call this function". The syntax directly maps to a completely static behavior, and users are expected to understand that. If you want a different completely static behavior, you should use a different syntax and we would thus also overload?.
to mean "statically call this function if the first argument is not null".)The third option is to null-short extension methods on non-nullable types, since not shorting those is a static error. And then don't null-short extension methods on nullable types, since — by the method's own declaration — it's safe to pass null to it. That sounds nice.
The problem is potentially nullable extension methods:
Do calls to
weird()
get shorted or not? We might be able to answer based on the substituted type:That feels pretty complex and scary. In particular:
I assume we would choose based on the type bound, but we are pretty far away from something typical users can reason about.
The text was updated successfully, but these errors were encountered: