Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potentially eliminating the case of === #856

Closed
dcodeIO opened this issue Sep 20, 2019 · 6 comments · Fixed by #2157
Closed

Potentially eliminating the case of === #856

dcodeIO opened this issue Sep 20, 2019 · 6 comments · Fixed by #2157

Comments

@dcodeIO
Copy link
Member

dcodeIO commented Sep 20, 2019

It has been suggested various times to align the use of the === operator to what JS/TS would do, which came also up again in a recent issue (I don't remember which one), suggesting to replace our special === semantics with changetype<usize>(a) == changetype<usize>(b) in standard library code, which is about the only place where this is of importance. Overall this change would make === and == behave exactly the same for string operands and drop the special meaning of someObject === someObject, replacing it with something else where necessary.

Considering the general confusion introduced by this, I am leaning towards this solution. Thoughts?

@dcodeIO
Copy link
Member Author

dcodeIO commented Sep 20, 2019

This turns out to be a bigger feat than expected. Because a === null compiled down to an i32.eq(a, 0) that was precomputable by Binaryen, but a A#__eq(0) isn't anymore, leading to all sorts of issues that must be solved first. Take for example

function test(): string {
  if (a !== null) return a; // now results in an "is possibly null" error
  return "";
}

This a more general issue under the hood that we already have with anything that implements custom == / != overloads, but now surfaces due to applying it to strings in all cases.

@dcodeIO
Copy link
Member Author

dcodeIO commented Sep 20, 2019

The easiest solution seems to be to do the identity check as an additional one to overloads that one can't override, looking somewhat like

// equality
i32.eq(a, b) ? true : A#__eq(a, b)

// inequality
i32.eq(a, b) ? false : A#__ne(a, b)

but that will limit what the overloads can do in the identity-equal case and introduces a branch.

A proper but radical solution would be to drop support for overloads entirely and build string comparison into the compiler, with alternative solutions going into the direction of building our own interpreter.

A half-baked solution would be to disallow overriding == and != and bake only those into the compiler, but I'd say that having > etc. overloads with no way to also override == is, well, meh.

@dcodeIO
Copy link
Member Author

dcodeIO commented Sep 21, 2019

Currently thinking about moving null checking to the type system, adding a third reference type variant alwaysNull to the existing nullable and nonNullable variants, with the implication that flows then need a way to remember the "actual" type of locals in addition to the declared type at any given point.

@mbrowne
Copy link

mbrowne commented Jun 21, 2020

Why not just introduce a new operator? I think this would avoid the confusion and probably be easier to implement too. For example:

if (a is b)

There could also be a negative form:

if (a isnt b)

...although of course that would be for convenience/readability, since if (!(a is b)) would do the same thing.

@mbrowne
Copy link

mbrowne commented Jun 21, 2020

...When I wrote the above, I forgot about the fact that is is already an operator in TypeScript (used just in types, not actual executable code). But although this could potentially introduce a new confusion, I think it would be less than the confusion of repurposing ===. Or of course you could also invent some other operator, e.g. isSame.

@cyberixae
Copy link

I'm expecting my AssemblyScript code to compile as TypeScript and produce a JavaScript program that works as a drop in replacement for the WebAssembly module. Both modules should ( eventually ) support loading with import and be 100% compatible so that A/B testing of TypeScript/AssemblyScript modules becomes trivial. I think such interoperability is more important than any convenience feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants