Thursday, May 18, 2017

Slytherin Software Engineering: Checked Exceptions, Java 8 Streams, and you!

There's nothing quite so Slytherin in software as functional programming. A functional program is not a heroic quest to impose order on the chaos of memory, but the evaluation of elegant mathematical and logical expressions, over data structures that can never change, with no side-effects. Is all as it ever was? Yes. Our machines are not as perfect as our ideas, but we use compilers to keep the (vaguely dirty) world of processors, instructions, and memory separate from our timeless forms. Additionally there's a bit of the esoteric: pure functional programming disallows the most basic elements of the imperative style that most people learn first, data structures like arrays and control-flow ideas like iteration. This lends itself to uniform syntax with meaning differentiated by position and hierarchy, not ugly flat structures with wide varieties of (plucky?) characters. This is serious Slytherin stuff, right here.

Alas, sometimes even a Slytherin must code in Java. Java's endemic flaw is that it never has enough features; in this it is infinitely preferable to, say, C++, which always has too many! The consequence of this flaw is that we must write lots of redundancies. A redundancy is a statement that offers no possibility for expression, but that we must write anyway. This is drudgery, mere toil, not befitting our high nature! Java has long supported some functional idioms and even anonymous classes, but using them was an exercise in managing redundant boilerplate. Java 7 helped clear some Generics-related boilerplate, but Java 8's compact lambda expressions and Streams API finally made functional expressions look good on the page.

There's just one problem: what if your lambda expression calls some function that throws a checked exception? Streams methods won't accept such a lambda! This sort of problem predates Java's lambdas and Streams, but now that functional idioms are good-looking enough to use it's a problem worth re-examining. So let's consider the possibilities.

You could handle the exception. Yeah, right. In your nice, pithy lambda? What are you, a Hufflepuff? You didn't throw that exception, it's not your responsibility. Let someone else handle it.

You could catch it, wrap it in RuntimeException, and throw that. You'd do that with a higher-order function, obviously. The downside to this is that by wrapping the checked exception you obscure its true nature to callers. That's a red flag right there (we obviously prefer green ones). Another core Slytherin value this violates is reciprocity. You had to deal with the annoyance of a checked exception and it's your right to propagate this annoyance up the call stack. But to force the caller to check arbitrary levels of getCause() and try to guess the intentions of the various wrapping layers? I'm not going to lecture you about fairness or the social contract, but think of the possible consequences: your caller could denounce your method for being imprecise. You don't want that reputation. It's just this fear that makes us civilized; do heed it.

You could wrap the exception to get it through the Streams expression, then catch it outside and unwrap it for the caller. For this you need a more specific type than RuntimeException, one that is only used for this purpose — if you wouldn't make your caller guess at the meaning of a caught RuntimeException you certainly shouldn't have to do it. This is the Golden Rule of Entitlement shared by all Slytherins, in case you were already developing a habit of skipping class by Kindergarten. So you declare such a type along with your function-wrapper and take care to use it consistently. But now your aesthetic is starting to slip. I once had such code reviewed by a Ravenclaw that commented, “That's an awful lot of control-flow just to avoid a for loop.” I could only sulk, “And an awful lot of type-names just to avoid a builder,” and take my laptop and cognac into the stairwell to rewrite the whole module, newly enlightened to the futility of striving for beauty, for unity of expression and purpose. Never have your code reviewed by a Ravenclaw.

It turns out that the best way, for a Slytherin, was invented in 2009. Do the sneakyThrow. Like it just by the sound of the name? I thought you might. You still have to wrap your lambda expression, but you don't need an extra try-catch block around the Streams expression, and the exception that comes out is exactly the type that was thrown. All you did was abuse Generics so you could make an unchecked cast and deliberately make that cast incorrectly to an unchecked type1 to fool the complier's static exception-type checks — the ends justify the means. Now you can put a (correct) throws declaration on your method, tie it up in a nice little bow, and laugh as the compiler warns you about it: how naïve it is, how little it knows of the dark arts.

You could also leave the throws declaration off and lift the burden of checked-exception handling from your caller. This could have real consequences: there are exception-handling schemes out there that rely on the methods they invoke to honor their declarations. Some Slytherins would say that the weakness of those that trust in the honor of others is their own fault, that we should not be blamed for doing what we must. I mean, it's just code, so do whatever, but don't be a douchebag about stuff that really matters, OK?


1 Two different meanings of “unchecked” in one sentence... oh, dear...

Saturday, May 6, 2017

Should a word have two meanings? What the fuck for?

When first I sat at the table I took all the cards at face value. It was bad enough when they gave me directions according to where the old post office used to be. Worse when I arrived there with a package to mail. “And where should I take this, the hospital?”
“Only if it's for a patient, dear.” She took a drag, stamped out her cigarette on the curb, and walked back into the bookstore.

In the town square stood a statue of a man in a military coat and cap, striding forward with anger in his face. “A civic or national hero?”
“Why, no. He led a revolution for a country that no longer exists in a land that, though it's a lot like ours, still seems a world away.”
“Then, what, he was an exponent of our ideals?”
“Well, I can't speak for everyone, but not mine. His professed ideology ridiculed political and personal freedoms from the first. When he held power he indeed suppressed these and others besides, and used racist oppression as a tool to consolidate political support. This came to be a hallmark of his country and its successors, though of course this is hardly unique in the world.”
“Then why should we keep his statue here?” The plaque below mentioned something about its artistic significance. It had been pulled from a scrap heap after the war.

A bar off the square had its own statue outside. A person holding a glass, with a motorized arm lifting the glass to drink and lowering it back down, over and over again, forever. A sticker on the door read, “Register to vote here.” Inside a drinker slapped his arm around me. He was, it turned out, in this strange city, from my home town, and that's one of our local pastimes: getting black-out drunk and hugging eachother. That's one of the reasons I left. He raised his glass and toasted a candidate for local office whose speeches were false fiction (fiction is no different from fact or prophecy, it can be false but it isn't always). I wasn't going to change his mind.

He had a landscaping practice. His best customer was always traveling for business but kept a house in a post-bohemian neighborhood up the hill from the square. He was taking classes for an Associate's Degree but was struggling with math requirements. I met an accountant once that said she never liked math, and was never good at it. Then she wondered aloud why she'd gone into accountancy! Anyway, eventually he asked me what I did for work and I didn't have a quick deflecting lie ready and it was like he knew. I have lots of quick lies ready for when my colleagues ask me about my personal life, but not for that, because they all know what I do for work! He said he'd never been so close to someone he wanted to punch in the face.

He lived a couple dozen miles south of town. Past the shipping port and the huge railyard that spreads out from a massive freight beltway, hidden to highway maps but imposing on the ground, in a glacial valley among factories and warehouses. He'd parked blocks away on a side street to avoid the specter of crime on the main drag. He was frighteningly drunk. Before my work came up and before punching-in-the-face came up he'd been laughing at my expense, or at the expense of the act I put on. Many of my lies and embellishments are self-deprecating, and I was dressed ridiculously; punch up or punch in, that's comedy. Now his sarcastic disgust was getting angrier. “I bet you take public transportation!” he sputtered. I didn't mention my bike locked up outside. I guessed at the sort of route he might take out to the freeway and made a mental note of streets to avoid on my way home.