'maybe' operator to complement ?? operator

Essentially: proposed maybe operator is a logical inversion of ?? operator.

Maybe operator a !? b : evaluate expression b if expression a is not nullish.

res = isNulish(a)  ? a : b;

Practical use:

var celsius; 
var fahrenheit  =  celsius !? celsius * 9 / 5 + 32;
// no error and fahrenheit is undefined as celsius is undefined too.

We simply need this, although the 'appropriate' syntax is &?. Using ?? for nullish coalescing was unfortunate:

In proposing the nullish coalescing operator ??, there is not much discussion aside from a reference to C#, from which the ?? syntax was borrowed.
However, this is shortsighted, since C# uses boolean logic, while ES uses truthy logic. We take advantage of the fact that ES && and || operators will return the actual value of the first operand when short-circuiting occurs, rather than true and false. C# cannot do this, and so is inappropriate to borrow from directly.

In the sense that && mathematically complements || in truthy logic, we should have added together the operators &? and |?. Here, |? is the proper name for what we today call ??, and &? is its complement. The usage of & and | as the first character of the operator is an obvious and natural allusion to the closely related && and || operators, and similarly connotes their complementary nature. Indeed, we can regard &? and |? as narrowing/specializing && and ||, respectively, so the naming is quite appropriate.

The common names for &? and |? can be simply "nullish AND" and "nullish OR", respectively. Note that where some references define && and || as "logical AND" and "logical OR", it should be clear by now that there are multiple types of "logic" at play (Boolean, nullish, truthy, etc.) and we should be specific. We love ES's truthy logic and are also now embracing nullish logic!

The need for the &? operator comes up in many cases, as you might expect being the proper mathematical complement of ?? (ahem.. |?). One example is in using DataLoaders in a GraphQL resolver, where one needs to guard that the key is not nullish, but allow zero as a key. We cannot use && and we would like to use &?.

({ key }) => key &? loader.load(key)

Without this, we resort to a silly type predicate function in TypeScript:

export const ok = <T>(value: T): value is Exclude<T, null | undefined> =>
  // double `not equal` is the operator we need here (`null == undefined`)
  (value != undefined || undefined) as boolean;

used as

({ key }) => ok(key) && loader.load(key)

Note that we had to force-cast the result in TypeScript to be able to use a truthy result where a boolean result is expected.

Unfortunately, we also defined ??= which carries on the inappropriate C# nomenclature.

There is also @claudiameadows's nullish checking pipeline idea (https://github.com/tc39/proposal-pipeline-operator/issues/159) as an alternative solution.

let fahrenheit  =  celsius ?> (c => c * 9 / 5 + 32);
down level compiles to:
let fahrenheit = (celsius !== null && celsius !== undefined)
 ? celsius * 9 / 5 + 32
  : void 0;

The question of pipeline operators should be treated separately. The proposed pipeline operator |> has not seen much traction yet. I expect primarily because ES does not curry its function arguments. There is then the whole question of pipeline operators for 2 and 3 arguments, hence the ||>, |||>, <|, <||, <|||, ..., as in F#. Quite a quagmire.

From my GraphQL resolver example, it often happens that the key is composite, coming from a destructuring. In that case, we immediately see that the pipeline needs to support multiple arguments to be useful:

({ key1, key2, key3 }) => 
  key1 &? key2 &? key3 &? loader.load({ key1, key2, key3 })

Also note, that there is no need to introduce a lambda expression and pipelines where an appropriate operator will suffice. The operator already short circuits and does not evaluate the right hand side in that case.

The pipeline operator has had a lot of discussion, but that is a good thing. We shouldn't rush things into the language. This idea does come up frequently, so it definitely feels like a problem worth solving. Hopefully someone on the committee agrees.

1 Like

@aclaymore Thanks for the references. I do hope the committee take this forward.

1 Like