5 ms·
As stated in the text, for `super` calls to work within a method, it’s necessary to know the class on which the method is defined. Here, that’s easy - it’s the
by pansa2 7y ago
As stated in the text, for `super` calls to work within a method, it’s necessary to know the class on which the method is defined. Here, that’s easy - it’s the class that the method is lexically defined within.
This is more difficult in a language which allows methods to be added to classes dynamically. IIRC both Python and JavaScript are in this category, but still calculate `super` lexically. Therefore, if a method is copied from one class to another, `super` within that method may refer to the wrong class.
- wool_gather 7y agoInteresting point. I'd have to look at my implementation to be sure, but Lox will also have this quirk, won't it? You can freely assign values, (as I recall) including functions, to a property on an instance. Or does it only come up when a method is added to the class?
- pansa2 7y ago> Lox will also have this quirk, won't it? Possibly - I’m not sure about the details of method lookup in Lox. Does `this` even work correctly when a method is assigned to an instance?
- munificent 7y agoIf you store a function or reference to a method in a field on an instance in Lox, the function will remember its original `this` binding. That's what Python, C#, Ruby, etc. do and is generally what you want. It's not what JS does because JS doesn't really know what a "method" is, or at least didn't before classes were added.
- pansa2 7y agoIs it possible that there isn't a `this` binding? Does Lox allow access to "unbound" methods directly from a class, or are methods accessible only via instances?
- munificent 7y agoMethods are only accessible from instances, so `this` is always meaningfully bound. If you try to use `this` outside of a class body, it's a static error.
- pansa2 7y agoOK, that solves the problem. The issue with unbound methods in Python is that they don’t yet have a value for `this`, but they do have a fixed value for `super`.
- munificent 7y agoLox makes a distinction between functions and methods, so you won't run into this problem. This is unlike JavaScript, but like most other object-oriented languages. If you take a function (which may be a reference to a method) and store it in a field on some instance, the function remembers its original bindings to "this" and "super", which is generally what you want and expect. Lox doesn't allow you to mutate a class by adding new methods to it.
- blattimwind 7y ago> Therefore, if a method is copied from one class to another, `super` within that method may refer to the wrong class. No, super() checks that "self" is an instance of the given class. So if you take a method defined in a class hierarchy "A -> B", and attach it to an instance of "C" (i.e. c.foo = B.foo) and call it like "c.foo(c)", which you have to do, since you didn't invoke the descriptor protocol to bind the method, you will get a type error, because c is not an instance of A/B. That is also true if you attach the method to the class (C.foo = B.foo); you can call it like a method, but super() still checks the type and will complain. Also, if you take a bound method and attach it to another object (i.e. c.foo = b.foo), it is already bound and you can't pass a "self" different from the object it's bound to. E.g. if you are passing around a callback that's a method. Note how Class.method is just a function, while instance.method is a bound method. That's due to the descriptor protocol of functions (__get__/__set__).
- pansa2 7y ago> That is also true if you attach the method to the class (C.foo = B.foo); you can call it like a method, but super() still checks the type and will complain. You're right. Here's some example Python code: >>> class A: ... def foo(self): ... print('A.foo') >>> class B(A): ... def foo(self): ... super().foo() ... print('B.foo') >>> b = B() >>> b.foo() A.foo B.foo >>> class C: ... def foo(self): ... print('C.foo') >>> class D(C): ... def foo(self): ... super().foo() ... print('D.foo') >>> d = D() >>> d.foo() C.foo D.foo Now, if I do `D.foo = B.foo` and call `d.foo()`, I do indeed get a "TypeError: super(type, obj): obj must be an instance or subtype of type". That's better than getting `A.foo B.foo`, as happens in JavaScript. However, if `super` were truly dynamic, I would have expected to get `C.foo B.foo`.
- blattimwind 7y agoIIRC super() is actually syntactic sugar for super(ClassTheDefIsFoundIn, nameOfFirstArgument), because there is no way I can think of to implement that as a function at runtime.
- philips4350 7y agoIIRC in JavaScript every method of a class has a [[HomeObject]] property in it, referencing the class it was defined in to solve this problem