Paul Chiusano

Functional programming, UX, tech, econ

TwitterGitHubLinkedInRSS


Consulting services

I offer Scala and FP consulting services. If you're interested in working together, please contact me.


About my book

My book, Functional Programming in Scala, uses Scala as a vehicle for teaching FP. Read what people are saying about it.


Popular links

Unison: a next-gen programming platform
unison.cloud: the worldwide elastic computer (coming soon)
Type systems and UX: an example
CSS is unnecessary

Needlessly confusing names

[   fp   tech   ]            

Names and the little details of an API matter. I’m going to pick on one small example I came across recently. In unagi-chan, a very fast lock-free queue implementation, we have the following API:

newChan :: IO (InChan a, OutChan a)

Here’s me:

Huh, okay, they split the queue into separate read and write access. Geez, was that really necessary? If I wanted to partially apply readChan or tryReadChan and pass around an IO a or IO (Maybe a), I could do that, you know. Now if I need both read and write access, you’ve forced me to pass around a pair… ugly. But okay, okay, fine, I can deal with this, this thing’s supposed to be screaming fast, I can put up with a few admittedly subjective API warts, and honestly I’m being pretty ungrateful that the people wrote this nice code and made it freely available.

Two minutes later: a type error when trying to read from an InChan. Wait, what? Let me re-check hackage docs here… WAT? readChan takes an OutChan??

readChan :: OutChan a -> IO a

WTF!!?! What kind of idiot would—oh, wait, maybe that does make sense. I’m probably just being dense here. Calm down, Paul. Let’s think about this, do you read from the InChan or the OutChan? Obviously I should read from the InChan… but AHA! From the perspective of the producer, the InChan IS the OutChan. But from the perspective of the consumer, it’s the reverse! This is so fucking confusing! What the hell was I even doing? I’ve forgotten by now…

(After a moment of realization). You know, it’s completely arbitrary whether the InChan is from the perspective of a queue writer or a queue reader, so these names are just confusing as hell. Calling these two types WootChan and Woot2Chan would have been MORE INFORMATIVE, since it would not have tempted me to start writing code based on my assumed understanding of the meaning of In and Out without checking the type signatures!

Not to mention, while I’m trashing this code, who decided to call those functions readChan and writeChan? Where exactly are we writing to / reading from? Is this a stack or a queue? How about enqueue and dequeue, which is more appropriately suggestive of what’s happening?

Five minutes later, I’d settled on this: if you really insist on splitting up the queue into two types, how about these names:

newQueue :: IO (Enqueue a, Dequeue a)

enqueue :: Enqueue a -> a -> IO ()
dequeue :: Dequeue a -> IO a

Now THIS is the sort of API I like. I can use it without switching on random parts of my brain that have nothing to do with what I’m trying to accomplish.

Summary:

Also see this section of design for experts; accomodate beginners.

comments powered by Disqus