Proposal: result-forwarding ternary operator

classic Classic list List threaded Threaded
24 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Proposal: result-forwarding ternary operator

Michael Rosefield

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Isiah Meadows-2

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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Sebastian Malton
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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Andrea Giammarchi-2
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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Michael Rosefield
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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Isiah Meadows-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Andrea Giammarchi-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Isiah Meadows-2

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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Andrea Giammarchi-2
oh gosh, I've stopped at the title. I guess I'll just move on then ^_^

On Wed, Sep 20, 2017 at 11:14 AM, Isiah Meadows <[hidden email]> wrote:

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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Naveen Chawla
In reply to this post by Isiah Meadows-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Isiah Meadows-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Naveen Chawla
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Andrea Giammarchi-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Naveen Chawla
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.

Sent: September 19, 2017 8:57 AM
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 <[hidden email]> wrote:

(I've also put this on reddit, 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, 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

T.J. Crowder-2
On Wed, Sep 20, 2017 at 11:28 AM, Naveen Chawla <[hidden email]> wrote:
>
> The comma operator seems to make the `do` concept redundant, at
> least for me.

No, not at all. Again: With the comma operator, you can't use *statements*, only expressions. With the `do` expression, you can use actual statements:

```js
const x = do {
    for (const x of getTheThings()) {
        if (x.id == something) {
            x.foo;
        }
    }
};
```

...which is basically:

```js
const x = getTheThings().find(x => x.id == something).foo;
```

...except it doesn't throw if `find` returns `undefined`, and isn't a series of function calls.

`do` expressions are basically to address overly-complex conditional expressions and IIFEs.

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Bob Myers
Could you please clarify how the system would know that some random expression in the middle of something like this for/if construct should be treated as a sort of "return"? I can understand that the **last** expression in a block would be the return value, but how would it know that `x.foo` was an implicit return? By the way, in current iterations of the `do` concept is there a `return`?
```js
const x = do {
    for (const x of getTheThings()) {
        if (x.id == something) {
            x.foo;
        }
    }
};
```

On Wed, Sep 20, 2017 at 4:11 PM, T.J. Crowder <[hidden email]> wrote:
On Wed, Sep 20, 2017 at 11:28 AM, Naveen Chawla <[hidden email]> wrote:
>
> The comma operator seems to make the `do` concept redundant, at
> least for me.

No, not at all. Again: With the comma operator, you can't use *statements*, only expressions. With the `do` expression, you can use actual statements:

```js
const x = do {
    for (const x of getTheThings()) {
        if (x.id == something) {
            x.foo;
        }
    }
};
```

...which is basically:

```js
const x = getTheThings().find(x => x.id == something).foo;
```

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

T.J. Crowder-2
On Wed, Sep 20, 2017 at 12:52 PM, Bob Myers <[hidden email]> wrote:
>
> Could you please clarify how the system would know that some
> random expression in the middle of something like this for/if
> construct should be treated as a sort of "return"?

Sorry, my example was missing a `break`. And it may have been off, since the `break` (rather than `x.foo`) would be the last executed statement. The main point was: You can use statements in `do` expressions, not with the comma operator.

> By the way, in current iterations of the `do` concept is there
> a `return`?

As far as I could tell reviewing the discussion hat the TC39 proposals list refers to, it hasn't been decided. As someone points out in the comments, with `return` it's effectively an IIFE. Folks seem quite interested in `do` expressions but I'm having trouble seeing much need for them in a world with IIFEs and arrow functions:

```js
const x = (() => {
    for (const x of getTheThings()) {
        if (x.id == something) {
            return x.foo;
        }
    }
})();
```

I mean, yes, even with `return` the `do` expression version of that would be *slightly* more concise, but...

We're off-topic, though. This is about `do` expressions. The thread is about "result-forwarding ternary operators".

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Andrea Giammarchi-2
combining all the things (arrow with implicit return + arguments default + ternary)

```js
const newFoo = ((x = getSomething()) => x ?
  (doSomethingFirst(), x.doSomething()) :
  doSomethingElse()
)();
```

So yeah, we probably don't need yet another pattern/new syntax to do that.

Regards



On Wed, Sep 20, 2017 at 2:04 PM, T.J. Crowder <[hidden email]> wrote:
On Wed, Sep 20, 2017 at 12:52 PM, Bob Myers <[hidden email]> wrote:
>
> Could you please clarify how the system would know that some
> random expression in the middle of something like this for/if
> construct should be treated as a sort of "return"?

Sorry, my example was missing a `break`. And it may have been off, since the `break` (rather than `x.foo`) would be the last executed statement. The main point was: You can use statements in `do` expressions, not with the comma operator.

> By the way, in current iterations of the `do` concept is there
> a `return`?

As far as I could tell reviewing the discussion hat the TC39 proposals list refers to, it hasn't been decided. As someone points out in the comments, with `return` it's effectively an IIFE. Folks seem quite interested in `do` expressions but I'm having trouble seeing much need for them in a world with IIFEs and arrow functions:

```js
const x = (() => {
    for (const x of getTheThings()) {
        if (x.id == something) {
            return x.foo;
        }
    }
})();
```

I mean, yes, even with `return` the `do` expression version of that would be *slightly* more concise, but...

We're off-topic, though. This is about `do` expressions. The thread is about "result-forwarding ternary operators".

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Naveen Chawla
In reply to this post by T.J. Crowder-2
As your example shows, for loops can be reduced to array reduction function calls. `if` `else`s can be represented by ternaries.

`while` loops aren't so straightforward but can be factored into single function calls. They are less common anyway.

I find single expressions listed as `(a, b, c)` more readable than code blocks who eventually evaluate to a single value each.

So, even if `do` expressions were introduced into ES, I would avoid using them as much as I could, unless it were really smarter and more readable to use them than any of the alternatives

On Wed, 20 Sep 2017 at 16:11 T.J. Crowder <[hidden email]> wrote:
On Wed, Sep 20, 2017 at 11:28 AM, Naveen Chawla <[hidden email]> wrote:
>
> The comma operator seems to make the `do` concept redundant, at
> least for me.

No, not at all. Again: With the comma operator, you can't use *statements*, only expressions. With the `do` expression, you can use actual statements:

```js
const x = do {
    for (const x of getTheThings()) {
        if (x.id == something) {
            x.foo;
        }
    }
};
```

...which is basically:

```js
const x = getTheThings().find(x => x.id == something).foo;
```

...except it doesn't throw if `find` returns `undefined`, and isn't a series of function calls.

`do` expressions are basically to address overly-complex conditional expressions and IIFEs.

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: result-forwarding ternary operator

Michael Rosefield
There was a suggestion that came up in my original reddit post that I think merits discussion here.

I know one of the main arguments against this new operator is to prevent needless and confusing language explosion, but u/notNullOrVoid pointed out that this bears similarity to another operator already under TC39 consideration, the pipeline-operator (https://github.com/tc39/proposal-pipeline-operator).

My suggestion could then be implemented as follows:

const foo = getSomething() |> x => x ? dosomething(x) : doSomethingElse();
 
And this ternary could be simply a pipeline variant:

const foo = getSomething() ?> x => dosomething(x) : doSomethingElse();

That reads much clearer and also takes care of the syntactically invalid ?! formularion.

On Wed, 20 Sep 2017 at 14:22 Naveen Chawla <[hidden email]> wrote:
As your example shows, for loops can be reduced to array reduction function calls. `if` `else`s can be represented by ternaries.

`while` loops aren't so straightforward but can be factored into single function calls. They are less common anyway.

I find single expressions listed as `(a, b, c)` more readable than code blocks who eventually evaluate to a single value each.

So, even if `do` expressions were introduced into ES, I would avoid using them as much as I could, unless it were really smarter and more readable to use them than any of the alternatives

On Wed, 20 Sep 2017 at 16:11 T.J. Crowder <[hidden email]> wrote:
On Wed, Sep 20, 2017 at 11:28 AM, Naveen Chawla <[hidden email]> wrote:
>
> The comma operator seems to make the `do` concept redundant, at
> least for me.

No, not at all. Again: With the comma operator, you can't use *statements*, only expressions. With the `do` expression, you can use actual statements:

```js
const x = do {
    for (const x of getTheThings()) {
        if (x.id == something) {
            x.foo;
        }
    }
};
```

...which is basically:

```js
const x = getTheThings().find(x => x.id == something).foo;
```

...except it doesn't throw if `find` returns `undefined`, and isn't a series of function calls.

`do` expressions are basically to address overly-complex conditional expressions and IIFEs.

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12