Le 22 mai 2014 à 23:58, Claude Pache <[email protected]> a écrit :

> Hi,
> 
> Today, I came to a case where I wanted to grab a reference to some getter of 
> the DOM,
> but to not fail if it doesn't exists:
> 
> ```javascript
> try {
>    originalElementsGetter = 
> Object.getOwnPropertyDescriptor(window.HTMLFormElement.prototype, 
> 'elements').get
> }
> catch(e) {
>    originalElementsGetter = undefined
> }
> ```
> 
> (If you are curious: the context is monkey-patching `<form>.elements`, so 
> that it includes
> the `<output>` elements of the form, for I've just discovered that IE forgets 
> to include them.)
> 
> This seems to be a typical case for the Existential Operator (?.) we spoke 
> recently about
> (although, in my precise case, a try/catch does the trick).
> However, the Existential Operator works only on properties and methods:
> 
> ```javascript
> // Bad: if window.HTMLFormElement?.prototype is undefined, 
> Object.getOwnPropertyDescriptor will protest loudly.
> originalElementsGetter = 
> Object.getOwnPropertyDescriptor(window.HTMLFormElement?.prototype, 
> 'elements')?.get
> 
> // Here is what I could use:
> Object.defineProperty(Object.prototype, '$getOwnPropertyDescriptor', {
>    value: function(prop) { return Object.getOwnPropertyDescriptor(this, prop) 
> }
>  , writable: true
>  , configurable: true
> })
> oldElementsGetter = 
> window.HTMLFormElement?.prototype?.$getOwnPropertyDescriptor('elements')?.get
> ```
> 
> Can we do better?
> 
> I want to propose a mechanism that can simply express the following
> (only partially fulfilled by the Existential Operator):
> 
> 1. check for nully (null or undefined) values at precise spots of an 
> expression being evaluated;
> 2. if a nully is found, stop the evaluation of the entire current 
> (sub)expression, and yield undefined;
> 3. or, instead of yielding undefined, provide an alternate value;
> 4. and be able to determine precisely what "the current subexpression" of 
> point 2 means.
> 
> So, let's introduce the Conditional Fail Operator (`??`), and, its 
> counterpart, the Recover Operator (`!!`).
> (You could think of them as a throw/catch-like mechanism, or, better, as a 
> break/block-like mechanism.)
> For the sake of illustration, I have artificially lengthen my original 
> example:
> 
> ```javascript
> originalElementsGetter = 
> Object.getOwnPropertyDescriptor(window.HTMLFormElement??.prototype??, 
> 'elements')??.get??
>                          !! 
> Object.getOwnPropertyDescriptor(window.HTMLElement??.prototype??, 
> 'elements')??.get??
>                          !! 
> Object.getOwnPropertyDescriptor(window.Element??.prototype??, 
> 'elements')??.get
> ```
> 
> The semantics are the following:
> 
> * `??` is a unary operator that is used as suffix. If its operand is nully 
> (null or undefined),
>    the evaluation of a certain expression (more precisely defined below) that 
> it is part of, fails immediately.
>    Otherwise, the operand is just returned as is.
> * `!!` is a short-circuiting binary operator. It evaluates its LHS.
>    If the evaluation is not interrupted by a `??`, it returns the result.
>    But if the evaluation is interrupted by a `??`, it evaluates its RHS and 
> returns the result.
> * For any assignement operator (`=`, `+=`, etc.), if the evaluation of its 
> RHS is interrupted by a `??`,
>    the RHS is replaced by `undefined` and the assignment is performed 
> normally.
> * All other operators and function calls are transparent to the failure 
> signal send by `??`
>    (you have to stop it by an explicit `!!`).

I see a nasty footgun in the last two bullets, in case someone refactors from 
`foo.bar = baz??` to `fooMap.set('bar', baz??)`, for the latter will fail 
silently.
But we do want function calls to be transparent to  `??`-failure signals, as it 
can seen in my original example.
The best alternative I can see, is the following:

* All operators (excluding `!!`, of course, but including assignments) and 
function calls are transparent to failure signals.
* If a failure signal remains uncaught, an error is thrown (and this condition 
may even be statically determined and produce an early error).
    This will catch (!) early failed-assignment bugs, and force the programmer 
to be more explicit.

With this amendment, my example must be completed with a final `!! undefined`:

```javascript
originalElementsGetter = 
Object.getOwnPropertyDescriptor(window.HTMLFormElement??.prototype??, 
'elements')??.get??
                         !! 
Object.getOwnPropertyDescriptor(window.HTMLElement??.prototype??, 
'elements')??.get??
                         !! 
Object.getOwnPropertyDescriptor(window.Element??.prototype??, 
'elements')??.get??
                         !! undefined
```

—Claude

> 
> As I have shown in [1], it seems relatively easy to spec such a behaviour 
> using a custom Abrupt Completion.
> The proposed spec needs to be refined in order to avoid precocious 
> GetValue(...) calls,
> but I am able to write a complete strawman in case there is interest.
> 
> WDYT?
> 
> —Claude
> 
> [1] 
> http://esdiscuss.org/topic/specifying-the-existential-operator-using-abrupt-completion
> 

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to