I have thought about the right semantics (and the issues) of the existential 
operator.

    user.getPlan?().value?.score;

The intended semantics of `?` is that, whenever its LHS evaluates to `null` or 
`undefined`,
the evaluation of the whole expression (or subexpression) is interrupted and 
return immediately `undefined`.
In other word, it may be seen as an abrupt completion, as demonstrated by the 
following expansion:

    (do {
        let result = user           // user
        result = result.getPlan // _.getPlan
        if (result == null)         // _?
            break                   // abrupt completion
        result = result.call(user)  // _()
        result = result.value       // _.value
        if (result == null)         // _?
            break                   // abrupt completion
        result = result.score       // _.score
    })

Now, it should be determined, whenever such an abrupt completion is encountered 
during evaluation,
in which cases it should propagate, and in which case it should be transformed 
into a normal completion of value `undefined`.
Roughly, property accesses and function calls should propagate it when it is 
found on their LHS, 
and in all other cases it should be mutated it to NormalCompletion(undefined). 
E.g.:

    (user.getPlan?().value?.score || 0).toFixed(2) // the `||` operator 
interrupts the abrupt completion propagation


Here is a simple strawman that illustrates how that idea could be implemented 
in the spec.
It has some known (and unknown) issues, but I think it gives a good idea of the 
mechanism.
And it resolves quite naturally the non-compositional issue of the original 
strawman (see the remark at the end of the message).

The specification is patched as follows:

6.2.2 The Completion Record Specification Type

    An additional value is allowed for the [[type]] field, besides normal, 
break, continue, return, or throw; namely: failsoft.

6.2.3.1 GetValue(V)

An additional parameter is added to that abstract operation:

    GetValue(V, propagateFailsoft = false)

If the second argument is absent, it is presumed to be false. An additional 
step is prepended to the algorithm:

0. If V is an abrupt completion of [[type]] failsoft and if propagateFailsoft 
is false,
    a. Let V be NormalCompletion(undefined).


12.3 Left-Hand-Side Expressions

The production of MemberExpression is expanded as follows:

FailsoftMark:
    "?"

MemberExpression:
    (...)
    MemberExpression FailsoftMark

The runtime semantics is the following:

MemberExpression: MemberExpression FailsoftMark

    1. Let ref be the result of evaluating MemberExpression.
    2. Let val be GetValue(ref, true).
    3. ReturnIfAbrupt(val).
    3. If val is null or undefined,
        a. Return Completion([[type]]: failsoft, [[value]]: undefined, 
[[target]]: empty).
    4. Return val.

Here, there is an issue in expressions like `a.b?(c)`, because the correct 
`this` value of the method call won't be able to be determined.
This can be resolved by further suitable refinements.

Finally, in the algorithms involving LeftHandSideExpression's (section 12.3), 
some calls to GetValue(...) are replaced by GetValue(..., true).
They are:

Property Accessors
12.3.2.. Runtime Semantics: Evaluation
MemberExpression : MemberExpression [ Expression ]
Step 2. Let baseValue be GetValue(baseReference, true).

The new operator
12.3.3.1 Runtime Semantics: Evaluation
NewExpression : new NewExpression
Step 2. Let constructor be GetValue(ref, true).

ibid.
MemberExpression : new MemberExpression Arguments
Step 2. Let constructor be GetValue(ref, true).

Function Calls
12.3.4.2 Runtime Semantics: EvaluateCall
Step 1. Let func be GetValue(ref, true).

In all other cases, a call to GetValue(...) will intercept a failsoft abrupt 
completion and return `undefined`.


A notable fact of that strawman is that the two following expressions are 
equivalent:

    (a?.b).c
    a?.b.c

because evaluating a ParenthesizedExpression does not apply GetValue(...) 
(Section 12.2.10.4).

—Claude





_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to