1

I'm taking a course in Pharo (Smalltalk implementation). There is a small detail I don't really understand about the language.

The professor speaks of late self binding and static super binding. From what I understand of static binding the compiler knows at compile-time what my super class is. This seems logical as there is no multiple inheritance (as far as I know by now) so there can only be one super. So it just has to look at the inheritance tree and take the parent.

The late self binding is something I don't quite grasp. How I see it, is that the compiler can know which class it's compiling if you will, so it knows the type. So why can't it determine if it's compiling class Foo, that self is pointing to Foo? That is, if self always points to the current instance of the class Foo?

Christophe De Troyer
  • 2,852
  • 3
  • 30
  • 47

2 Answers2

1

Your question regarding late binding (a.k.a. dynamic binding) of self in Smalltalk (or this in Java parlance) was how it comes that the compiler cannot know what class self refers to.

The answer is that, in any object-oriented languages that support late or dynamic binding (which is most, if not all, OO languages) you don't know what self (or this) will be bound to until you start sending messages. Let's illustrate this with a simple pseudocode example which you can translate to whatever is your favourite OO language.

class Foo :
    method m :
        print "Hello, I am foo"

class Bar subclass-of Foo :
    method m :
        print "Hello, I am bar"

So suppose we have a class Foo implementing some method m, and some other class Bar, of which Foo is the superclass, which also implements a method m but with a different behaviour. Now suppose, we have a variable z of type Foo to which I first assign an object instance of type Foo, and then a bit later an object instance of type Bar. So far, no problem: since Bar is a subclass of Zork its instances can be used anywhere instances of type Zork are expected because of the substitutability principle. In particular, you can send a message named m to either Zork objects or Bar objects.

z = new Foo()    % z now contains an object of type Foo
z.m()            % This will print "Hello, I am foo"
z = new Bar()    % z now contains an object of type Bar (subclass of Foo)
z.m()            % This will print "Hello, I am bar"

However, as is illustrated by the instructions above, the result of executing m() will depend on what type of object is actually stored in the variable z, and you only know this at runtime. Upon the first call to m() above, z contains an instance of class Foo, so the method m() implemented on class Foo will be called. The second call to m() above behaves differently, since in the mean time z has been reassigned and now contains an instance of class Bar, so the method m() implemented on class Bar will be called.

The problem is that you only know at runtime what type of object instance z will actually contain. So the choice of which version of the method m() to be executed (the one of class Foo or the one of class Bar) is deferred until runtime, depending on the actual type of the receiver object (in our example: depending on the type/class of the object contained in the variable z).

I hope this explains the principe of late or dynamic binding a bit better and why you cannot determine this at compile time but only at runtime.

You may also want to read this related discussion which exemplifies and discusses the difference between static and dynamic binding in Java: Static Vs. Dynamic Binding in Java

Kim Mens
  • 325
  • 1
  • 13
0

Because if Bar is a subclass of Foo, and method baz is defined in Foo, you can call baz from an instance of Bar, and in that case, the class of self will be Bar, not Foo.

Idan Arye
  • 12,402
  • 5
  • 49
  • 68
  • Answer correct but may be a bit too cryptic for the student to understand. I tried to provide a more involved and complete explanation below using this example. – Kim Mens Oct 09 '21 at 13:15