Categories and protocols

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

Categories and protocols

Fernando Rodríguez
Hi,

I noticed that methods are grouped in categories and protocols. What's
the difference between categories and protocols? O:-)


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Chris Uppal-3
Fernando wrote:

> I noticed that methods are grouped in categories and protocols. What's
> the difference between categories and protocols? O:-)

(I don't know if you want a serious answer or not, here is one anyway...)

Protocols are about defining the roles and contracts between objects.  They
specify groups of messages that an object is required to understand in order to
be used in some context.  They are intended to be used to express (more or less
informally) the 'type' of an object as used in that context. (They can be
likenened to Java's "interfaces" which are used in a similar way, albeit more
formally)   You'll see lots of method comments stating that some argument
should be, say, a <SequenceableCollection>, which means that any object that
conforms to the <SequenceableCollection> protocol is acceptable as a value for
that argument.   Protocols are about understanding the structure of /programs/.

Categories are only about browsing.  They can be used to organise the methods
into /overlapping/ groups of related methods.  When used properly, they help
the reader understand the structure of a /class/.

Both concepts are occasionally used (slightly hackishly, IMO) to mean something
else.  E.g. the Model of an MVP triad is included in command routing if its
class is declared to conform to the protocol <commandTarget>  (IIRC).  And the
method category '**auto generated**' is used to mark methods that the system
can and should overwrite with new versions when it's generating methods.
Neither of these applications is typical of the use of protocols or categories.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Fernando Rodríguez
On Thu, 25 Nov 2004 12:54:42 -0000, "Chris Uppal"
<[hidden email]> wrote:

>Fernando wrote:
>
>> I noticed that methods are grouped in categories and protocols. What's
>> the difference between categories and protocols? O:-)
>
>(I don't know if you want a serious answer or not, here is one anyway...)

Hhmmm... yes, why not? O:-)

>Protocols are about defining the roles and contracts between objects.  They
>specify groups of messages that an object is required to understand in order to
>be used in some context.  They are intended to be used to express (more or less
>informally) the 'type' of an object as used in that context. (They can be
>likenened to Java's "interfaces" which are used in a similar way, albeit more
>formally)   You'll see lots of method comments stating that some argument
>should be, say, a <SequenceableCollection>, which means that any object that
>conforms to the <SequenceableCollection> protocol is acceptable as a value for
>that argument.   Protocols are about understanding the structure of /programs/.


>Categories are only about browsing.  They can be used to organise the methods
>into /overlapping/ groups of related methods.  When used properly, they help
>the reader understand the structure of a /class/.


Maybe I still don't get it right, but it seems like
overlapping/redundant concepts to me....

Anyway, what's the usual practice when creating new methods? Should
you always include them in a category or protocol? O:-)


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Chris Uppal-3
Fernando wrote:

> Maybe I still don't get it right, but it seems like
> overlapping/redundant concepts to me....

I don't think there's /that/ much overlap, not in the concepts anyway (the
implementations are much more alike). One is about describing the contract
between interacting objects, the other is a way of making the CHB more
useful...

> Anyway, what's the usual practice when creating new methods? Should
> you always include them in a category or protocol? O:-)

I can only tell you what /I/ do.

I use explicit protocols only rarely (less than once per "project"), which is
mainly because I don't often need to specify the contracts between objects
explicitly and separately from some shared abstract superclass.  When I /do/
use them, I don't add methods to protocols at all, not in the sense (I think)
you mean.  There are two steps to using a protocol -- (1) define the protocol
and the selectors it requires, (2) define which classes conform to that
protocol.  Once defined, the protocol is intended to be fairly static --
there's no point at all to a protocol that changes as often as the classes that
use it.

Here's a real example.  I wanted to put together a small library for plotting
graphs.  One of the (rather tricky) decisions was how to provide data to the
library for plotting -- what protocol the plottable data-objects should obey.
After a great deal (far too much) messing around trying various things,
settling on ideas, and then changing my mind again, I've eventually settled on
a design where the data that is plotted must be supplied as an object
conforming to the protocol <PlottableData>.  <PlottableData> is defined to have
two selectors #size and #do: (where both are expected to work as in
Collections, and where #do: should iterate over objects that themselves respond
to #x and #y with Numbers).   (As an aside, the conditions in brackets in the
previous sentence cannot be expressed (or cannot be recorded) in Dolphin
protocols, and that, together with the fact that they aren't saved in packages
as first-class objects, is why I don't make more use of them than I do.)  So
now I have a (semi-) formal expression of what it takes for data to be
plottable by my plotting package -- that's the whole point of using protocols.
 From now on there'd be no point in adding methods to the protocol (unless I
change my mind about the fundamental design -- again...).  However I can and do
create classes who instances conform to the protocol, so I can and do create
classes with methods #size and #do:.  When I create such classes, I declare
them to conform to <PlottableData>, but not by adding methods to a protocol,
but by adding the /class/ to the protocol[*] (e.g. using the Protocol Browser).
There is no /functional/ benefit in making this explicit declaration, but it
does help to /document/ the relationship between the objects that are
<PlottableData> and the objects that will render them on-screen or to a
printer.

Once I have all that set up, if I define a new class and declare it to conform
to <PlottableData> then Dolphin will check to see if that class defines #size
and #do:, and will warn me if it doesn't (in fact it gives me the option to
create dummy methods with those names).  Similarly, if I did change my mind and
add a new method to the protocol, #boundingRectangle say, then Dolphin would
warn me about any classes that conformed to <PlottableData> but which didn't
already have a  #boundingRectangle method.

Method categories, on the other hand, are completely different (and much
simpler).  All they do is give you a better way of navigating around the
definition of a class.  E.g. when I create a new Presenter class, I'll nearly
always have method in categories 'commands', #event handling', 'initialising'
and 'subpresenters' (and probably lots more too).  For instance I like to
define an "accessor" method for each named subpresenter, so they all go in
'subpresenters',  there will normally be an #initialize method in
'initialising'.  #createComponents is about initialising sub-presenter, so that
goes into both 'subpresenters' and 'initialising'.  Similarly
#createSchematicWiring goes into both 'initialising' and 'event handling'.  And
so on.  The categories let me find the methods I'm interested in quickly, and
also allow me to restrict the methods list to just the ones I'm interested in
at any one time.  I find them very useful, and therefore make an effort always
to put methods into sensible categories when I first create them.

HTH...

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Blair McGlashan-3
A small augmentation to Chris' excellent overview of the protocols vs
categories:

"Chris Uppal" <[hidden email]> wrote in message
news:[hidden email]...
>...
> From now on there'd be no point in adding methods to the protocol (unless
> I
> change my mind about the fundamental design -- again...).
>...

I wouldn't state it that strongly. One of the reasons to use protocols is to
take advantage of the way the system enforces the interface contract when
you do add to the protocol. This can be handy when several classes implement
a protocol in order to serve in a particular role. The protocols help to add
some of the support you might get from a statically typed language in that
situation.

>...
> There is no /functional/ benefit in making this explicit declaration, but
> it
> does help to /document/ the relationship between the objects ...

I agree that the main benefit is in declaring the relationship explicitly,
but it is also possible to use protocols to perform dynamic enquiry as to
whether an object can be used in a particular role. Although protocol
conformance tests are a form of switch on type, and should thus be used
sparingly, they are cleaner than #isKindOf: tests because they don't depend
on the implementation inheritance hierarchy. In this sense protocols can be
used as a replacement for defining loads of #isXXXX test methods (i.e. is-a
tests) that end up polluting Object.

I agree with your criticisms of protocols BTW (and would add the additional
one that they have no inheritance capability). Ironically protocols did
originate in an idea to extend the category mechanism. In exploring this
idea it quickly developed into the protocol mechanism, which as you have
explained has a completely different purpose. However having seeded
protocols from the category mechanism they have almost inexorably ended up
with the limitations you describe. Protocols should probably be represented
as classes (or at least a special type of behaviour), but I haven't explored
that idea in any detail.

Lastly there is a paper on "SmallInterfaces" available somewhere on the net
that describes Dolphin's protocols as related work. This paper's description
of Dolphin's protocols contains a number of factual inaccuracies, not the
least of which is that it states that the protocols have no persistent form.
Protocols are saved out with class file outs. This is not ideal, because as
you say protocols should be represented as code artifacts in their own right
in the package system. However it does preserve the protocol definitions.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

talios@gmail.com
In reply to this post by Chris Uppal-3
Chris Uppal wrote:

>Here's a real example.  I wanted to put together a small library for plotting
>graphs.  One of the (rather tricky) decisions was how to provide data to the
>library for plotting -- what protocol the plottable data-objects should obey.
>After a great deal (far too much) messing around trying various things,
>  
>
Chris, coming from the Java world - would it be fair of me to think of
protocols along the lines of java's "interfaces", where you declare an
interface, which a class can "implement":

public interface Foo {
  void someMethodYouMustImplement();
}

public class Bar implements Foo {
  public void someMethodYouMustImplement() {
    .....
  }
}

?


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Chris Uppal-3
In reply to this post by Blair McGlashan-3
Blair McGlashan wrote:

> > From now on there'd be no point in adding methods to the protocol
> > (unless I
> > change my mind about the fundamental design -- again...).
> > ...
>
> I wouldn't state it that strongly.

I was about to agree, but on reflection, it seems to me that changing a
protocol /is/ changing the fundamental design.  (At least if you exclude the
case where you are tinkering with a protocol trying to improve the way it
captures some pre-existing design -- compare the case of changing the design
documentation which can either be because the design has changed, or because
the documentantation wasn't good/complete/clear enough).  But still, the way I
expressed it over-emphasised the static-ness of protocols -- after all, it's
not as if design changes are all that rare (and that's one of the reasons for
using Smalltalk in the first place...)


> > There is no /functional/ benefit in making this explicit declaration,
> > but it
> > does help to /document/ the relationship between the objects ...
>
> I agree that the main benefit is in declaring the relationship explicitly,
> but it is also possible to use protocols to perform dynamic enquiry as to
> whether an object can be used in a particular role.

Agreed; I think I'd forgotten about that scenario when I was writing the post
:-(

In practise, though, I tend not to use protocols for that purpose (I don't
think I've ever done so), even though I agree that it's cleaner and more
general than an #isKindOf: check.  One reason is practical -- I find that
protocols in their current implementation are too lightweight for me to feel
comfortable using them to affect runtime behaviour.  They have a tendency to
disappear if you aren't careful (I've "lost" protocols before), and adding
pre-existing classes to protocols is a little awkward (eg. in my earlier
example, a SequencableCollection of Points is in fact suitable for use as a
<PlottableData>, but adding the corresponding explicit declaration would
require some messing around).

More theoretically, I'm not comfortable with the fact that classes must
/explicitly/ declare themselves to conform to some protocol.  It seems too
declarative to me, and I've become very hostile to the declarative view of
programming in recent years (especially in Smalltalk).  I think I'd be happier
testing whether the object "implements" the protocol in the sense of a
#respondsTo: for each of the selectors in the protocol.  I'm not absolutely
certain that this unease is actually defensible (after all, an #isKindOf: check
is even /more/ declarative), but that's how I've been seeing it to date.


> Protocols should
> probably be represented as classes (or at least a special type of
> behaviour), but I haven't explored that idea in any detail.

Thinking about this a little, I don't agree.  I know that SmallInterfaces takes
that approach, but the more I think about it, the less sense it makes (to me,
anyway).  Protocols (obviously) aren't some kind of class -- there is no "is-a"
relationship that we are trying to model by making Protocol a subclass of
Behavior; indeed (if anything) it seems that Behaviour should be a subclass of
Protocol.  I'd say that a protocol is able to answer the question, "is <some
object> suitable for use in <some context>" and that really has very little to
do with classes.   In practise, for many contexts, knowing whether an object is
an instance of some class is actually a very good heuristic for answering that
question, so there's a case to be made that /classes/ should be able to act as
/protocols/ -- not the other way around (you could think of it that every class
implicitly defines a protocol).

Another practical point is that it would be nice to be able to associate text
with each selector in a protocol.  That would either be a comment would be
copied into the body of corresponding auto-generated placeholder methods, or
could even be the entire source for the placeholder methods (one could go
further and specify method categories for each selector too).  I can see that
that makes a protocol look rather like a class, but I don't think the
similarities are anything other than misleading.


> Protocols are saved out with class file outs.
> This is not ideal, because as you say protocols should be represented as
> code artifacts in their own right in the package system.

That would be fairly tricky to get right -- the interaction with the
pre-requisites system would be quite complicated, at least if you wanted to
allow protocols to be "retro-fitted" to existing classes without awkwardness.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Chris Uppal-3
In reply to this post by talios@gmail.com
Mark Derricutt wrote:

> Chris, coming from the Java world - would it be fair of me to think of
> protocols along the lines of java's "interfaces", where you declare an
> interface, which a class can "implement":

I'd say they are almost identical ideas; but I'd also add a few caveats:

The first caveat is that there's a fairly common tendency in the Java
programming world to think of interfaces as sort of "cut down" abstract
classes.  (This manifests, for instance, in claims that Java does have
multiple-inheritance, but that it is restricted to interfaces.  Another
manifestation, I think, is that many programmers would have difficulty
expressing /why/ there are significant differences between a completely
abstract class (no method bodies at all) and an interface with the same
apparent "contents")  IMO that tendency, although quite common, is flat-out
wrong (it's encouraged by the unfortunate similarity -- handy but misleading --
between the syntax used for classes and interfaces).  I see both Java
interfaces and Dolphin protocols as being about how you know/document/test
whether a given object is suitable for use in some context.  Certainly Dolphin
protocols are not in any sense "cut down classes".

The second caveat is that, unlike Java interfaces, Dolphin protocols are  not
used for static type checking (obviously!).  One effect of this is that there
is less need for as many protocols -- you only define or use a protocol where
you think it has positive value, rather than being forced to do so to keep the
compiler happy.

The last caveat is also related to type checking.  In Java, interfaces can be
used to loosen the coupling that the type-checker would otherwise cause between
different classes.  That use (which is perfectly legitimate, IMO) allows you to
replace the declaration of some variable:
    SomeClass aVariable;
with a reference to a suitable interface:
    SomeInteface aVariable;
(where SomeClass implements SomeInteface).  The point is not only that
"SomeInteface" is more general than "SomeClass" (thus allowing greater
flexibility), but also it avoid mentioning "SomeClass" /at all/, and so avoids
coupling between the class and the code that uses its instances.  Smalltalk, in
contrast, doesn't introduce that kind of coupling in the first place, so
Dolphin protocols have no such role.  In fact you could think of Dolphin
protocols as a way of /increasing/ the coupling; available for use in cases
where you don't think Smalltalk's normal semantics express the connection
strongly enough.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Categories and protocols

Blair McGlashan-3
In reply to this post by Chris Uppal-3
"Chris Uppal" <[hidden email]> wrote in message
news:[hidden email]...

> Blair McGlashan wrote:
> ...
>> but it is also possible to use protocols to perform dynamic enquiry as to
>> whether an object can be used in a particular role.
>
> Agreed; I think I'd forgotten about that scenario when I was writing the
> post
> :-(
>
> In practise, though, I tend not to use protocols for that purpose (I don't
> think I've ever done so), even though I agree that it's cleaner and more
> general than an #isKindOf: check.  One reason is practical -- I find that
> protocols in their current implementation are too lightweight for me to
> feel
> comfortable using them to affect runtime behaviour.  They have a tendency
> to
> disappear if you aren't careful (I've "lost" protocols before),

There are certainly a couple of circumstances where that might happen:
1) The protocol implementation in a class depends on loose methods in other
packages than that which owns the class
2) You rename or delete a method that is implementing a protocol.

(1) is really a failing of the way protocols are represented in package
system. As we have discussed protocols are always associated with a class
(and included in the class file out), and this means that the protocol is
not preserved in any of the packages.

The IDE trys to protect you against (2), for example by warning you if you
attempt to delete a method contributing to the implementation of a protocol.
Unfortunately it doesn't give the same kind of warnings when using some
refactorings (especially method signature changes); these may silently drop
the protocol from the affected class if it not longer conforms to the
protocol. It can also happen when filing in or out chunks as the system will
always maintain the correctness of the protocol conformity and that may mean
dropping a protocol from classes that will not conform after a change.

>...and adding
> pre-existing classes to protocols is a little awkward (eg. in my earlier
> example, a SequencableCollection of Points is in fact suitable for use as
> a
> <PlottableData>, but adding the corresponding explicit declaration would
> require some messing around).

Well there might be cases where you could make assertions about pre-existing
classes implementing protocols that you yourself define, although I don't
think the SequenceableCollection of Point is a good example since none of
the Collection classes restrict the class of elements in any way. Regardless
I think that once again this is an issue of the way the protocols are (not)
represented in the package system.

>
> More theoretically, I'm not comfortable with the fact that classes must
> /explicitly/ declare themselves to conform to some protocol.  It seems too
> declarative to me, and I've become very hostile to the declarative view of
> programming in recent years (especially in Smalltalk).

For me that is the whole point of protocols - they allow you to add
additional meta-information about the roles supported by a class.

>..I think I'd be happier
> testing whether the object "implements" the protocol in the sense of a
> #respondsTo: for each of the selectors in the protocol.  I'm not
> absolutely
> certain that this unease is actually defensible (after all, an #isKindOf:
> check
> is even /more/ declarative), but that's how I've been seeing it to date.

In that case you might prefer SmallInterfaces. Personally I think that
approach is completely misguided - it might be pure coincidence that a class
implements a particular set of selectors. The fact that a class responds to
a particular selector says nothing about the semantics. You are just taking
an educated guess that it probably implements the protocol. Of course good
style in Smalltalk recommends the use of specific, intention revealing
selectors (e.g. in PlottableData your might have #addCoordinate: rather than
#add:), and this might make the guess more likely to be correct, but it
doesn't guarantee it.

>> Protocols should
>> probably be represented as classes (or at least a special type of
>> behaviour), but I haven't explored that idea in any detail.
>
> Thinking about this a little, I don't agree.  I know that SmallInterfaces
> takes
> that approach, but the more I think about it, the less sense it makes (to
> me,
> anyway).  Protocols (obviously) aren't some kind of class -- there is no
> "is-a"
> relationship that we are trying to model by making Protocol a subclass of
> Behavior; indeed (if anything) it seems that Behaviour should be a
> subclass of
> Protocol.  I'd say that a protocol is able to answer the question, "is
> <some
> object> suitable for use in <some context>" and that really has very
> little to
> do with classes. In practise, for many contexts, knowing whether an object
> is
> an instance of some class is actually a very good heuristic for answering
> that
> question, so there's a case to be made that /classes/ should be able to
> act as
> /protocols/ -- not the other way around (you could think of it that every
> class
> implicitly defines a protocol).
>

Whoever sits on top, there are powerful reasons to explore the idea, not the
least of which is the potential to unify concepts. Apart from being
consistent with Smalltalk's general philosophy, this avoids introducing
another code grouping concept that must be understood by programmer and
tools. It also opens up the possibility of other capabilities such as
mix-ins, and multiple implementations of the same selector with visibility
dependent upon the role in which one is using an object.

> Another practical point is that it would be nice to be able to associate
> text
> with each selector in a protocol.  That would either be a comment would be
> copied into the body of corresponding auto-generated placeholder methods,
> or
> could even be the entire source for the placeholder methods (one could go
> further and specify method categories for each selector too).  I can see
> that
> that makes a protocol look rather like a class, but I don't think the
> similarities are anything other than misleading.
>
>
>> Protocols are saved out with class file outs.
>> This is not ideal, because as you say protocols should be represented as
>> code artifacts in their own right in the package system.
>
> That would be fairly tricky to get right -- the interaction with the
> pre-requisites system would be quite complicated, at least if you wanted
> to
> allow protocols to be "retro-fitted" to existing classes without
> awkwardness.

It would certainly complicate the prerequisites tracing (e.g. where a
protocol owned by a package depends on loose methods in other packages tthis
would mean tracing the ownership of the methods that support a protocol, as
well as the conforming class with which a protocol has been associated).

Regards

Blair