Proposal: result-forwarding ternary operator

Naveen Chawla naveen.chwl at gmail.com
Wed Sep 20 10:28:52 UTC 2017


The comma operator seems to make the `do` concept redundant, at least for
me. Yes it forces ternaries like in my last example (as opposed to being
able to express it via `if` `else`), but I prefer that anyway

On Wed, 20 Sep 2017 at 15:47 Andrea Giammarchi <andrea.giammarchi at gmail.com>
wrote:

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


More information about the es-discuss mailing list