In this model you can only call selectors defined in the class of the receiving objects or in one of its ancestors. If you call a selector with a receiving object that is not in one of these classes, the result is undefined; if you are lucky, the program crashes immediately.
Now consider the case when you want to have a selector (or several)
available in two classes: You would have to add the selector to a
common ancestor class, in the worst case to object
. You
may not want to do this, e.g., because someone else is responsible for
this ancestor class.
The solution for this problem is interfaces. An interface is a collection of selectors. If a class implements an interface, the selectors become available to the class and its descendents. A class can implement an unlimited number of interfaces. For the problem discussed above, we would define an interface for the selector(s), and both classes would implement the interface.
As an example, consider an interface storage
for
writing objects to disk and getting them back, and a class
foo
that implements it. The code would look like this:
interface selector write ( file object -- ) selector read1 ( file object -- ) end-interface storage bar class storage implementation ... overrides write ... overrides read1 ... end-class foo
(I would add a word read
( file – object ) that uses
read1
internally, but that’s beyond the point illustrated
here.)
Note that you cannot use protected
in an interface; and
of course you cannot define fields.
In the Neon model, all selectors are available for all classes; therefore it does not need interfaces. The price you pay in this model is slower late binding, and therefore, added complexity to avoid late binding.