| > C++'s vtable is also late binding, since you don't know which implementation you're calling until runtime. And there's no such thing as "extremely late binding". C++'s vtables are determined at compile time. The specific implementation executed at a given moment may not be possible to deduce statically, but the set of possible methods is statically determined for every call site: It consists of the set of overridden implementations of the method with that name in the class hierarchy from the named type and downwards. No such restriction exists in Ruby or Smalltalk or most other truly dynamic languages. E.g. for many Ruby ORM's the methods that will exist on a given object representing a table will not be known until you have connected to the database and read the database schema from it, and at the same time I can construct the message I send to the object dynamically at runtime. Furthermore the set of messages a given object will handle, or which code will handle it can change from one invocation to the next. E.g. memoization of computation in Ruby could look sort-of like this: class Memo
def method_missing op
result = ... execute expensive operation here ...
define_singleton_method(op) { return result }
end
end
After the first calculation of a given operation, instead of hitting method_missing, it just finds a newly created method returning the result."Extreme late binding" is used exactly because people think things like vtables represent late-binding, but the ability to dynamically construct and modify classes and methods at runtime represents substantially later binding. E.g. there's no reason why all the code needs to be loaded before it is needed, and methods constructed at that time And incidentally this is not about vtables or not vtables - they are an implementation detail. Prof. Michael Franz paper on Protocol Extension [1] provided a very simple mechanism for Oberon that translates nicely to vtables by dynamically augmenting them as code is loaded at runtime. For my (very much incomplete) Ruby compiler, I use almost the same approach to create vtables for Ruby classes that are dynamically updated by propagating the changes downwards until it reaches a point where the vtable slot is occupied by a different pointer than the one I'm replacing (indicating the original method has been overridden). Extending the vtables at runtime (as opposed to adding extra pointers) would add a bit of hassle, but is also not hard. The point being that this is about language semantics in terms of whether or not the languages allows changing the binding at runtime, not about the specific method used to implement the method lookups semantics of each language - you can implement Ruby semantics with vtables, and C++ semantics by a dictionary lookup. That's not the part that makes the difference (well, it affects performance) > That's not true, you can always have a "send_message(string id)". Few people do it because you lose static type safety. And some languages, like C# and Scala, have dynamic types that allows for the "method_missing" protocol and such features are very unpopular. If you're working in a language with static typing you've already bought into a specific model; it's totally unsurprising that people who have rejected dynamic typing their language choice will reject features of their statically typed language that does dynamic typing. I don't think that says anything particularly valuable about how useful it is. Only that it is generally a poor fit for those types of languages. [1] Protocol Extension: A Technique for Structuring Large Extensible Software Systems, ETH Technical Report (1994)
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.42.... |