Proposal: result-forwarding ternary operator

Naveen Chawla naveen.chwl at gmail.com
Wed Sep 20 10:09:37 UTC 2017


I had no idea about the comma operator! Can you give me an example of an
"actual statement" that cannot be serviced in a comma operator expression?

As it stands then, I prefer the comma operator way for the initial example:

```js
const
    x = getSomething(),
    foo =
       x ?
          (
              doSomethingFirst(),
              x.doSomething()
          ) :
          doSomethingElse()
```



On Wed, 20 Sep 2017 at 15:19 Isiah Meadows <isiahmeadows at gmail.com> wrote:

> Haskell and most Lisp dialects have a `do` syntax that enables you to do
> multiple operations and return the result of the last. The difference
> between this and the comma operator is that you can use actual statements
> as well as expressions.
>
> Also, my `if`/`else` usage was more just personal syntactic preference - a
> ternary works just as well.
>
>
> On Wed, Sep 20, 2017, 05:38 Naveen Chawla <naveen.chwl at gmail.com> wrote:
>
>> I prefer to the "do" approach (albeit in a different way, as I'm showing
>> below). Can someone tell me why it's called "do" instead of something like
>> "expr", or "eval" or something? "do" just seems weird naming for evaluating
>> the last statement in a multi statement code block.
>>
>> For the initial example, I prefer this use of the `do` concept, instead
>> of the `if` `else` way of doing it:
>>
>> ```js
>> const
>>     x = getSomething(),
>>     foo =
>>        x ?
>>           do {
>>               doSomethingFirst();
>>               x.doSomething()
>>           } :
>>           doSomethingElse()
>> ```
>>
>> On Wed, 20 Sep 2017 at 14:11 Isiah Meadows <isiahmeadows at gmail.com>
>> wrote:
>>
>>> I'll just note that the only two languages I know of with a feature like
>>> this is Haskell with its `maybe fn orElse m`* function in `Data.Maybe` and
>>> Scala's `Option[T].mapOrElse(fn, orElse)`. Here's what many other languages
>>> do:
>>>
>>> Several languages use some form of `if let`, including Rust, Scala, and
>>> Swift:
>>>
>>> ```swift
>>> // In Swift
>>> let newFoo
>>> if let x = getSomething() {
>>>     doSomethingFirst()
>>>     newFoo = x.doSomething()
>>> } else {
>>>     newFoo = doSomethingElse()
>>> }
>>> ```
>>>
>>> Clojure offers the macro `(if-let)`, which does mostly the same thing
>>> (Common Lisp has a similar macro):
>>>
>>> ```clj
>>> ;; Top-level declaration
>>> (def new-foo
>>>   (if-let x (get-something)
>>>     (do
>>>       (do-something-first)
>>>       (do-something x))
>>>     :else (do-something-else)))
>>> ```
>>>
>>> OCaml uses pattern matching, and C/C++, most of its derivatives (like
>>> Python), and Kotlin just do `if (x != NULL) ... else ...` or similar.
>>> (Kotlin has flow-sensitive typing like TypeScript, which helps avoid
>>> mistakes.)
>>>
>>> * I might have gotten the argument order wrong - I'm not a regular
>>> Haskell user, and it's not commonly used.
>>>
>>> On Tue, Sep 19, 2017, 09:36 Michael Rosefield <rosyatrandom at gmail.com>
>>> wrote:
>>>
>>>> We still have to explicitly create a variable (x), either in the do
>>>> block or before that ternary, and the bracket-enclosed comma-separated
>>>> expressions are... not to my taste.
>>>>
>>>> This was always about syntactic sugar and concision, as there are
>>>> always other ways to go about it; as I commented in my reddit post, both
>>>> operators can be done functionally:
>>>>
>>>> const $equivFn = (cond, ifTruthy, otherwise) => cond ? ifTruthy(cond) : otherwise(),
>>>>       foo = $equivFn(getSomething(), x => doSomething(x), () => doSomething()),
>>>>       equivFoo = getSomething() ?! x => doSomething(x) : doSomethingElse();
>>>>
>>>> // normal ternary
>>>> const $ternary = (cond, ifTruthy, otherwise) => cond ? ifTruthy() : otherwise(),
>>>>       foo = $ternary(checkSomething(), () => doSomething(), () => doSomething()),
>>>>       equivFoo = checkSomething() ? doSomething() : doSomethingElse();
>>>>
>>>>
>>>> ... but it's not elegant.
>>>>
>>>> And I appreciate ?! was a bad choice, but can easily be substituted by
>>>> anything else.
>>>>
>>>> On Tue, 19 Sep 2017 at 14:06 Andrea Giammarchi <
>>>> andrea.giammarchi at gmail.com> wrote:
>>>>
>>>>> I don't think `do` is "much longer" than your last example, however,
>>>>> it can be shorter
>>>>>
>>>>> ```js
>>>>> const newFoo = do {
>>>>>   let x = getSomething();
>>>>>   x ?
>>>>>     (doSomethingFirst(), x.doSomething()) :
>>>>>     doSomethingElse();
>>>>> };
>>>>>
>>>>> On Tue, Sep 19, 2017 at 3:00 PM, Sebastian Malton <
>>>>> sebastian at malton.name> wrote:
>>>>>
>>>>>> I don't think that talking about the syntax is relevant now since it
>>>>>> is not important when talking about the reasonability of a suggestion.
>>>>>> Saying that the syntax could be `?|`
>>>>>>
>>>>>> The `do` is much longer than the example.
>>>>>>
>>>>>> I think that this a reasonable idea.
>>>>>>
>>>>>> *From:* isiahmeadows at gmail.com
>>>>>> *Sent:* September 19, 2017 8:57 AM
>>>>>> *To:* rosyatrandom at gmail.com; es-discuss at mozilla.org
>>>>>> *Subject:* Re: Proposal: result-forwarding ternary operator
>>>>>>
>>>>>> Few issues:
>>>>>>
>>>>>> 1. This is already technically valid code: `cond?!fn:orElse` is
>>>>>> equivalent to `cond ? !fn : orElse`
>>>>>> 2. Have you considered `do` expressions (stage 1 proposal)? They work
>>>>>> a lot like IIFEs, but allow easy definition of computed constants.
>>>>>> 3. Have you considered using in-condition assignment or just
>>>>>> factoring out the computed condition into a separate variable? Sometimes, a
>>>>>> little verbosity helps.
>>>>>>
>>>>>> Using `do` expressions, your second code sample would look like this:
>>>>>>
>>>>>> ```js
>>>>>> const newFoo = do {
>>>>>>     let x = getSomething();
>>>>>>     if (x) {
>>>>>>         doSomethingFirst();
>>>>>>         x.doSomething();
>>>>>>     } else {
>>>>>>         doSomethingElse();
>>>>>>     }
>>>>>> };
>>>>>> ```
>>>>>>
>>>>>> On Tue, Sep 19, 2017, 08:33 Michael Rosefield <rosyatrandom at gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>> (I've also put this on reddit
>>>>>>> <https://www.reddit.com/r/javascript/comments/7129tn/proposal_resultforwarding_ternary_operator/>,
>>>>>>> which I've copied this from. Hope the formatting doesn't go haywire...)
>>>>>>>
>>>>>>> First course of action for this proposal is, obviously, to
>>>>>>> come up with a better name for it....
>>>>>>>
>>>>>>>
>>>>>>> Motivation
>>>>>>>
>>>>>>> As with the 'optional chaining' proposal for tc39
>>>>>>> <https://github.com/tc39/proposal-optional-chaining>, this operator
>>>>>>> is a way to avoid excess and annoying code from safety-checking.
>>>>>>>
>>>>>>> The optional chaining proposal, above, follows a chain and
>>>>>>> short-circuits it upon acting on a null object, returning a safe '
>>>>>>> *undefined*' result; it can be thought of as an extended '*if*'
>>>>>>> sequence. It looks like this:
>>>>>>>
>>>>>>> // safeVal = result of someProp, or undefined if looking for props on null obj
>>>>>>> const safeVal = blah?.someMethod()?.someProp;
>>>>>>>
>>>>>>> This proposal provides for an '*else'* scenario, particularly in
>>>>>>> situations where chaining isn't appropriate, by forwarding the result of a
>>>>>>> truthy conditional check to a single-parameter function.
>>>>>>>
>>>>>>>
>>>>>>> Syntax
>>>>>>>
>>>>>>> *condition ?! fn : expr*
>>>>>>>
>>>>>>> Parameters
>>>>>>>
>>>>>>>    - condition: any condition, *identical to use in standard
>>>>>>>    ternary*
>>>>>>>    - fn: function taking single parameter, which is the result of
>>>>>>>    evaluating *condition*
>>>>>>>    - expr: any expression, *identical to use in standard ternary*
>>>>>>>
>>>>>>>
>>>>>>> Usage Example
>>>>>>>
>>>>>>> // temporary variable
>>>>>>> const temp = getSomething(),
>>>>>>>       foo = temp ? doSomething(temp) : doSomethingElse();
>>>>>>>
>>>>>>> // repeated code, possible side-effects
>>>>>>> const foo2 = getSomething() ? doSomething(getSomething()) : doSomethingElse();
>>>>>>>
>>>>>>> // proposal, no chaining
>>>>>>> const newFoo = getSomething() ?! x => doSomething(x) : doSomethingElse();
>>>>>>>
>>>>>>> // proposal, chaining
>>>>>>> const newFoo = getSomething() ?!
>>>>>>>       x => {
>>>>>>>         doSomethingFirst();
>>>>>>>         return x.doSomething();
>>>>>>>       } :
>>>>>>>       doSomethingElse();
>>>>>>>
>>>>>>>
>>>>>>> Notes
>>>>>>>
>>>>>>>    -
>>>>>>>
>>>>>>>    The choice of '?!' is entirely arbitrary and not a core part of
>>>>>>>    the proposal.
>>>>>>>    -
>>>>>>>
>>>>>>>    The result of the conditional check is not passed on to the
>>>>>>>    falsey path, because it seems pointless to do so.
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> es-discuss mailing list
>>>>>>> es-discuss at mozilla.org
>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> es-discuss mailing list
>>>>>> es-discuss at mozilla.org
>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>
>>>>>>
>>>>> _______________________________________________
>>>>> es-discuss mailing list
>>>>> es-discuss at mozilla.org
>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170920/a192a1e7/attachment-0001.html>


More information about the es-discuss mailing list