From: "Chris Uzdavinis" <chris / atdesk.com>
> "Nat Pryce" <nat.pryce / b13media.com> writes:
> > In Ruby, instead of defining classes or interfaces, you define
> > protocols that objects should speak, and define those protocols
> > outside the language.
>
> This is interesting.  What distinction do you make between protocol
> and interface?  Can the protocol be independent from the interface?

A protocol encompasses (a) more than one interface and (b) how and when
the parties in a protocol can invoke methods on those interfaces, and what
parameters they can pass to those invocations.

> > You can then define useful classes or modules that implement those
> > protocols, but a programmer can just as easily write the protocol
> > from scratch.
>
> Yes, in that regard, every ruby function is like a C++ function
> template.  (Gotta make those C++ comparisons...!)
>
>   template <typename T> void foo(T arg) { /*...*/ }
>
> Rather than an "interface" which is a fixed, hard coded set of
> requirments, of which perhaps only a subset is actually used,
> templates use what they call the "concept" approach.  ANY arg can be
> passed in provided that it supports all the necessary concepts which
> the code places on it.  (The difference is a compile-time check is
> made, rather than runtime.)

It is similar to a C++ template in that C++ templates are turing complete
and dynamically typed.  You can, if perverse enough, write complete
programs in C++ templates and have then interpreted by the C++
compiler!  Similarly, Ruby programs are turing complete and dynamically
typed.  However, Ruby has a human-friendly syntax and a far more
convenient development environment :-)

Just as with C++ templates, violating protocols in a dynamically typed
language can result in obscure error messages. The C++ community is
developing mechanisms to type-check templates as early as possible.
In a dynamically typed language, unit tests fulfill the same role.

> > An simple example of this kind of protocol is the relationship
> > between the methods hash and eql? or the Enumerable mixin requiring
> > the existence of the each method.
>
> These are good examples.  Do you think that when we write Ruby code
> that this type of mindset should be the primary kind of issues we
> think about?

Yes.

This is the fundamental mind-set that I use when desiging OO code, whether
in a dynamically typed language or a statically typed language.  A
statically
typed language lets you define interfaces or abstract classes, but they
don't
actually let you define the *protocols* by which objects interact, and so
are only of limited practical use.

> How would you suggest we recover when an argument does not support the
> protocol?  Since Ruby is dynamic, object x may not support it now, but
> if you try again later it might.  Or vice versa.

You don't recover.  That's a programming error -- a bug.  Programming errors
are the fault of the programmer and should be caught by unit tests.  If an
error occurs at run time you should (a) write a unit test that fails because
of
the error and (b) fix the code so that the unit test passes.  You now have
better code and a more complete suite of tests.

> There certainly is an element of uncertainty introduced along with all
> the dynamic capabilities.

Only if you don't have adequate tests.  Dynamic code is a convenience,
and a great one.  However, the behaviour of a package will not magically
change because it is written in dynamic code.  The behaviour of the package
should be specified both in terms of protocols, and by a good suite of
unit tests.

> The trick is keeping it balanced to where
> you can know what's going on but still have flexibility.
> I still have this uneasy feeling, though, that nothing can ever be
> completely trusted, because perfectly working code can easily be
> broken by other code in another file which is completely unrelated to it.

Again, only if code is not properly specified and tested.  Unit tests are an
executable specification of how code should behave.

> It seems you have to really know everything that is going on in a
> program to know if it's going to work.  Though there are Modules to
> kind of separate things, it's not truly modular since if your code and
> mine are running in the same program, my code can break yours, and
> vice versa.
>
> The risk to me is not all just type, but behavior too.  In a big
> application it's unreasonable to expect everyone to study every line
> of every file that everyone else is working on.
>
> So when someone modifies the behavior of Array class such that []
> becomes 1-based, for example, he breaks MY working code, which hasn't
> changed.

Again, use automatic test suites!  Never do by hand that which a
computer can do automatically :-)

Cheers,
            Nat.