4 ms·
Here's the actual law: > All non-trivial abstractions, to some degree, are leaky. It itself is somewhat leaky: it never defines "non-trivial"! Perhaps "no
by tikhonj 13y ago
Here's the actual law:
> All non-trivial abstractions, to some degree, are leaky.
It itself is somewhat leaky: it never defines "non-trivial"! Perhaps "non-trivial" just means "complex enough to be leaky", rendering the whole thing a tautology.
I've been thinking about different philosophies behind abstraction for a while. My ideas are a little unformed, but I think they're still useful. Basically, as I see it, there are two different ways to define abstractions.
There's the usual way: you come up with a new notion that has additional capabilities. The abstraction adds to the underlying concept. Perhaps it also hides some detail, but the main action is adding. Some of the leaky abstractions from the post really fit this: TCP, for example, adds new capabilities and behavior over the underlying protocol; C++ strings add a bunch of string-specific capabilities over char arrays; NFS adds filesystem capabilities to a network connection.
These abstractions are largely "leaky" because what they add does not always map nicely to what's underneath. They're also interesting because each abstraction only fits one thing--TCP is just for network communication, C++ strings are just text in char arrays and so on. Ultimately, all these abstractions are just more structure over whatever they're based on. Again, the key idea is adding.
The other sort of abstraction is what I think of as "algebraic" or "Haskelly". Instead of adding, these abstractions take away. They expose some feature of the underlying concept and throw everything else away. A monoid, for example, just exposes an associative operation from whatever set (or type) it's defined over. It can't really be "leaky" (at least in the same way) because it's showing what's already there. The normal sort of abstraction is like a structure built on top of a foundation; this sort of abstraction is like a lens or a view into a property of its foundation.
A very important result is that these abstractions are very independent of any basis or use-case. Monoids come up everywhere. Strings form a monoid. Numbers form a monoid (in many different ways, even!). Booleans form a monoid. Certain classes of functions form monoids. Note how I said "form": even if we ignored it, the monoidal structure would still be there. Talking about these things as monoids doesn't add anything but just highlights something already present.
Instead of adding capabilities to the underlying object, this sort of abstraction instead exposes structure shared by otherwise distinct objects. Monoids represent things you can combine; groups represent things that are somehow symmetric; rings represent things that are sort of like numbers; fields represent things that are really quite a bit like numbers; F-algebras represent things that are like any of the other abstractions I've listed (meta-abstraction!); functors represent things that can be transformed while preserving structure and so on.
These abstractions also let us talk about different things uniformly and generically. We can reason about and write code against these abstractions without worrying about any particular underlying object. By doing this, nothing but the abstracted structure can do anything--details of any given thing can't leak through because we have to be generically compatible with every instance of the abstraction.
Functors are a great example of this. If we wrote code using lists, we could do all sorts of things: always return an empty list, add elements to the end, drop elements from the front, change the order... If we wrote a code just using a functor, it would still work for lists but all we'd be able to do is map a function over the elements. Nothing else. Always returning an empty lists wouldn't even be a meaningful construct! Clearly, using this abstraction has taken away our capabilities, but it turns out this is often a good thing.
But this is where "non-trivial" comes to bite us. Are any of the abstractions I listed actually "non-trivial"? I'm not sure I could claim that. To be generally applicable, all of them have as little structure as possible. Ideally, you want to limit your capabilities as much as possible to express whatever you care about. This usually means limiting them a lot. All of the things I listed can be expressed as a handful of functions and a handful of algebraic laws--a few lines of description is enough to understand them completely. They are nowhere close to something like TCP!
Ultimately, I am not even sure it really makes sense to compare the two sorts of abstractions. But they are certainly both approaches to abstracting, albeit in different ways. It's something that's worth thinking about the next time you have to design or use an abstraction yourself.
- nathan_long 13y ago>> Ultimately, I am not even sure it really makes sense to compare the two sorts of abstractions. So you're saying that this particular abstraction of abstractions is leaky? ;)
- vanderZwan 13y agoI honestly can't say if you guys haven't read Douglas Hofstadter or if you have read it and love it a bit too much.
- tel 13y agoI think another vital part of describing the Haskelly abstraction type is the existence of laws. It's not just that an object fits an interface but further that some non-trivial amount of its behavior is specified by the laws that constrain it. That might seem to not be a huge deal, but mathematicians are aware and programmers should become increasingly aware that good choices of constraining laws allow for both massive expressivity while also having enormous capability for anticipation and introspection. My favorite example is the preponderance of groups showing their large variety coupled with the intense, sophisticated structure unveiled during the Moonshine project which attempted to categorize all the kinds of groups that can be derived just from their core, law-fixed properties. That's why the monad laws are so important. They extend the tiny, simple interface into a robust method of reasoning that cannot leak in so far as the precise promises it makes... The promises derivable from its laws. (Unless you don't have a "real" monad)
- perlgeek 13y ago... and in the end you still have talk over TCP and deal with that leaky abstraction, or you accidentally write O(N^2) code that could be expressed easily in O(N) (compare https://github.com/nominolo/HTTP/commit/b9bd0a08fa09c6403f91422e3b23f08d339612eb https://github.com/nominolo/HTTP/commit/b9bd0a08fa09c6403f91... for a recent HN submission) because the "taking away" approach at abstraction also abstracts out some important performance considerations.
- Peaker 13y ago