Deriving a Kotlin ''Try'' Type
Time to dive into a Try or two.
Join the DZone community and get the full member experience.Join For Free
Functional programming languages like Scala often have a type called "Try" to hold the result of a computation if successful or to capture an exception on failure.
This is an incredibly useful type, allowing a caller to pointedly control how to handle an exceptional scenario. In this post, I will try and create such a type from scratch.
As an example, I will be using the scenario from Daniel Westheide's excellent introduction to the Try type in Scala
So my objective is to call a remote URL and return the content as a string. A few things can go wrong:
- The URL can be badly formed
- The URL may be wrong and may not have anything to retrieve content from
Let's start with the first one, the URL being badly formed, an API call using the "Try" type would look something like this:
Here a URL is being parsed and the result is a valid URL or an exception. So a Try type that can implement this much, would look something like this:
"Try" type has two sub types - A "Success" wrapping a successful result and a "Failure" capturing an exception from the call.
With the two subtypes in place, let's extend the use of the Try type:
If I were to call using a badly formatted URL like above with a wrong scheme "htt" instead of "http", should result in a failure. So let's implement the "isFailure" and "isSuccess" behavior:
That works nicely, so now that a URL is available, hopefully valid, let's get some content from the URL:
which means that our "Try" type should have a "get()" method to retrieve the result if successful and can be implemented like this:
The Success path simply returns the result and the Failure path propagates the wrapped exception.
Let's take it a small step forward. Given a URL, say you want to return the host of the URL
While this works, the problem with the approach is that the "get()" call for an invalid URL would result in an exception if the URL is not valid to start with, so a better approach is to retrieve the host name only if the URL is valid. Traditionally this is done using a "map" operator and a usage looks like this:
So let's add in a "map" operator to the "Try" type:
and it behaves as expected.
Along the lines of "map" operation, now let's get back to the original scenario of validating the URL and then attempting to get the content. Now the call to get content can also fail, so you would want that to be wrapped with a Try type also.
The two calls need to be chained together, and "map" operation may appear to be the right operator to use:
If you look at the response type now, it does not really line up, it is a "Try<Try<String>>" and not a "Try<String>", this is exactly what a flatMap operation does. It takes a valid URL and returns just the inner wrapped result. A test using it would look like this:
So how can "flatMap" be implemented? With a fairly simple code that looks like this:
One more small feature, given that Try type has two subtypes is to deconstruct the contents when required:
This assumes that the user knows the subtypes which may be an okay assumption to make for this type.
A type like "Try" is incredibly useful in capturing a result cleanly or with exception and provides a neat alternative to using a normal try..catch block. Here I showed a way to write such a type from scratch, however, this may be overkill, a better way to get such a type is to simply use an excellent library like vavr which has the Try type already built-in. I feel it is instructive to create such a type from scratch though.
Here is the code in my GitHub repository - https://github.com/bijukunjummen/fp-experiment-kotlin/blob/master/src/main/kotlin/sample/adt/Try.kt
Published at DZone with permission of Biju Kunjummen, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.