-
Notifications
You must be signed in to change notification settings - Fork 570
Make nil == null, js.Undefined == undefined a bijection. #240
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
Conversation
Ok, good, the tests I've added are indeed failing now, which is expected: |
Woohoo, everything works! Tests pass, including old tests, and newly added tests. Now that's the case, next step would be to see if the code can be refactored to be simpler/more direct/better. @neelance, please take a look and review. |
@@ -372,7 +372,7 @@ var $internalAppend = function(slice, array, offset, length) { | |||
|
|||
var $equal = function(a, b, type) { | |||
if (type === $jsObjectPtr) { | |||
return a === b; | |||
return a === b || (a.hasOwnProperty("object") && a.object === undefined && b.hasOwnProperty("object") && b.object === undefined); |
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.
It might make sense to factor out this "if both a and b are undefined, return true" check out into $interfaceIsEqual
, since that's where "if both a and b are nil interfaces, return true" happens. I wasn't sure which is better.
Also, I am unsure about the way "if both a and b are undefined" is being checked. It seems to work, but maybe there's a much better JavaScript way?
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.
As I've written in the other comments, the *js.Object
type holds the JS value itself. So when comparing two undefined
, the JS value in a
would be undefined
and b
would also be undefined
. So a === b
holds.
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.
Unless I change something else elsewhere, a === b
did not hold. That's why I needed to add the "or" block. If you remove it, tests will not pass.
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.
Why was this necessary? Which test was failing?
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.
This change is really not the correct way. If something fails, then we'll have to look for the bug somewhere else. ;-)
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.
Have you reviewed #237? This PR is to fix the issue described there, and it uses the solution I proposed. I should make sure you agree with that proposal first, before we discuss its implementation details.
Why was this necessary? Which test was failing?
The test for #237 that I added.
Namely, calling js.Global.Call("eval", "(foo(null))"))
would print expected output, but calling js.Global.Call("eval", "(foo(undefined))")
would print:
x: undefined
x == nil: false
x == js.Undefined: false
Instead of:
x: undefined
x == nil: false
x == js.Undefined: true
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.
In the x == js.Undefined
case, a
and b
on this line should end up being the JS value undefined
. But this does not happen. The issue is in $interfaceIsEqual
, which does not correctly unwrap the JS value. It already shows with this simple test:
var i interface{} = js.Undefined
println(i == js.Undefined)
So $interfaceIsEqual
needs to be fixed. I think it does not even need to call $equal
in this case, because this just boils down to a === b
which can be inlined.
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.
That sounds like the way to go. How should I unwrap the undefined
value in $interfaceIsEqual
?
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.
Just get the object
field. Check for the type first, then you don't need hasOwnProperty
.
The tests in I am grateful that you wanted to tackle this bug, but it seems to me like you are not aware about how |
No problem, it's true that I am poorly familiar with internal details of GopherJS compiler, in fact this was my first time trying to make a PR for it, so I expected that even if I got it to work and pass tests, there's still a high chance my entire approach is wrong or there's a simpler, better, more direct way to accomplish it. In addition to try to help fix this issue, it was meant to be a learning experience so I could make better contributions in the future, which is why I appreciate the explanations.
Is this documented somewhere? I thought the Note that I initially wrote the if guard like this: if runtime.GOARCH == "js" { ... } But then changed it. Anyway, I thought importing |
The mocks are there for type checking, |
In short: The behavior of the |
Ok. How would you like to proceed? Do you want to give me actionable feedback to change this PR so it can be accepted, or do you want to do this yourself? |
I would love to help you. I'll post some comments on the code. |
@@ -4,7 +4,7 @@ machine: | |||
|
|||
dependencies: | |||
pre: | |||
- cd /usr/local && sudo rm -rf go && curl https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gz | sudo tar -xz && sudo chmod a+w go/src/path/filepath | |||
- cd /usr/local && sudo rm -rf go && curl https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz | sudo tar -xz && sudo chmod a+w go/src/path/filepath |
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.
Separate commit pls.
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.
Done in a55786e.
Just to prove how little I knew when I began working on this PR, you can see my WIP commit here from when I just got it to work, before I cleaned up all the debugging/test code. :P |
Catch and handle the case of both values being js.Undefined in $interfaceIsEqual. Place this check underneath the check for (a.constructor !== b.constructor) as an optimization. Related to #237.
I've addressed all your feedback, PTAL. I've moved the Go 1.4.1 -> 1.4.2 update into a separate commit. I've removed the I've broken down the verbose tests into minimal previously-failing tests. There are now two compiler commits:
All tests are passing. Please review again and let me know how this looks. |
Commit cb553f3 fixes the issue for when both *js.Object were undefined. This change makes that fix general and apply when the value of the two *js.Object is anything.
LGTM |
Make nil == null, js.Undefined == undefined a bijection.
This PR is a work in progress.
Fixes #237.