Skip to content

mk-pmb/es-fallback-first-defined-value

Repository files navigation

Suppose a robot that can add sugar cubes to beverages. It has several methods for deciding how many sugars to add, so there must be some code that determines the highest-priority answer.

The nonsolutions

Each of these have a code demo and comments about their problems in sugars.js:

Strategy nice code lazy eval correct result¹
temporary variable ☐ ☑ ☑
just use || ☑ ☑ ☐
|| wrap(…) ☐ ☑ ☑
[ …values ].find() ☑ ☐ ☑
[ …functions ].reduce() ☐ ☑ ☑

¹ Without lazy eval, "correct result" can only be half because gratuitous evaluation of the later expressions might have modified the (meaning of the) result or might have thrown an Error.

New syntax to the rescue!

First defined value:

  var n = (guessFromColor(bev)
    ?| queryHwdb(bev.idVendor, bev.idProduct)
    ?| (cfg || false).defaultSugars
    ?| surpriseMe(bev)
    );
  • Precedence like ||
  • Picks the next value in the chain until it encounters a value that is defined (!== undefined).
  • Code from sugars.js. More details there.

Custom decider function:

  var n = ( ?| checkAcceptable
    : guessFromColor(bev)
    : n2u(queryHwdb(bev.idVendor, bev.idProduct))
    : (cfg || false).defaultSugars
    : surpriseMe(bev)
    // Beware: If there was no acceptable value, you still get the last one!
    // So better append either a default value, or a last resort:
    : test.fail('No acceptable value!')
    );
  • Precedence like … ? … : …
  • Picks the next value in the chain until it encounters a value for which the decider function returns a truthy value.
  • Code from sugars.js. More details there.

Q&A

Neat, where's the babel plugin?

I wish I had one. For now the tests use a RegExp-based pseudo-transpiler.

What if I want to accept null or undefined but not false?

Use a custom decider function. If it's just about null, vote a thumbs-up emoji on issue #4.

No. I'd really like to have an SNO in JavaScript as well, but SNO is for diving deep into an object, whereas this proposal is about a decision chain with several unrelated values.

I don't care about people who want 0 sugars.

Then instead let's calclulare the amount of damage your character takes, or how many ads to show before a funny cat video.

Optional extensions

Feature creep galore.

Individual criteria:

  (undefined        // <- redundant   // [1]
    ?|: pureWhite           cloud1()  // [2]
    ?|: colorful            cloud2()
    ?|: colorful            cloud3()
    ?|  undefined   // <- just to show you can mix them.
    ?|: (codepoint.odd)     cloud4()
    ?|: (codepoint.odd)     cloud5()
    ?|: (codepoint.even)    cloud6()
    ?|: ((Date.now() % 3) ? codepoint.odd : pureWhite)   cloud7()
    ?|: (codepoint.ascii)   cloud8()  // [3]
    ?|: dontBotherMe        cloud9()  // [4]
    ?|: colorful            auroraBorealis()
    ?|  { error: "Couldn't find any. :-(" }
  ),
  • Precedence of |?: is same as |?
  • |?: works mostly like |? but with a custom criterion for the (one) next candidate value.
    • If you want to avoid the above repetitions, just open a new level or parens for a chain with a custom decider function.
  • Code from flakes.js. More details there.

Hindsight

  • Custom decider functions get the chain's previous value as 2nd argument. Details: hindsight.js

 


License: ISC

About

Suggesting a new fallback operator for ECMAScript, like || but stops at first defined (!== undefined) value.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published