Strict (non-coercing) expressions

# T.J. Crowder (7 years ago)

In the thread on strict relational operators, felix suggested an expression mode affecting all operators:

Maybe every operator can have a non-coercing variant?

One possible syntax is to have a modifier on operators

x = a (<) b (+) c (&&) (!)d;

if (x (!=) y) ...

Another possible syntax is to have a modifier on expressions

x = #(a < b + c && !d)

if #(x != y) ...

I thought the idea deserved its own thread. It's much broader in scope than strict relational operators, and not exclusive with them.

I quite this idea of an expression mode making all operators within it non-coercing, and having them throw a TypeError when presented with mixed types. Using flagged parentheses (I didn't want to say "decorated") seems like a great way to do it, too:

if #(a > b) { /*...*/ }

while #(a > b) { /*...*/ }

for #(let i = 0; i < a.length && a > b; ++i) { /*...*/ }

if (answer == 42 && #(a > b))  { /*...*/ }

(Note the intentially-loose answer == 42 in that last one.)

Which raises the question of possibly extending that concept to the block level, where all expressions in the block are strict:

#{
    if (a > b) { /* ... */ }
    //    ^-- Throws if a and b are not the same type
}

If you like strict comparisons, a #{ /*...*/ } wrapper around all the code in your module is all you need...

Or for just a function:

function foo() #{ // <== Note the #
}
const foo = () => #{
}

I wonder if people would then ask for an explicitly-loose version of ! (or, indeed, other operators)... :-)

-- T.J. Crowder

# Bruno Jouhier (7 years ago)

I like the idea of a block level annotation. Lighter and more practical than a new set of operators. Module level would be nice too. OTOH expression level feels a bit like overkill.

Why not turn this into a more general pragma syntax then? This would allow us to control other special conditions: throw on overflow, on divide by zero, etc.

# Mark S. Miller (7 years ago)

On Thu, Apr 13, 2017 at 11:08 AM, Bruno Jouhier <bjouhier at gmail.com> wrote:

I like the idea of a block level annotation. Lighter and more practical than a new set of operators. Module level would be nice too. OTOH expression level feels a bit like overkill.

Why not turn this into a more general pragma syntax then?

We already have a pragma syntax. So how about

"use coercions, not!";

Just kidding about the actual text, but this "use x"; pragma pattern was meant to be usable for more than just "use strict";. This pragma syntax was designed to be ignored on versions of the language that do not yet recognize the pragma. Such version compat seems appropriate for the issue we're discussing.

# Bruno Jouhier (7 years ago)

“use …”, of course!

# Bruno Jouhier (7 years ago)

The "use ..." syntax could be extended to expressions:

const foo = "use !div-by-0" && bar / zoo;
# Isiah Meadows (7 years ago)

Just a quick FYI, nobody on TC39 likes adding directives known to the core language - they aren't too keen on Perl's tendency towards them.

Isiah Meadows me at isiahmeadows.com

# Bruno Jouhier (7 years ago)

I don't know the ins and outs of the "nobody likes", I'll just respond as a "language user".

We do not expect NaN in 99.99% of our code, and we do not expect infinities in 99.95% of it. Instead of having these values creep unnoticed though the computations (and else branches executed because tests are silently false) it would be better to have them turned into exceptions (fail fast).

With a pragma I would just set the fail fast default at the top of every module and override it in the few functions where special values are expected. Impact will be low and code will remain familiar.

With a new set of operators, I'll have to replace the operators (almost) everywhere in the code. I'll also have to create a new lint rule to enforce the new operators everywhere, and I'll need to introduce a lint directive for the exceptions. Big impact and code will look strange.

Obviously I prefer the pragma solution but I don't really care about the pragma syntax. If "use ..." does not cut it there are other ways (contextual pragma keyword?).

Bruno

# Claude Pache (7 years ago)

Le 13 avr. 2017 à 08:39, T.J. Crowder <tj.crowder at farsightsoftware.com> a écrit :

In the thread on [strict relational operators][1], felix [suggested][2] an expression mode affecting all operators:

Maybe every operator can have a non-coercing variant?

One possible syntax is to have a modifier on operators

x = a (<) b (+) c (&&) (!)d;

if (x (!=) y) ...

Another possible syntax is to have a modifier on expressions

x = #(a < b + c && !d)

if #(x != y) ...

I though the idea deserved its own thread. It's much broader in scope than strict relational operators, and not exclusive with them.

I think that, in general, “implicit coercion” is not the real issue, although it makes things worse in some cases. The real issue is “ambivalent meaning”.

For example, + is so problematic in JS because it has two contradictory meanings: addition and concatenation.

On the other hand, < is less problematic, because there is much rarely a situation where it is ambiguous (for a human).

Another example:

var a = new Date
var b = new Date(a)
a <= b // true
a < b // false
a == b // probably not what you mean

In this case, “stricter” is not helpful in the “equality” test. What would have helped, is comparison operators with non-ambivalent meanings. E.g., Perl has == for numerical comparison, eq for string comparison, and, since v6, eqv for structural comparison, === for identity comparison, =:= for...

# Rick Waldron (7 years ago)

On Sat, Apr 15, 2017 at 7:02 AM Bruno Jouhier <bjouhier at gmail.com> wrote:

I don't know the ins and outs of the "nobody likes", I'll just respond as a "language user".

The committee, which is now comprised of more practitioners/language users than runtime implementors and academics combined, has done everything it possibly can for 8 years (ES5 was first published in 2009) to avoid introducing new directives.

# Bruno Jouhier (7 years ago)

Fine. I'm -1 on this feature if it means adding whole sets of new operators, and +1 if it can be implemented with a directive. So -1 it will be.