-
-
Notifications
You must be signed in to change notification settings - Fork 670
Tackle the case of === #1111
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
Tackle the case of === #1111
Conversation
i32.const 160 | ||
i32.const 160 | ||
call $~lib/string/String.__eq |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Seems this force full string equal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the downside is that we cannot precompute ===
string comparisons anymore. Previously, ===
compiled to just an i32.eq
due to the differing semantics, which is trivial to precompute, while it now calls the overload.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Hope increase limits for inlining helps with this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes me wonder if we can handle strings differently, by doing something like i32.eq(lhs, rhs) | String.__eq(lhs, rhs)
where Binaryen can see that this is trueish and potentially eliminate the overload call. But looks like temp locals will become a problem there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I prefer use overloading for string operators. It simplify compiler and the same time show more explicitly what's doing on. Also it allow inherit String class and overload any operator which also pretty flexible.
I guess tuning inline params need anyway and this will helps with this. Also it could be done earlier in MIR part in future as part of StdLibSimplify pass
|
||
if (ASC_SHRINK_LEVEL < 1) { | ||
if (isString<T>()) return joinStringArray(dataStart, length, separator); | ||
} | ||
// For rest objects and arrays use general join routine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this conditional guard potentially decreased code size so recommend leave as is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not sure about this one as well. Removed it because joinReferenceArray
wasn't compatible with strings anymore, but there's probably something better we can do.
hmm.. if going this way, wouldn't this mean that we'd also have to do type conversion for Sure we are getting more like typescript/javascript this way, but do we really want/need to go there? I'm not sure. It's good that AssemblyScript is familiar for JS/TS developers, on the other hand it's good that there are some differences that preserves the "low level mindset". |
@petersalomonsen No, it's about remove special meaning for |
yes @MaxGraey - my point was just that if going in that direction, wouldn't the next expectation (demand from users) be that we do type conversion for
|
Typescript also restrict "10" == 10 due to |
ahh good point :-) very well then 👍 thanks for clarifying :-) |
Appears this breaks null checking because, when compiling to Wasm, the compiler can't predict how every single overload turns out, affecting code like
where One solution would be to add special cases for if any argument is a literal |
I guess all this could be solved using some top reference type like |
Seems to conflict with our goal to make stuff properly virtual eventually. In such a case the code would still virtually call the top-most overload. Related: #1152 |
Multiple solutions:
Preferring either 2 or 3. |
In C# for example operators cannot be virtual. In Java you could overload only '+' and it can't be also virtual. So I suggest also restrict polymorphism for overloaded operators because it produce many problems and performance issues |
|
In this case |
Is not a good solution due to we already have some codebases which based on this feature. Also it quite nice feature and JavaScript try to find way to it |
Basically all languages have some sort of operator overloading except of JavaScript =) |
Last commit addresses these issues by inlining part of the Also means that anyone implementing these overloads must do the same if null checking is relevant to them. Upside is that it's all still possible, downside is that it requires users to understand the ins and outs of those specific overloads. |
An alternative implementation might be to internalize the |
Hmm. May be better inline |
|
This now should bring us closer to efficient code in that the One side effect is that we can't allow top-level var someGlobal: string; without an initializer anymore because flows can't track when the global is becoming initialized. Hence, reference-typed globals now require either an initializer or a nullable type. Example: var someGlobal: string;
function a(): void {
someGlobal = "123";
}
function b(): void {
someGlobal.length; // not known to b's flow
}
a(); // commenting this out will break the runtime
b(); |
var someGlobal: string;
function a(): void {
someGlobal = "123";
}
function b(): void {
someGlobal.length; // not known to b's flow
}
a(); // commenting this out will break the runtime
b();
Basically it's normal and expected behaviour but will be great handle (emit error) about uninitialised global in compile time ofc |
Quick heads up: WebAssembly/binaryen#2702 has just been merged |
So are we switching I can't wait to see if |
btw some people uses class SomeContainer<K, V> {
find(key: K): V {
if (this.root.key === key) {
...
}
}
} |
This is an experiment of what has to be done to make
===
not-so-special anymore, essentially degrading it to an alias of==
with no special semantics. While we'll lose the ability to do safe identity comparisons, feedback has shown that the special semantics we had compared to TS are hard to justify.===
and!==
in the standard library with pointer opsstring | null
null
anywaystd/array
testWould be a breaking change for users depending on the old semantics.