Proposal: result-forwarding ternary operator

Andrea Giammarchi andrea.giammarchi at gmail.com
Wed Sep 20 10:16:58 UTC 2017


let's close the circle:

```js
const newFoo = do { let x = getSomething(); x ?
  (doSomethingFirst(), x.doSomething()) :
  doSomethingElse();
};
```

and about this:

> Can you give me an example of an "actual statement" that cannot be
serviced in a comma operator expression?

I guess you cannot `throw` or even `try / catch / finally` there ... which
is just about it: any valid expression would do.


Regards


On Wed, Sep 20, 2017 at 12:09 PM, Naveen Chawla <naveen.chwl at gmail.com>
wrote:

> 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/a673bb1a/attachment-0001.html>


More information about the es-discuss mailing list