Skip to content

class defined without constructor does not pass instanceof check? #3722

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

Closed
blitmap opened this issue Nov 13, 2014 · 5 comments
Closed

class defined without constructor does not pass instanceof check? #3722

blitmap opened this issue Nov 13, 2014 · 5 comments

Comments

@blitmap
Copy link

blitmap commented Nov 13, 2014

I have this code:

class Array2 extends Array
    # it works on codepen.io when this is uncommented:  (why?)
    # http://codepen.io/anon/pen/ZYEOvb
    # constructor: -> super

    @is_equal: (a, b) ->
        return false unless a instanceof Array2
        return false unless b instanceof Array2
        return true  if a is b
        return false if a.length isnt b.length
        return false for v, i in a when v isnt b[i]
        return true

tmp1 = new Array2 '!'
tmp2 = new Array2 '!'
alert Array2.is_equal tmp1, tmp2

I'm trying to understand why Array2's constructed from this class definition do not pass the instanceof check in Array2.is_equal().

I've been staring at this for a while so I'm not sure if I'm just missing something obvious. I thought if you did not define a constructor it would be implicitly generated? When I uncomment that line the only change is Array2.prototype.constructor is defined, but it looks identical to the Array2 function.

Is this by design? What am I doing wrong?

PS: It works on codepen.io when I uncomment that line, but it does not work locally when I run it through my copy of CF 1.8. This makes me doubly confused :( I'm thinking codepen uses 1.7, which means something must have changed?

@blitmap blitmap changed the title class definition without constructor does not pass instanceof check? class defined without constructor does not pass instanceof check? Nov 13, 2014
@vendethiel
Copy link
Collaborator

See #2359 and everything that happened around that...

@blitmap
Copy link
Author

blitmap commented Nov 13, 2014

Thank you for pointing me to the explanation.

I do think the schenario @epidemian details at the end is the correct behavior, though. I wish Coffeescript took it up.

class Something
  constructor: ->
    return new SomethingElse()

class SubSomething extends Something
  # implied constructor: -> super

^ If this had been written in Javascript, SubSomething.prototype would be new Something not new SomethingElse -- SomethingElse() wouldn't exist in the prototype chain even if it acts as an external constructor.

I think it would be correct to expect those results:

(new Something) instanceof Something # => false
(new Something) instanceof SomethingElse # => true (as "expected", because Something has an other typed constructor)
(new SubSomething) instanceof SubSomething # => true
(new SubSomething) instanceof SomethingElse # => false (it didn't inherit the constructor of Something, even if we didn't override it!)

I'm going to go cry in the shower now. what a reality we live in :'[

@epidemian
Copy link
Contributor

I'm going to go cry in the shower now. what a reality we live in :'[

Yeah, i confess i also feel a bit bad every time this issue is revived. It's been long since i was bitten by this behaviour though – i think i've learned not to rely that much on prototypal inheritance 😅

^ If this had been written in Javascript, SubSomething.prototype would be new Something not new SomethingElse -- SomethingElse() wouldn't exist in the prototype chain even if it acts as an external constructor.

But new Something is new SomethingElse. SubSomething.prototype should be Object.create(Something.prototype), which won't be an instance of SomethingElse. This is what CS basically does with the surrogate constructor technique.

@blitmap
Copy link
Author

blitmap commented Nov 14, 2014

@epidemian: I just think if you're using an external constructor to return an other-typed object from the constructor of another class (Something), then it wasn't your intention for the returned object to be of type Something, and this would all be the expected behavior. :p I dunno, I've told myself I need to always explicitly write the constructor even though I embraced CS for not having to write a lot of boilerplate :3 Perhaps this problem would be better solved by making a note in the help text? I was surprised by it, but I can learn around it.

@epidemian
Copy link
Contributor

@pogs, sorry, i wasn't clear. All i was trying to say is that if you want to have this behaviour...

(new Something) instanceof Something # => false
(new Something) instanceof SomethingElse # => true (as "expected", because Something has an other typed constructor)
(new SubSomething) instanceof SubSomething # => true
(new SubSomething) instanceof SomethingElse # => false (it didn't inherit the constructor of Something, even if we didn't override it!)

... the prototype of SubSomething should not be new Something (jsFiddle, yields false, true, true, true). It should be Object.create(Something.prototype) (jsFiddle, has the expected behaviour).

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

No branches or pull requests

3 participants