"Duck Typing" or "No need for abstract classes"

E

Edgardo Hames

Hi, you all.

I'm working on a new small project where several network protocols are
to be supported. I had an idea about how to implement it and it
resembled something like this.

class Protocol
abstract :login, :logout, :send, :receive
end

class MyProtocol < Protocol
def login
# does something useful
end
... # so on
end

Then my network client would just call the methods of a Protocol
object without caring about the actual classes that implement it (yes,
you're right, I come from a static typing background). But then I read
something (I don't remember where :( ) which said that agile languages
don't need to implement so many patterns and I think I saw the light!

I don't need a Protocol class, the network client should just call the
methods of the protocol and duck typing should do all the magic. Am I
right? Am I coming a little closer to walking the Ruby Way?

Please, post a positive reply and you just may save me a couple of
therapy sessions :p

Kind Regards,
Ed
 
J

Jamis Buck

Hi, you all.

I'm working on a new small project where several network protocols are
to be supported. I had an idea about how to implement it and it
resembled something like this.

class Protocol
abstract :login, :logout, :send, :receive
end

class MyProtocol < Protocol
def login
# does something useful
end
... # so on
end

Then my network client would just call the methods of a Protocol
object without caring about the actual classes that implement it (yes,
you're right, I come from a static typing background). But then I read
something (I don't remember where :( ) which said that agile languages
don't need to implement so many patterns and I think I saw the light!

I don't need a Protocol class, the network client should just call the
methods of the protocol and duck typing should do all the magic. Am I
right? Am I coming a little closer to walking the Ruby Way?

You've got it! Congratulations. :)
Please, post a positive reply and you just may save me a couple of
therapy sessions :p

I'm happy to be of service. That'll be $250. :p
 
N

Nicholas Van Weerdenburg

That's the idea, and with a small project, it seems the way to go-
just have any class that wants to be a protocol implement login,
logout, send, receive.

Similarly, you may might want your protocol classes to implement IO
methods, such that it can seamlessly take place of an IO object or
File object.

If, you find problems with run-time errors due to a large number of
erronous new protocols being implemented that escape unit-tests, you
could define a protocol not so much as a type, but as a contract.

module Protocol
attr :login, :logout, :send, :receive # alternative- implement
methods with a "raise Exception" in the body, forcing overrides in the
class mixinng in Protocol. But a more general method, like shown below
in MyProtocol, is cleaner and saves typing in the long run.
end

class MyProtocol
protocol Protocol # where protocol is a custom include like
method that does a design-by-contract type check that all of
Protocol's methods are implemented.
end

MyProtocol will now thow an exception until it implements all 4
methods. And it explicitly documented my contract for the programmer
looking at the code.

But I'm leaning away from even this lately. Last month I still liked
interfaces a-la Java, and that's largely disipated. Maybe next month
I'll have quacked-up completely, and not worry about protocols either.
I'm still waiting to see how my code talks to me as I write larger
Ruby programs.

Considering protocols some more, I find that in Ruby itself, I find
myself thinking in terms of interfaces/protocols as implicitly defined
by core ruby, example- e.g. Enumerable, Comparable, Array, Hash, IO,
BasicSocket as a few. While these don't enforce any implementation
contract to go with their interface example, they provide a set of
implied interfaces for my mind to consider.

This set turns out to be quite broad, and I don't find many impluses
to create others, such as your Protocol class. It usually seems to
have little value. But I can still perceive the need in a larger
system that has a lot of variations on a unique object type (e.g.
Document in a large document management system). But then, a module
usually emerges for reasons of factoring out common functionality, and
it handles the explicit protocol definition quite well as a side
effect, rather then a explicit goal. So the module, while not
providing enforced implementation of a protocol, does provide good
documentation of what it is, and a mental concept to think with. And
if a module doesn't appear to satisfy other needs, such as common
functionality, then your probably don't have enough complexity to
really benefit from an explicitly defined interface anyhow.

Now if you ship a framework, or have lots of programmers working on
the project, then adding the ability to ensure implementation of
certain methods through an explict protocol mechanism like the one
considered above becomes interesting. But some would argue the unit
tests would provide the implementation contract. But I'm not sure of
that- the person subclassing may not write test, or even if they do,
they may not understand the full ramifications of the class they are
extending. And, the original unit tests might not automatically pick
up sub classes.

Note that while the protocol-pattern is somewhat like a Java interface
(which is like an ObjectiveC protocol...), general Ruby programming
patterns would never make use of it anyway. Usually it's typed
variables, typed collections (e.g. generics or custom collections), or
casts that make use of interfaces or parent classes. And if you start
adding code to get a similar effect, you are way-gone from
duck-typing.

Now that I've written this, it occurs to me that maybe I'm really
thinking about design-by-contract (DBC), with one case being ensuring
the implementation of a certain protocol/set of methods. But since the
concept of protocol isn't used for anything else, maybe it's better
consider as a DBC need being applied uniquely in cases where
unit-testing doesn't suffice.

Okay, so I've now punted on interfaces and protocols, and am left
brooding over DBC. I wonder if there have been any interesting
discussions on the value of DBC in Ruby. Something to google for later
this week.

Regards,
Nick
 
M

Mathieu Bouchard

I don't need a Protocol class, the network client should just call the
methods of the protocol and duck typing should do all the magic. Am I
right? Am I coming a little closer to walking the Ruby Way?

Ruby allows you to play in the swamp, but it doesn't mean it's better to
play in the swamp: rather see it as an opportunity to build your own raft,
hopefully better than the one-size-fits-all raft provided with your
standard static-language.

If you want to automate and refactor (DRY/OAOO) your unit-tests to the
point that a set of unit-tests is shared among all modules-or-classes that
implement the same protocol, then it's better to encode a hint in your
program. That hint is to inherit from a dummy module-or-class.

Furthermore, once you have done that, you have also automated the process
of adding helper-methods to all modules-or-classes that implement the same
functionality. Think about how you can add methods to Enumerable and
Comparable.

A small aside regarding Ruby's peculiar multiple-inheritance system: I'd
rather define a protocol using a non-class module than with a class,
because then a same class can implement several protocols without
conflict, as a class can inherit from any number of non-class modules, but
only from one class, and a non-class module cannot inherit from a class at
all.

Those are pragmatic techniques completely consistent with the basic
principles of pragprog/xp/agile, but for some reason, many among those
communities have preferred to take a more, er, romantic path.

Duct-taping as a design philosophy is an obfuscation technique.

More Canadian Content:

http://images.amazon.com/images/P/B00008R9KR.01.LZZZZZZZ.jpg

_____________________________________________________________________
Mathieu Bouchard -=- Montréal QC Canada -=- http://artengine.ca/matju
 
R

Robert Klemme

Edgardo Hames said:
Hi, you all.

I'm working on a new small project where several network protocols are
to be supported. I had an idea about how to implement it and it
resembled something like this.

class Protocol
abstract :login, :logout, :send, :receive
end

class MyProtocol < Protocol
def login
# does something useful
end
... # so on
end

Then my network client would just call the methods of a Protocol
object without caring about the actual classes that implement it (yes,
you're right, I come from a static typing background). But then I read
something (I don't remember where :( ) which said that agile languages
don't need to implement so many patterns and I think I saw the light!

I don't need a Protocol class, the network client should just call the
methods of the protocol and duck typing should do all the magic. Am I
right? Am I coming a little closer to walking the Ruby Way?

Please, post a positive reply and you just may save me a couple of
therapy sessions :p

:) You're compltely right.

Some additional musings: In your case I'd add a base class only if all
protocols share some common behavior or state. This keeps redundancy low.

# example
class Protocol
def cycle
session = login

begin
yield session
ensure
logout
end
end

def send_all(*a)
a.each {|x| send x}
end
end

Another reason might be that you have to plan for future extensions and
you want to have a place to put them. Then you can justify an empty base
class because if you have lot's of protocols it might be tedious to add
the base class later.

Kind regards

robert
 
C

Curt Sampson

Duct-taping as a design philosophy is an obfuscation technique.

No, Ruby's implementation of it is the problem. You can do duck typing
very much like Ruby does and still have statically checked types; you
just need a type inference engine to do that for you.

I think that that may actually be the next big step in popular
programming languages. A lot of programmers these days expect that they
will both never have a memory leak, and never have to track memory
allocations and deallocations by hand. So we have garbage collectors.
Soon people may see that it's perfectly reasonable to expect to be told
at compile time type about type mismatches, and yet not have to keep
track of types by hand, in the way that Java forces you to (and prevents
duck typing). So add a type inference engine or whatever you need for
this.

I've given "no type-checking except at runtime" a go for a while now,
and I've decided it makes life much harder than it needs to be. ("What
can I pass to this? It looks like it wants something that looks kinda
like an array, but just how much like an array? Ooops! More than just
that much!")

It's a heck of a lot easier to use an unfamiliar library in Java than
in Ruby, because it's a lot more clear what the methods you're invoking
expect you to hand them.

Of course, creating something like this is much harder in a language
like Ruby where objects are ever-changing and ever-malliable. But even
for Ruby it should be possible to do it at least to some extent, falling
back to exceptions at runtime if you're doing something tricky (such as
adding and removing singleton methods on an object on the fly).

cjs
 
L

Lothar Scholz

Hello Curt,

CS> On Tue, 25 Jan 2005, Mathieu Bouchard wrote:

CS> Of course, creating something like this is much harder in a language
CS> like Ruby where objects are ever-changing and ever-malliable. But even
CS> for Ruby it should be possible to do it at least to some extent, falling
CS> back to exceptions at runtime if you're doing something tricky (such as
CS> adding and removing singleton methods on an object on the fly).

100% ACK.
As a toolwriter i often get requests: I want a good working
refactoring browsers, where are the code tooltips,
can't you integrate a ruby lint etc.

These tools all need a type inference engine and this is a huge task.
If someone wants to start with it perfect. I really want to see the
heuristics that are used. And i really hope that ruby gets some common
agreements how to write type assertions very soon.

I recently read an article on www.smalltalk.org about the python
typing extension. It's bad to see that so many people don't understand
that this technique can be optional and some hints are much better then none. We
don't need to be able to specify everything, but in most cases it's
very easy and very helpful to do so.
 
P

Pit Capitain

Lothar said:
CS> On Tue, 25 Jan 2005, Mathieu Bouchard wrote:
CS> Of course, creating something like this is much harder in a language
CS> like Ruby where objects are ever-changing and ever-malliable ...
100% ACK.
As a toolwriter i often get requests: I want a good working
refactoring browsers, where are the code tooltips,
can't you integrate a ruby lint etc.

These tools all need a type inference engine and this is a huge task.
...

I'm sure you know where the original refactoring browser came from. Your last
statement is simply wrong.

Regards,
Pit
 
L

Lothar Scholz

Hello Pit,

PC> ...

PC> I'm sure you know where the original refactoring browser came from. Your last
PC> statement is simply wrong.

If i remember correctly the first version was not more intelligent
then a grep with some good regexprs (for the most important "rename
method" and "rename class" refactoring moves) all later versions have
a build in type inference engine based on heuristics.

This can be done much much easier in smalltalk so the type inference
does not need so much explicit written help.

Remember that even things like counting argumetns in a method
invocation and comparing that with the arguments in a def statement to
find out if this is a possible invocation of the declaration is a very
simple type inference engine.
 
N

Nicholas Van Weerdenburg

Smalltalk's refactoring browser is image-based. The environment is working
on the end-result of all dynamic stuff (with the effective source
representation of that end-result). If you have dynamically added a method
to a class, that method shows up in the browser (I think!).

Wouldn't it be far more difficult to implement such a tool based solely on
the source-code that caused all that dynamic stuff to happen in the first
place.

Is image-based tooling a mismatch for Ruby? Hmmm.

This is the impression I've gotten- that a live image system uses the
objects that exist while programming against a live system to do code
completion, etc. In effect, this is what irb completion does.

As for the inference engine, I'd be very happy with a 80% accurate
solution- e.g. the really dumb cases. It would offer a great
performance boost, IMHO.

I have to admit though- the level of trust I have with the IntelliJ
IDEA refactoring tools is so high, I never think twice about
refactoring. However, with unit tests and version control in the ruby
world, I would be pretty comfortable as well. All I need is a good
impact report with a "Do it!" button.

Interestingly, Rails seems to be evolving into a pseudo-image-like
system, with class reloads and breakpoints that spawn irb sessions.
Conceivably an editor could be smart enough to bind to the running
environment.

Regards,
Nick
 
N

Nicholas Van Weerdenburg

Ruby allows you to play in the swamp, but it doesn't mean it's better to
play in the swamp: rather see it as an opportunity to build your own raft,
hopefully better than the one-size-fits-all raft provided with your
standard static-language.

If you want to automate and refactor (DRY/OAOO) your unit-tests to the
point that a set of unit-tests is shared among all modules-or-classes that
implement the same protocol, then it's better to encode a hint in your
program. That hint is to inherit from a dummy module-or-class.

Furthermore, once you have done that, you have also automated the process
of adding helper-methods to all modules-or-classes that implement the same
functionality. Think about how you can add methods to Enumerable and
Comparable.

My recent thought was that this should emerge as the result of good
programming practice. If you have complexity that requires a protocol,
then there is probably a module that already emerged and fills the
need- e.g. Enumerable, Comparable, IO, etc.

I'm now thinking that explicitly thinking about protocols and
implementing them in a top-down manner is often not so necessary for
this reason. There is a suprising amount of context that a well-writen
program provides on a larger scale. These are harder to indentify then
the problem "how do I know what a represents?" but I think they tend
to emerge.

This explains why rapid Lisp and Smalltalk programmers truly don't
miss explicity-protocols in most cases. I'm not sure if there are
enough large Ruby programs to consider this.

Of course, this implies well written programs, which is not the norm
in the world. Which again makes me think of the possible distinction
between pack-programming languages and hacker languages.

And like extreme programming, most early large Ruby programs will be
probably be done by smaller groups of the leading lights of the Ruby
community. That might not generalize well to the world-at-large.

Finally, this implies a bottom-up style of programming, and that is
something of a personal style. So explicity protocols may help people
decompose and think about there program while writing it.
A small aside regarding Ruby's peculiar multiple-inheritance system: I'd
rather define a protocol using a non-class module than with a class,
because then a same class can implement several protocols without
conflict, as a class can inherit from any number of non-class modules, but
only from one class, and a non-class module cannot inherit from a class at
all.

Those are pragmatic techniques completely consistent with the basic
principles of pragprog/xp/agile, but for some reason, many among those
communities have preferred to take a more, er, romantic path.

Duct-taping as a design philosophy is an obfuscation technique.

More Canadian Content:

http://images.amazon.com/images/P/B00008R9KR.01.LZZZZZZZ.jpg


Red Green rocks! Hmmm. I never equated duck typing with duct taping.
Much to consider...

_____________________________________________________________________
Mathieu Bouchard -=- Montréal QC Canada -=- http://artengine.ca/matju

Nick
 
N

Nicholas Van Weerdenburg

Hello Curt,

CS> On Tue, 25 Jan 2005, Mathieu Bouchard wrote:

CS> Of course, creating something like this is much harder in a language
CS> like Ruby where objects are ever-changing and ever-malliable. But even
CS> for Ruby it should be possible to do it at least to some extent, falling
CS> back to exceptions at runtime if you're doing something tricky (such as
CS> adding and removing singleton methods on an object on the fly).

100% ACK.
As a toolwriter i often get requests: I want a good working
refactoring browsers, where are the code tooltips,
can't you integrate a ruby lint etc.

These tools all need a type inference engine and this is a huge task.
If someone wants to start with it perfect. I really want to see the
heuristics that are used. And i really hope that ruby gets some common
agreements how to write type assertions very soon.

I recently read an article on www.smalltalk.org about the python
typing extension. It's bad to see that so many people don't understand
that this technique can be optional and some hints are much better then none. We
don't need to be able to specify everything, but in most cases it's
very easy and very helpful to do so.

Several interesting articles on http://www.smalltalk.org at the moment-

"The Futility of Adding Types to a Dynamic Language"
and
"Extending Encapsulation For Smalltalk"

Are interesting looks into typing and encapsulation in dynamically
typed systems.

It was also amusing that the author of the first added a side-bar
essentially apologizing for disagreeing with Guido Van Rossum.

"Please note that it is my opinion and view that adding types to
Python are a mistake and that this should not be seen as an ad hominen
personal attack upon Guido van Rossum, as that is not intended
(...rest clipped...)"

http://www.smalltalk.org is a nice looking site as well.

Nick
 
F

Florian Gross

Nicholas said:
This is the impression I've gotten- that a live image system uses the
objects that exist while programming against a live system to do code
completion, etc. In effect, this is what irb completion does.

Partially, IRB does not actually evaluate the expressions. If it sees
that you are calling a method it will IIRC just list all methods that
are provided by any of the currently loaded classes. This is a good
thing for expressions with side effects such as `rm -rf /`, but could be
improved in other cases.
Interestingly, Rails seems to be evolving into a pseudo-image-like
system, with class reloads and breakpoints that spawn irb sessions.
Conceivably an editor could be smart enough to bind to the running
environment.

As the author of the breakpoint library I'm still very interested in
using it for writing an IDE that will attach to a live code base and
allow you to investigate, modify and much more. Note that this would at
first not be just as nifty as the Smalltalk solutions because you can
not generally get code for methods and so on, but using some of the cool
thing like the AST library or by reading back the code from Files you
could probably get pretty close.

It's an interesting area and I'd be willing to offer as much support as
I can to such efforts if somebody can kick this off with a decent code base.
 
N

Nicholas Van Weerdenburg

Partially, IRB does not actually evaluate the expressions. If it sees
that you are calling a method it will IIRC just list all methods that
are provided by any of the currently loaded classes. This is a good
thing for expressions with side effects such as `rm -rf /`, but could be
improved in other cases.


As the author of the breakpoint library I'm still very interested in
using it for writing an IDE that will attach to a live code base and
allow you to investigate, modify and much more. Note that this would at
first not be just as nifty as the Smalltalk solutions because you can
not generally get code for methods and so on, but using some of the cool
thing like the AST library or by reading back the code from Files you
could probably get pretty close.

It's an interesting area and I'd be willing to offer as much support as
I can to such efforts if somebody can kick this off with a decent code base.

Cool!

(I'm saying that too much the last few days)

What code base to mean? IDE or "live codebase"'?

This is way beyond me so I'd be interested in knowing what you think
the main components needed are, and how the functionality would be
distributed across breakpoint, IDE, and a "live codebase" manager.

Thanks,
Nick
 
M

Mathieu Bouchard

No, Ruby's implementation of it is the problem. You can do duck typing
very much like Ruby does and still have statically checked types; you
just need a type inference engine to do that for you.

Well, I was not questioning Ruby at all here, but rather, how the current
Ruby together with unit-testing and DRY implies that one should have
something like abstract-classes.

Now if you do have an (already implemented) system that does
type-inference in Ruby I am curious.
Of course, creating something like this is much harder in a language
like Ruby where objects are ever-changing and ever-malliable. But even
for Ruby it should be possible to do it at least to some extent, falling
back to exceptions at runtime if you're doing something tricky (such as
adding and removing singleton methods on an object on the fly).

So you say that this is all "in theory"?

There's a large gap between dream and implementation...

_____________________________________________________________________
Mathieu Bouchard -=- Montréal QC Canada -=- http://artengine.ca/matju
 
F

Florian Gross

Nicholas said:
What code base to mean? IDE or "live codebase"'?

The IDE project.
This is way beyond me so I'd be interested in knowing what you think
the main components needed are, and how the functionality would be
distributed across breakpoint, IDE, and a "live codebase" manager.

I've not thought much about this yet, but I think the separation would
be like this:

* breakpoint: Backend for running code in the right places of a running
application.
* live codebase manager: Find code for method objects, extract diverse
meta data.
* IDE: frontends for displaying the results of the live codebase manager
and for providing a GUI for manipulating the environment.
 
C

Curt Sampson

So you say that this is all "in theory"?

No. It has been done in practice, just not for Ruby.

But I would propose actually changing the language to better support
this sort of thing.

cjs
 
R

Robert Klemme

Curt Sampson said:
No. It has been done in practice, just not for Ruby.

But I would propose actually changing the language to better support
this sort of thing.

I opt against this: not every good or useful language feature must be
present in Ruby.

Regards

robert
 
A

Alexander Kellett

I opt against this: not every good or useful language feature must be
present in Ruby.

i've lost the track of threads now (hope you don't mind
if i request that you please use 'was: blah' when changing
thread name...)

is this for having the benefits of static type checking
or for optimisation?

Alex
 
C

Curt Sampson

I opt against this: not every good or useful language feature must be
present in Ruby.

No. Ruby could end up being a second-rate language instead.

Look at Java. It was ten years behind the state of the art in OOP
when it was first made, has advanced little since, and its prospects
for real advancement are almost nil. (I'd bet that never going to
see continuations in Java, for example.) Java's already reliant on
precompilers for things like macros and aspect-oriented programming.

That's why I left Java for Ruby.

Lisp, on the other hand, in all of its various forms, is still one of
the most powerful programming languages in the world, and is still
being used to write new systems more than forty-five years after its
invention.

Ruby asked me to give up a lot of useful type checking in order to get
duck typing. It does not have to do so. If it continues to do so, one
day a language is going to come along that offers what Ruby does but
doesn't make this compromise, and people will start switching, just as
people are now switching from Perl to Ruby because Perl doesn't "need" a
better syntax for OO work.

cjs
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,522
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top