chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.77k stars 417 forks source link

Nilability ergonomics: optional chaining #17577

Open vasslitvinov opened 3 years ago

vasslitvinov commented 3 years ago

Nilability ergonomics / convenience features have been proposed in #12614 and forked off into #16931. The first of them is the topic of #13639, already implemented.

This issue requests the second convenience feature that is akin to Swift's Optional Chaining

This feature is a shorthand for this kind of conditional expression:

if const xTemp = x then xTemp.someMethod() else nil

that uses this syntax, which is inspired by Swift:

x?.someMethod()

This syntax probably entails defining a new postfix operator ?. to differentiate from the the postfix ?, which is allowed only on types.

The semantics is clear when x is a class and someMethod() returns a class, nilable or non-nilable.

A design question is: should we allow it for other types? For non-classes, the semantics could be:

x?.someMethod()
// is equivalent to:
if x then x.someMethod() else <the default value of x.type>

A consideration here is whether the user can tell, from the result of the expression, whether the then or else branch was taken. It is possible in the case where x is a class and someMethod() returns a non-nilable class, otherwise it is not possible to tell.

mppf commented 3 years ago

Sounds good to me.

should we allow it for other types?

I'd expect it would work with e.g. option(int) once that exists.

vasslitvinov commented 3 years ago

I'd expect it would work with e.g. option(int) once that exists.

Right. Then, what if there is no option? Ex.

var x = 5;
var y = x?.someMethodOnInts();

Should x?. be an error in this case?

If so, should x?. be an error when x is a non-"option" class type, i.e., a non-nilable class? One can view a non-nilable class as a couterpart to a non-option int.

mppf commented 3 years ago

I'd lean towards having x?. be an error if there is no option class. However it also seems like it might be useful to do something else for it, to enable generic programming. Let's suppose we have int.someMethod(): real. Then I would expect 1?.someMethod() to return new option(1.someMethod()) - in other words, to wrap the result in an option.

Taken back to classes, let us suppose we have class types C and D. If we write myC?.methodReturningD()then I would expect the result to be D? (with the appropriate memory management according to the return type of methodReturningD).

It would be good to know what approach Swift takes for these cases. Can you investigate?

vasslitvinov commented 3 years ago

Optional chaining In Swift states that the result of an ?. expression is always an optional, even when the invoked function is non-optional.

This is necessary -- because ?. can be applied only to an optional value. Therefore the result of a ?. may indeed be a nil.

So, should we disallow ?. on non-optional things in Chapel, too, by analogy with Swift?

Alas, the Chapel-Swift analogy does not go very far. In particular, Chapel allows postfix-! on non-nilable classes, while Swift does not allow postfix-! on non-optional values.

With that in mind, I propose the following rules: