Proposal: result-forwarding ternary operator

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


This is starting to seem eerily familiar... (especially the idea of "let"
expressions)

Take a look at this thread from a couple years ago, and you'll see what I
mean.

https://esdiscuss.org/topic/the-tragedy-of-the-common-lisp-or-why-large-languages-explode-was-revive-let-blocks

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

> gotta admit an `if (let y = fn())` would be a very nice feature to have.
> Only the `for(...)` lets us declare block variables, the `let` expression
> would solve/simplify this case and many others.
>
> ```js
> const newFoo = (let x = getSomething()) ?
>   (doSomethingFirst(), x.doSomething()) :
>   doSomethingElse();
> ```
>
> On Wed, Sep 20, 2017 at 10:41 AM, 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
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170920/b7715a21/attachment-0001.html>


More information about the es-discuss mailing list