There has to be a better pattern than returning the "foo()" if the baz property doesn't exist.
I'm curious what you would want to do with the resulting "foo()" anyway. I can imagine a flow where I want "bar", and it doesn't exist it doesn't. I cannot imagine wanting the "foo()" in place of it. There is type unpredictability in the result, so subsequent operations would normally expected to be impossible without type-branching. Hence my question to you about what you would typically want to do with the "foo()" if that was the returned result. On Sat, 7 Sep 2019 at 12:08, Andrea Giammarchi <[email protected]> wrote: > Interesting I forgot about that, but it wouldn't cover the "trap here" use > case. > > foo().bar ?! what => what : what; > > I'd like to forward foo() here > > On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield <[email protected]> > wrote: > >> This is getting very reminiscent of my 'forwarding ternary' operator (or >> whatever I called it) I suggested a couple of years ago. I believe you were >> involved in the discussion, Andrea...! >> >> ``` >> const val = foo() ?! >> (x) => x.bar.baz : >> someFallbackValue; >> ``` >> >> On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, <[email protected]> >> wrote: >> >>> 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. <[email protected]> >>> wrote: >>> >>>> On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi >>>> <[email protected]> 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 >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

