Sunday, April 26, 2015

Finding unused code (F#)

Coming from C#, I'm used to the compiler warning me about unused variables. Relying on the compiler to help me with checked exceptions in F#, I noticed that unused values (and functions) would go unnoticed. Having accidentally read earlier that Haskell has a compiler flag to check for unused bindings, I looked for the F# equivalent but failed to find it, until Scott Wlaschin pointed me in the right direction.

By using the --warnon:1182 flag, the compiler will warn you about unused bindings.


For example, compiling Paket.Core with this flag enabled, outputs the following warnings.

Looking into these warnings revealed values and functions that can be deleted, but no apparent bugs. There are also cases where unused bindings make sense, for example when you pass in a function that does not use all of its arguments or when pattern matching. In these cases you can suppress the warning by prefixing the bindings with an underscore.

A useful compiler feature which strangely enough is opt-in. I plan on using it from now on.

Sunday, April 19, 2015

Parsing command line arguments with F#

Last year, I set out to write my first node.js application; a small web application for keeping lists of everything I consume. I had something working pretty quickly, deployed it to Heroku and still find myself using it today. Since there's very little use for having it running on a server, and because I wanted something to toy with getting better at F#, I decided to port it to an F# console application.

With the UI gone, I need to resort to passing in arguments from the command line to have my program transform those into valid commands and queries that can be executed.

The set of commands and queries is limited; consume an item, remove an item and query a list of everything consumed.

Ideally I go from a sequence of strings to a typed command or query. However, when the list of arguments can't be parsed, I expect a result telling me what failed just the same.

Since we need the name to identify the command or query, I expect the input to have at least two arguments.

Arguments come in pairs; a key and a value. My first thought was to build a map here, but that made key validation, key transformations and pattern matching harder.  I can actually get away with transforming the input to a sequence of tuples.

Hoping to avoid some mistakes in the input, basic validation makes sure the keys actually look like keys, instead of a value. Keys start with a single or double dash.

Once that validation is out of the way, I strip away those dashes. That should make the two last steps easier.

The name is required, so I wrote a small function that makes sure a specific key exists.

Now that I have a list of arguments,  I can map them into a typed command or query using pattern matching.

Having written all these small functions, I can simply compose them using Scott Wlaschin's Railway oriented programmming.

This is far from a generic command line parser, but it's simple and covers my needs.

Next up, executing those commands and queries, and printing feedback.

Sunday, March 29, 2015

Checked errors in F#

In the land of C#, exceptions are king. By definition exceptions help us deal with "unexpected or exceptional situations that arise while a program is running". In that regard, we're often optimistic, overoptimistic. Most code bases treat errors as exceptional while they're often commonplace. We are so confident about the likelyhood of things going wrong, we don't even feel the need to communicate to consumers what might go wrong. If a consumer of a method wants to know what exceptions might be thrown, he needs to resort to reading the documentation (or source) and hope it's up-to-date.

Java on the other hand has a concept of unchecked and checked exceptions. Unchecked exceptions are exceptions that are caused by a programming mistake and should be left unhandled (null reference, division by zero, argument out of range etc); while checked exceptions are exceptions that your program might be able to recover from. They become part of the method signature and the Java compiler forces consumers to handle them explicitly.

While checked exceptions might bloat the method's contract and enlarge the API surface area, they might have every right to. Dealing with errors is an important part of programming. Having discoverable errors which require thoughtful care, should improve overall quality. Having said that, it also requires careful consideration from the designer to decide what's truly exceptional.

Coming up with something that can compete with the mechanics of checked exceptions in C# seems to be impossible. We could return a result with an error from a method, but the compiler doesn't force you to do anything with that result.

F# on the other hand doesn't allow for the result of an expression to be thrown away. That is, unless you explicitly ignore it, or bind it and leave it unused.

Let's look at an example. We start by defining two discriminated unions. The first type defines a generic result; it can either be success or failure. The second type defines all the errors that can be returned after deleting a file.

Then we write a function that deletes a file, but instead of throwing exceptions when an error occurs, it returns a specific error. When no errors occur, success is returned.

When I now use this function, the compiler will tell me that it has a return value which needs to ignored or binded.

While ignoring a result stands out, an unused binding is easier to go unnoticed. I wish the F# compiler had a flag to detect unused bindings.

Assuming I don't ingore the result, I can use pattern matching to address each error specifically.

By not including a wildcard pattern, extending the contract by adding errors will introduce a breaking change. We'll have to consider what to do with newly added errors.

For example, if I add the error PathTooLong, the compiler shows me this warning.

In summary, it might be more safe to be a bit less optimistic when it comes to errors. Instead of throwing exceptions, making errors part of the public interface, communicating errors explicitly, and handing responsibility on what to do with the error to the caller, might lead to more robust systems. While this can be achieved with C#, the mechanics are error-prone. Expressions and pattern matching make that F# allows for stronger, yet still not ideal, mechanics.