In some situations, program invariants may establish that a variable is non-null in a way that cannot be made apparent to the type system. Kotlin, Swift, and Typescript all have some form of null assertion operator to handle this.
The postfix ! operator has been proposed for this, since it is a familiar idiom from other languages (see below).
This issue is for discussion of the operator, and possible alternative syntax. cc @Hixie @munificent @lrhn @eernstg
For reference, the operator in other languages:
Kotlin has the !! operator, which throws if the argument is null
// Kotlin
var s : String? = null
s!!.length // Throws if null, then calls the method
s!! // Throws if null
Swift has both a ! (force unwrap) operator (throws if nil), and also an implicitly unwrapped type which causes an implicit unwrap on each use.
// Swift
var str : String?
str = "Hello, playground"
str!
str!.count
let strImplicit : String! = str
strImplicit.count // equivalent to strImplicit!.count
Typescript has a purely static null assertion operator.
var str : String | null;
str!
str!.length
My preferences are:
Yes, we should have this operator.
It should be a postfix !, with the same precedence as ..
I don't think we need any special case support for !.. That should fall out naturally from using postfix ! followed by a method call. It also allows other important use cases:
int? n;
expectsInt(n!);
someJson["key"]!["subkey"];
var value = someMap["key"]!;
That should fall out naturally from using postfix
!followed by a method call.
I think to make this work out in general, we either need the ! type operator, or we need to track nullability outside of the type system. See discussion here.
I think we're converging on a clear yes with syntax of !. @lrhn @eernstg @munificent is there more discussion to be done on this or should we mark this as decided?
+1 on !, and marking this as decided! ;-)
Syntactically, I think we will need a special case for !. as a member access; if we just make ! a postfix operator then we won't be able to write things like e!.m(), just like we can't write e++.m(). But I have no doubts that we can do that.
Agree on !. We'll fiddle with the grammar to give it the most useful precedence.
+1!
Syntactically, I think we will need a special case for
!.as a member access;
We can't deal with this via precedence? In any case, however we handle it, we'll probably need to be sure we can handle e!..m, e!(a), e!<T>(a) as well.
There will be an operator, and the syntax is !.
Most helpful comment
There will be an operator, and the syntax is
!.