Protocols for the Brave
You might have heard about the old ways gaining hype recently, and we don’t mean praying to the gods of the north.
Functional programming is the rediscovered toy which is bringing some sanity to the world of mutable state and global bindings.
Today we’re introducing a feature found in Clojure which allows you to define interfaces for your classes. Let’s look at one-off implementation:
const protocols = (...ps) => ps.reduce((c, p) => p(c), Object);
const Mappable = (klass) => {
return class extends klass {
map() {
throw 'Not implemented';
}
};
};
const Foldable = (klass) => {
return class extends klass {
fold() {
throw 'Not implemented';
}
};
};
class NaturalNumbers extends protocols(Mappable, Foldable) {
constructor() {
super();
this.elements = [1,2,3,4,5,6,7,8,9];
}
map (f) {
return this.elements.map(f);
}
fold (f) {
return this.elements.reduce(f, this.elements, 0);
}
}
Yes, we’re building a chain of class inheritance up there with that reduce boy. It’s pretty cool. We’re doing it dynamically! You see, each protocol receives a base class (Object) and extends it somehow returning the new class. The idea is similar to that of interfaces.
We supply method signatures for the protocol and make sure we provide implementations for it on our base classes.
What’s so cool about it? We get to write things like these:
const map = f => o => o.map(f);
const fold = f => o => o.fold(f);
const compose = (... fns) => fns.reduce((acc, f) => (x) => acc(f(x)), id);
Ok, maybe we could have written those two functions without the above fuzz but,
now that we know NaturalNumbers
are Mappable
, we can call map
on them
and trust it will return the right result. Furthermore, with our third function,
we can compose any number of operations defined in protocols cleanly:
const plus1 = x => x + 1;
const div5 = x => x / 5;
const plus_then_div = compose(map(div5), map(plus1));
console.log(plus_then_div(new NaturalNumbers));
// => [ 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2 ]
More important, if we know that an object of ours is Mappable
, we know map
will work on it. Protocols gives us an idea of what we can do with an object and
help us abstract common operations between data types, thus reducing the
overhead of dealing with a hundred functions.
What is easier? To have a hundred functions for every different object or ten functions that work on a hundred objects?
Use the 100 answers in this short book to boost your confidence and skills to ace the interviews at your favorite companies like Twitter, Google and Netflix.
GET THE BOOK NOWA short book with 100 answers designed to boost your knowledge and help you ace the technical interview within a few days.
GET THE BOOK NOW