Use the types Luke : Creating a LazyEither from the types and knowledge

Types can guide you (and trick you) when functional programming in Java

John McClean
4 min readNov 1, 2018

Dysfunctional programming in Java 5 : No Exceptions allowed we presented some code that constructed an Either type lazily. It looked like this :-

In this article we’ll break down what is going on in that (⏫⏫) code snippet — we could alternatively expand it out into something like this (⏬⏬)

Photo by Simon Zhu on Unsplash

Let’s look at how we can use the types to figure out how to construct a value declaration like this and what it really means (which in turn means we fully understand the more syntactically sweet version at the very top).

Creating a LazyEither from an eager Either

Let’s start with the method signature of loadContents(), it returns an Either type. That could be a LazyEither (since LazyEither is a sub-class of Either) or a standard eager Either.

Either way (ha!) it is straightforward to get a LazyEither instance from an eager Either, we can call the fromEither factory on LazyEither

LazyEither.fromEither(loadContents());

And it looks like we’re done, the result of this call will match the require type signature perfectly!

LazyEither<IOException,String>

which is also an instance of


Either<IOException,String>

But we’re not done! (😯). Because loadContents returns an Either type, that may have created eagerly. In fact if we look at the code for the implementations of loadContents in Dysfunctional programming in Java 5 : No Exceptions allowed it has been created eagerly!

This means if we simply convert the result of loadContents () to a LazyEither, the method loadContents itself will still be executed eagerly and not lazily! Without changing the implementation of loadContents we want to make the call to loadContents lazy — and we can do this with Eval

If we want caching / memoization so we only loadContents once we can use Eval.later

Eval.later(this::loadContents);

This will give us back a value with the following signature

Eval<Either<IOException,String>> contents;

contents has the following charactertistics

  1. Is lazily populated on first access ✅
  2. Is only populated once due to Memoization ✅
  3. Does not throw Exceptions if the I/O data is unavailable ✅
  4. Represents the fact the contents data maybe present or absent ✅
  5. IOException is captured if one is thrown during loading ✅
  6. 👹Generics hell!👹

What we’d like to do, is condense that down into

LazyEither<IOException,String> contents;

Luckily enough there is a factory method on LazyEither which matches this type in its return signature : fromLazy

We can match the input parameter with a little refactoring of our previous two attempts.

LazyEither<IOException,String> attempt1 = LazyEither.fromEither( loadContents() );Eval<Either<IOException,String>> attempt2 = Eval.later( this::loadContents );

We can create a LazyEither embedded inside an Eval

Eval<LazyEither<IOException,String>> attempt3 = Eval.later( ()-> LazyEither.fromEither( loadContents() ) );

We can use some static imports

import static cyclops.control.Eval.later;
import static cyclops.control.LazyEither.fromLazy;
fromLazy(later(()->LazyEither.fromEither(loadContents())));

Which matches the required signature and Laziness semantics of our contents field

So what did we do?

  • We converted a lazy, caching Eval instance that loadsContents just once
  • We made sure that Eval contained a LazyEither type which either contained the result of loading the contents (a String) or the Exception created when loading contents failed
  • Then we constructed a LazyEither instance from that lazy Eval instance — so that externally we have an Either that represents the result of loadContents, but only triggers loadContents once, when absolutely neccessary (on a terminal operation on the Either).

In practice : this is much cleaner

And now you know what it does and how it does it!

--

--

John McClean

Architecture @ Verizon Media. Maintainer of Cyclops. Twitter @johnmcclean_ie