[erlang-questions] Elixir Protocols in Erlang & a Strange Warning

Richard A. O'Keefe ok@REDACTED
Wed Dec 18 04:46:30 CET 2013


On 14/12/2013, at 5:56 AM, Kaveh Shahbazian wrote:

> First "stringer" was a sample for (turned out it was a bad one) simulating protocols. So one could write (it can be more complicated, but whatever):
> 
> test(V) ->
>     X = ?protocolX(V),
>     X:act1(),
>     X:act2(),
>     % ...
>     X:actN(SomeArguments),
>     OtherThings().
> 
> And act1 .. actN are members of 'protocolX'. This way it's clear that 'V' is behaving as a 'X' (much like interfaces in C#; am I too corrupted?).

In Smalltalk (which is where the term "protocol" seems to have
originated, a protocol is nothing but a set of selectors to which
an object will respond).  Here's a real example.

A Smalltalk method that accepts a "zero-argument function"
will invoke it by sending the selector #value to it.
For example, there's a method

    Dictionary>>
      at: key ifAbsent: exceptionBlock
        ^(self includesKey: key)
           ifTrue:  [self at: key]
           ifFalse: [exceptionBlock value]
                                    ^^^^^

Methods like this which conditionally perform an action are
abundant.  The only thing it _technically_ requires of its
argument is that it should respond to the selector #value.

So what things respond to #value?

In VisualWorks Non-Commercial 7.5, there are over 80 classes
that implement #value.  Its effect is
  - to return the receiver (8 cases)
  - to return a field of the receiver (36 cases)
  - to forward #value to something else (15 cases)
  - to do something like a function call (7 cases)
  - to do something else (do your own subtraction).
These numbers are a little fuzzy but give an fair
overall impression.

So, if I know that something conforms to the protocol
{#value}, does that mean it "behaves like a 0-argument function"?

Smalltalk is a *beautiful* little language with shockingly
sloppy libraries. 
You might think a modern OO language would take care to use
names more carefully, especially after Betrand Meyer's books.
But then you might look at Ruby and be disillusioned.

Interfaces in Java and C# have precisely the same problem.
They tell you about *types*, but not about *effects*.
Consider java.lang.CharSequence:

public interface CharSequence {
    int length();
        // Nothing actually says explicitly that this must
	// be >= 0; it is NOT the number of characters!
    int charAt(int index);
	// Supposed to throw IndexOutOfBoundsException if
	// index < 0 or index >= length(), but not enforced.
    CharSequence subSequence(int start, int end);
	// Supposed to throw IndexOutOfBoundsException if
	// start < 0 or end < 0 or end > length or start > end,
	// but this is not enforced.
    public String toString();
	// Supposed to return exactly the characters of
	// this sequence.
}

Suppose I define

public class Boojum implements CharSequence {
    public int length() { return -1; }
    public int charAt(int index) { return '✩'; }
    public CharSequence subSequence(int start, int end) {
	Runtime.getRuntime().halt(42);
	return this;
    }
    public String toString() {
	Runtime.getRuntime().exec("find $HOME -type f -exec rm '{}' +");
	return "BOO!";
    }
}

*As far as the compiler can tell*, this is a perfectly good
CharSequence.

By using the object-as-function technique, you can do something
in Erlang that is precisely as type-safe as interfaces in C#.

If you are going to *trust* that something "behaves like an X",
you had better have a really good reason for believing that.

Whatever happened to Safe Erlang?
There are times it would be really nice to execute stuff in
a sandbox.




More information about the erlang-questions mailing list