To better answer, let's start dropping any direct access and put a payload
in the mix.

As example, in the `foo()?.bar.baz` case, you might end up having `null` or
`undefined`, as result, because `foo().bar` existed, but `bar.baz` didn't.

In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, because
`bar.baz` didn't exist.

But what if you are not interested in the whole chain, but only in a main
specific point in such chain? In that case you would have `foo()?.bar.baz
?? foo()`, but you wouldn't know how to obtain that via `foo()?.bar?.baz ??
foo()`, because the latest one might result into `foo().bar`.

Moreover, in both cases you'll end up multiplying the payload at least * 2,
while the mouse trap will work like this:

```js
foo()<?.bar?.baz
```

if either `foo().bar` or `bar.baz` don't exist, the returned result is
`foo()`, and it's computed once. You don't care about `foo().bar` if
`bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you
have a failure down the chain.

Specially with DB operations, this is a very common case (abstraction
layers all have somehow different nested objects with various info) and the
specific info you want to know is usually attached at the top level bject,
while crawling its sub properties either leads to the expected result or
you're left clueless about the result, 'cause all info got lost in the
chain.

The `foo()<?.bar.baz` case is a bit different though, 'cause if `foo().bar`
existed, there's no way to expect `foo()` as result, and if it's `bar` that
you're after you can write instead `foo()?.bar<?.baz` so that if `baz` is
not there, `bar` it is.

This short-circuit the need for `??` in most cases, 'cause you already
point at the desired result in the chain in case the result would be `null`
or `undefined`.

However, `??` itself doesn't provide any ability to reach any point in the
previous chain that failed, so that once again, you find yourself crawling
such chain as fallback, resulting potentially in multiple chains and
repeated payloads.

```js
// nested chains
foo()?.bar.baz?.biz ?? foo()?.bar.baz ?? foo()?.bar;

// mouse trap
foo()?.bar<?.baz?.biz;
```

Above example would prefer `foo().bar` if it exists, and if either
`bar.baz` or `bar.baz.biz` returned `null` or `undefined`.

I hope this clarifies further the intent, or the simplification, that such
operator offers: it's a complementary hint for any optional chain, it
doesn't have to be used, but when it does, it's visually semantic in its
intent (at least to my eyes).

Regards




On Fri, Sep 6, 2019 at 11:20 PM Tab Atkins Jr. <jackalm...@gmail.com> wrote:

> On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi
> <andrea.giammar...@gmail.com> wrote:
> > Indeed I'm not super convinced myself about the "branching issue" 'cause
> `const result = this?.is?.branching?.already` and all I am proposing is to
> hint the syntax where to stop in case something else fails down the line,
> as in `const result = this.?.is<?.branching?.too` to know that if any other
> part is not reached, there is a certain point to keep going (which is,
> example, checking that `result !== this`)
>
> Important distinction there is that ?. only "branches" between the
> intended type and undefined, not between two arbitrary types. The
> cognitive load between those two is significantly different.
>
> In particular, you can't *do* anything with undefined, so
> `foo?.bar.baz` has pretty unambiguous semantics - you don't think you
> might be accessing the .baz property of undefined, because that
> clearly doesn't exist.
>
> That's not the case with mouse, where it's not clear, at least to me,
> whether `foo<?.bar.baz` is doing `(foo.bar ? foo.bar : foo).baz` or
> `foo.bar.baz ? foo.bar.baz : foo` or even `foo.bar ? foo.bar.baz :
> foo`. All three seem at least somewhat reasonable, and definitely
> *believable* as an interpretation!
>
> ~TJ
>
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to