Traits as a way of defining an interface instead of an abstract superclass

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Traits as a way of defining an interface instead of an abstract superclass

Chris Cunnington
I've been looking at MetaObjects's [1] decade old implementation of the
vm in Cocoa. It has a class called SqueakInterpreter.h that defines a
protocol that is used in SqView. The selectors are listed in
SqueakInterpreter.h but implemented in SqView.m. I believe this kind of
thing is now called a category in Objective-C-ese. And I was wondering
why somebody would do this? We don't separate the protocols from the
classes in Smalltalk. And I think the reason is we use abstract
superclasses. And we have deep user developed hierarchies.

Then it occurred to me that Objective-C doesn't have any user
hierarchies of any depth. There are framework hierarchies of great
depth. But the programmer in Objective-C from the start is supposed to
go straight to composition and only produce very shallow hierarchies.
I've got a book where a designer of Objective-C says inheritance is
superfluous.[2]

OK. Composition good. Inheritance bad. And it explains why there is no
decent hierarchy browser in Xcode 4. There was one in Xcode 3 and they
tossed it.

And following these protocols from where they are defined to where they
are implemented and where all developer hierarchies are two classes deep
feels sort of like walking around a basement where the ceiling is too
low with a flashlight looking for a crate.

And so I'm guessing that this idea of splitting a protocol from its
class has bled into Squeak from Objective-C in the form of Traits.
Casimiro must have a reason for using them that he likes. But they do
seem like a workaround as a result of a shallow hierarchy. I think I'd
rather create my own abstract superclass to define an interface.

Chris


[1] http://www.metaobject.com/downloads/Squeak/

[2] "Masterminds Of Programming" (2009) O'Reilly, pg. 258-260. Brad Cox
quotes:

"Inheritance just isn't all that important. Encapsulation is OOP's
lasting contribution."

"Smalltalk didn't have anything like protocol in those days and that was
added by Steve Naroff, who is now in charge of the Objective-C at Apple."

"At first I used inheritance heavily, experimenting to find its bounds.
Then I realized that encapsulation was the real contribution of OOP and
that it could be used manually to do almost everything I'd been using
inheritance for, but more cleanly."



Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Frank Shearar-3
On 12 October 2012 17:21, Chris Cunnington
<[hidden email]> wrote:
> I've been looking at MetaObjects's [1] decade old implementation of the vm
> in Cocoa. It has a class called SqueakInterpreter.h that defines a protocol
> that is used in SqView. The selectors are listed in SqueakInterpreter.h but
> implemented in SqView.m. I believe this kind of thing is now called a
> category in Objective-C-ese. And I was wondering why somebody would do this?
> We don't separate the protocols from the classes in Smalltalk. And I think
> the reason is we use abstract superclasses. And we have deep user developed
> hierarchies.

Protocols allow you to say "these messages, unrelated by inheritance,
nevertheless both understand these sets of messages". That's very
handy, because sometimes you can't or don't want an inheritance
relationship between the two classes.

Perhaps the classes both come from 3rd party libraries, and you're
writing something that should be able to operate on both, and want to
express that in THIS LIMITED way, the classes are similar.

frank

> Chris

Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Chris Cunnington
On 12-10-12 12:26 PM, Frank Shearar wrote:

> On 12 October 2012 17:21, Chris Cunnington
> <[hidden email]> wrote:
>> I've been looking at MetaObjects's [1] decade old implementation of the vm
>> in Cocoa. It has a class called SqueakInterpreter.h that defines a protocol
>> that is used in SqView. The selectors are listed in SqueakInterpreter.h but
>> implemented in SqView.m. I believe this kind of thing is now called a
>> category in Objective-C-ese. And I was wondering why somebody would do this?
>> We don't separate the protocols from the classes in Smalltalk. And I think
>> the reason is we use abstract superclasses. And we have deep user developed
>> hierarchies.
> Protocols allow you to say "these messages, unrelated by inheritance,
> nevertheless both understand these sets of messages".
There's something dicey about this wording, I feel. Messages don't
understand messages. Objects do. "These objects, unrelated by
inheritance, nevertheless both understand these sets of messages." Perhaps?

>   That's very
> handy, because sometimes you can't or don't want an inheritance
> relationship between the two classes.
>
> Perhaps the classes both come from 3rd party libraries, and you're
> writing something that should be able to operate on both, and want to
> express that in THIS LIMITED way, the classes are similar.
>
Yea, that makes sense. And it's illustrated by the vm source I've been
looking at. SqueakInterpreter.h is going to be the same no matter the
platform. The implementation in the view class will depend on the
operating system. I think there's a lot of that going on in
SqueakPureObjc.xcodeproj vm code with categories like:

sqSqueakOSXApplication+imageReadWrite.m
sqSqueakOSXApplication+events.m
sqSqueakOSXApplication+attributes.m
sqSqueakOSXApplication+cursor.m

That makes your point, I think.

So what we're talking about is scale. "Few people" using a code base as
opposed to "many people". Now that you say it, I suppose Cincom address
this because they make an enterprise Smalltalk. And I guess namespaces
come into this domain of many users.

Chris

Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Colin Putney-3
In reply to this post by Chris Cunnington
On Fri, Oct 12, 2012 at 9:21 AM, Chris Cunnington
<[hidden email]> wrote:

> And so I'm guessing that this idea of splitting a protocol from its class
> has bled into Squeak from Objective-C in the form of Traits. Casimiro must
> have a reason for using them that he likes. But they do seem like a
> workaround as a result of a shallow hierarchy. I think I'd rather create my
> own abstract superclass to define an interface.

You might find this interesting:

http://www.jot.fm/issues/issue_2002_05/article1/

It's a paper about SmallInterfaces, which created first-class
interfaces (in Java parlance) for Smalltalk. There was a Squeak port
that ran in Squeak 3.2 IIRC.

I find it much more fruitful to think about protocols rather than
classes when designing or analyzing OO systems. This fits in nicely
with what you said about composition being better than inheritance.
But there are a few issues with a protocol-centric view in Smalltalk:

One is that we don't really need formal protocols the way Java or
Objective-C do, because of the flexibility of Smalltalk. Objective-C
uses protocols to allow classes to be extended even when you don't
have the source code to the object that you're extending. Java uses
interfaces to allow polymorphism between classes that aren't related
by inheritance. In both cases, formalized protocols work around a
problem caused by the mechanics of the language or it's tools. In
Smalltalk, doing everything in-image, we don't have those problems.

Given that protocol-oriented programming is so good, it would be nice
to have better support for that mode of thinking. I bet, for example,
that there's a latent "Map" protocol in the image, which is a subset
of the methods that Dictionary implements. It's #at: and #at:put: plus
a few other supporting methods, but *not* the whole protocol
implemented by Dictionary and certainly not all the stuff it inherits
from Collection. I'd love to see a tool that would let us discover
these latent protocols, name them, and then view and manipulate the
system based on them.

Colin

Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Frank Shearar-3
In reply to this post by Chris Cunnington
On 12 October 2012 17:42, Chris Cunnington
<[hidden email]> wrote:

> On 12-10-12 12:26 PM, Frank Shearar wrote:
>>
>> On 12 October 2012 17:21, Chris Cunnington
>> <[hidden email]> wrote:
>>>
>>> I've been looking at MetaObjects's [1] decade old implementation of the
>>> vm
>>> in Cocoa. It has a class called SqueakInterpreter.h that defines a
>>> protocol
>>> that is used in SqView. The selectors are listed in SqueakInterpreter.h
>>> but
>>> implemented in SqView.m. I believe this kind of thing is now called a
>>> category in Objective-C-ese. And I was wondering why somebody would do
>>> this?
>>> We don't separate the protocols from the classes in Smalltalk. And I
>>> think
>>> the reason is we use abstract superclasses. And we have deep user
>>> developed
>>> hierarchies.
>>
>> Protocols allow you to say "these messages, unrelated by inheritance,
>> nevertheless both understand these sets of messages".
>
> There's something dicey about this wording, I feel. Messages don't
> understand messages. Objects do. "These objects, unrelated by inheritance,
> nevertheless both understand these sets of messages." Perhaps?

Er yes, that's what I had _meant_ to type.

(But of course Message instances are objects, and understand messages :) )

frank

Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Chris Cunnington


On Fri, Oct 12, 2012 at 2:27 PM, Frank Shearar <[hidden email]> wrote:
On 12 October 2012 17:42, Chris Cunnington
<[hidden email]> wrote:
> On 12-10-12 12:26 PM, Frank Shearar wrote:
>>
>> On 12 October 2012 17:21, Chris Cunnington
>> <[hidden email]> wrote:
>>>
>>> I've been looking at MetaObjects's [1] decade old implementation of the
>>> vm
>>> in Cocoa. It has a class called SqueakInterpreter.h that defines a
>>> protocol
>>> that is used in SqView. The selectors are listed in SqueakInterpreter.h
>>> but
>>> implemented in SqView.m. I believe this kind of thing is now called a
>>> category in Objective-C-ese. And I was wondering why somebody would do
>>> this?
>>> We don't separate the protocols from the classes in Smalltalk. And I
>>> think
>>> the reason is we use abstract superclasses. And we have deep user
>>> developed
>>> hierarchies.
>>
>> Protocols allow you to say "these messages, unrelated by inheritance,
>> nevertheless both understand these sets of messages".
>
> There's something dicey about this wording, I feel. Messages don't
> understand messages. Objects do. "These objects, unrelated by inheritance,
> nevertheless both understand these sets of messages." Perhaps?

Er yes, that's what I had _meant_ to type.

(But of course Message instances are objects, and understand messages :) )
 
Absolutely. I knew there was a wrinkle I wasn't seeing. :)

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Chris Cunnington
In reply to this post by Colin Putney-3
On 12-10-12 1:37 PM, Colin Putney wrote:

> On Fri, Oct 12, 2012 at 9:21 AM, Chris Cunnington
> <[hidden email]> wrote:
>
>> And so I'm guessing that this idea of splitting a protocol from its class
>> has bled into Squeak from Objective-C in the form of Traits. Casimiro must
>> have a reason for using them that he likes. But they do seem like a
>> workaround as a result of a shallow hierarchy. I think I'd rather create my
>> own abstract superclass to define an interface.
> You might find this interesting:
>
> http://www.jot.fm/issues/issue_2002_05/article1/
>
> It's a paper about SmallInterfaces, which created first-class
> interfaces (in Java parlance) for Smalltalk. There was a Squeak port
> that ran in Squeak 3.2 IIRC.
That was interesting. I read it, though, I think I'll have to read it
again in a few days to get a better idea.
>
> I find it much more fruitful to think about protocols rather than
> classes when designing or analyzing OO systems.
Hmm. That's interesting.

> This fits in nicely
> with what you said about composition being better than inheritance.
> But there are a few issues with a protocol-centric view in Smalltalk:
>
> One is that we don't really need formal protocols the way Java or
> Objective-C do, because of the flexibility of Smalltalk. Objective-C
> uses protocols to allow classes to be extended even when you don't
> have the source code to the object that you're extending.
That's a good point. They are a bit more restricted.

> Java uses
> interfaces to allow polymorphism between classes that aren't related
> by inheritance. In both cases, formalized protocols work around a
> problem caused by the mechanics of the language or it's tools. In
> Smalltalk, doing everything in-image, we don't have those problems.
>
> Given that protocol-oriented programming is so good, it would be nice
> to have better support for that mode of thinking. I bet, for example,
> that there's a latent "Map" protocol in the image, which is a subset
> of the methods that Dictionary implements. It's #at: and #at:put: plus
> a few other supporting methods, but *not* the whole protocol
> implemented by Dictionary and certainly not all the stuff it inherits
> from Collection. I'd love to see a tool that would let us discover
> these latent protocols, name them, and then view and manipulate the
> system based on them.
An automated code archaeologist? The only thing I can think of similar
to that is studying old images (i.e. 2.7) and comparing them to today.
What kind of criteria would such a tool use? <Spock>Fascinating.</Spock>

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Colin Putney-3
On Fri, Oct 12, 2012 at 1:02 PM, Chris Cunnington
<[hidden email]> wrote:
>> I'd love to see a tool that would let us discover
>> these latent protocols, name them, and then view and manipulate the
>> system based on them.
>
> An automated code archaeologist? The only thing I can think of similar to
> that is studying old images (i.e. 2.7) and comparing them to today. What
> kind of criteria would such a tool use? <Spock>Fascinating.</Spock>

Well, I'm imagining something a bit like a type inference tool. But
instead of figuring out what the concrete classes of receivers are, it
would just collect a list of messages that get sent to it.

So imagine that we pick a class at (pseudo) random, say ChangeSet, and
focus on one of its variables, say 'structures'. If we look at all the
methods of ChangeSet, we can see what messages get sent to
'structures'. Here's the list methods that use 'structures':

ChangeSet >> noteClassForgotten:
ChangeSet >> noteClassStructure:
ChangeSet >> structures
ChangeSet >> askAddedInstVars:
ChangeSet >> askRenames:addTo:using:
ChangeSet >> askRemovedInstVars:
ChangeSet >> checkForConversionMethods
ChangeSet >> absorbStructureOfClass:from:

#noteClassForgotten: sends the following messages to 'structures':

#ifNil:
#includesKey:
#removeKey:ifAbsent:

#noteClassStructure sends these messages:

#ifNil:
#includesKey:
#at:put:

So we've got a little histogram of messages:

#ifNil: - 2
#includesKey: - 2
#removeKey:ifAbsent: - 1
#at:put: - 1

And we can continue on down the list of ChangeSet's methods building
up our statistical database. We could do the same thing with temporary
variables, and even expressions that never get stored into a variable,
but do get sent messages.

A type inference tool would compare the sets of messages that an
object receives to the actual classes in the image and try to figure
out which classes it could be an instance of. What this protocol tool
would do differently is ignore the actual classes in the image, and
instead try to find patterns in the message sends, and try to shed
light on programmer intent. So we might ask, what other messages are
associated with #includesKey:, and how strong is the association?
What's the largest set of methods that are sent to at least 95% of
objects that receive #includesKey:? What objects fall into the other
5%?

There would probably be a lot of noise in the data - #ifNil:, for
example, might confuse things a bit. But I bet there's a lot of signal
as well, and with a bit of direction from the user, that sort of tool
might be able point out, for example, a class that almost implements
the Magnitude protocol, but is missing a couple of methods.

Anyway, thanks for bringing up this topic. It's interesting stuff.

Colin

Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Frank Shearar-3
On 12 October 2012 23:09, Colin Putney <[hidden email]> wrote:

> On Fri, Oct 12, 2012 at 1:02 PM, Chris Cunnington
> <[hidden email]> wrote:
>>> I'd love to see a tool that would let us discover
>>> these latent protocols, name them, and then view and manipulate the
>>> system based on them.
>>
>> An automated code archaeologist? The only thing I can think of similar to
>> that is studying old images (i.e. 2.7) and comparing them to today. What
>> kind of criteria would such a tool use? <Spock>Fascinating.</Spock>
>
> Well, I'm imagining something a bit like a type inference tool. But
> instead of figuring out what the concrete classes of receivers are, it
> would just collect a list of messages that get sent to it.
>
> So imagine that we pick a class at (pseudo) random, say ChangeSet, and
> focus on one of its variables, say 'structures'. If we look at all the
> methods of ChangeSet, we can see what messages get sent to
> 'structures'. Here's the list methods that use 'structures':
>
> ChangeSet >> noteClassForgotten:
> ChangeSet >> noteClassStructure:
> ChangeSet >> structures
> ChangeSet >> askAddedInstVars:
> ChangeSet >> askRenames:addTo:using:
> ChangeSet >> askRemovedInstVars:
> ChangeSet >> checkForConversionMethods
> ChangeSet >> absorbStructureOfClass:from:
>
> #noteClassForgotten: sends the following messages to 'structures':
>
> #ifNil:
> #includesKey:
> #removeKey:ifAbsent:
>
> #noteClassStructure sends these messages:
>
> #ifNil:
> #includesKey:
> #at:put:
>
> So we've got a little histogram of messages:
>
> #ifNil: - 2
> #includesKey: - 2
> #removeKey:ifAbsent: - 1
> #at:put: - 1
>
> And we can continue on down the list of ChangeSet's methods building
> up our statistical database. We could do the same thing with temporary
> variables, and even expressions that never get stored into a variable,
> but do get sent messages.
>
> A type inference tool would compare the sets of messages that an
> object receives to the actual classes in the image and try to figure
> out which classes it could be an instance of.

http://www.squeaksource.com/SqueakCheck does exactly this: given a
Theory (an arity 1 method on a TheoryTestCase marked with the <theory>
pragma), it finds all messages sent to the Theory's argument (call it
foo), and to foo class. It then finds all possible Class types that
match that protocol, and uses those classes as seeds for generating
random data to throw at the Theory.

> What this protocol tool
> would do differently is ignore the actual classes in the image, and
> instead try to find patterns in the message sends, and try to shed
> light on programmer intent. So we might ask, what other messages are
> associated with #includesKey:, and how strong is the association?
> What's the largest set of methods that are sent to at least 95% of
> objects that receive #includesKey:? What objects fall into the other
> 5%?

This is a much more complicated/difficult problem than what
SqueakCheck tries to do.

> There would probably be a lot of noise in the data - #ifNil:, for
> example, might confuse things a bit. But I bet there's a lot of signal
> as well, and with a bit of direction from the user, that sort of tool
> might be able point out, for example, a class that almost implements
> the Magnitude protocol, but is missing a couple of methods.

I wonder if some of the natural language tools can't help here: I'm
thinking things like bigram/trigram models and the like. My brain's
just melted from being up too late. There's another probabilistic tool
that can divide up high dimensional spaces to maximise differences in
data points. If I remember the name I'll mention it :/

frank

> Anyway, thanks for bringing up this topic. It's interesting stuff.
>
> Colin
>

Reply | Threaded
Open this post in threaded view
|

Re: Traits as a way of defining an interface instead of an abstract superclass

Igor Stasenko
In reply to this post by Colin Putney-3
On 12 October 2012 19:37, Colin Putney <[hidden email]> wrote:

> On Fri, Oct 12, 2012 at 9:21 AM, Chris Cunnington
> <[hidden email]> wrote:
>
>> And so I'm guessing that this idea of splitting a protocol from its class
>> has bled into Squeak from Objective-C in the form of Traits. Casimiro must
>> have a reason for using them that he likes. But they do seem like a
>> workaround as a result of a shallow hierarchy. I think I'd rather create my
>> own abstract superclass to define an interface.
>
> You might find this interesting:
>
> http://www.jot.fm/issues/issue_2002_05/article1/
>
> It's a paper about SmallInterfaces, which created first-class
> interfaces (in Java parlance) for Smalltalk. There was a Squeak port
> that ran in Squeak 3.2 IIRC.
>
> I find it much more fruitful to think about protocols rather than
> classes when designing or analyzing OO systems.

Same here. I think i even have class or two who serving just for
documentation purposes,
i.e. having no much sense to be inherited from, but just indicate what
protocol(s) should be
used for interacting with such kind of objects.

Today, i base my design on protocols and roles. By role i mean any
object at some certain place,
and that place (method argument, instance variable etc), defines what
protocol(s) a given role should conform to.
The inheritance is relevant only when you need polymorphism and to
reuse (inherit) large amount of common code, which every subclass
should (or can) use.


--
Best regards,
Igor Stasenko.