char* response(messy* message) {
body* b = message->body;
if(b==NULL) {
return NULL;}
char** lines = b->text;
if(t==NULL) {
return NULL;
}
if(b->line_count < 11) {
return NULL;
}
return t[10];
}
Writing all of those if statements grows tedious. A lazier programmer could just drop them, but then the program would crash whenever the program received malformed data.With Hackell, though, I can refactor out the if statements and get the following equivalent code:
response :: Messy -> Maybe String
response message = do
b <- body message
lines <- text body
lines `atMay` 10
I want to be clear on a couple of points. First, the Haskell code performs all of the same "null" and bounds checks that the C code made, so this is an apples-to-apples comparison. Furthermore, this isn't using exceptions, like a similar piece of C++ code might try. There's no stack unwinding and nothing can escape to contaminate the rest of your program. Finally, this isn't just a weird special case built into the language. With a minimal amount of effort, I could have each failure return a unique error Code. errorCode :: Maybe a -> b -> Either b a
errorCode (Just value) _ = Right value
errorCode Nothing code = Left code
response :: Messy -> Either Int String
response message = do
b <- body message `errorCode` 1
lines <- text body `errorCode` 2
(lines `atMay` 10) `errorCode` 3
I don't know a way of doing that in any of the C style languages. In those languages, you're forced to add in another if statement every time your code touches message->body to ensure that you're not going to segfault. With Haskell, I can refactor away those if statements and I don't have that code being duplicated all throughout my project.EDIT: improved readability of errorCode