Proposal: result-forwarding ternary operator

Isiah Meadows isiahmeadows at gmail.com
Wed Sep 20 09:49:37 UTC 2017


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


More information about the es-discuss mailing list