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 `!!`).
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