[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