HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

An Either Monad in Java

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
eitherjavamonad

Problem

Interested in a review of this code, in particular the (hopefully monadic) bind. I actually put this to good use. It was a nice complement to Guava's Optional, and shorter than:


Optional.fromNullable(x).or(y);

And I threw in a bind method, which I think lifts it up into monad space.

One question I wasn't sure of the the semantics of multiple calls. Should I carry along the original default value, or does each new value become the default? So in psuedo code, should


Either.with("A").or("B").or(null)

result in "A" (the original default) or "B"? I thought "B" made more sense.

I'm interested in if I got the monad signature & semantics right.

public class Either {

    private final A value;

    /**
     * constructor sets the default & value the same
     * @param defaultValue
     */
    Either(A value) {
        if (value == null) {
            throw new IllegalArgumentException("Either cannot be null");
        }
        this.value = value;
    }

    /**
     * constructor sets the default & value the same
     * @param defaultValue
     */
    Either(A defaultValue, A value) {
        this.value = (value == null) ? defaultValue : value;
    }

    /**
     * the unit method lifts the value into the monadic space
     * 
     * @param value
     * @return an either with the value as default
     */
    public static  Either with(A value) {
        return new Either(value);
    }

    /**
     * create a new either using the previous default
     * 
     * @param value
     * @return
     */
    public Either or(A value) {
        return new Either(this.value, value);
    }

    /**
     * @return the value, or the default
     */
    public A get() {
        return value;
    }

    /**
     * completes this class as a monad
     * 
     * @param f
     * @return an either of the new type
     */
    public  Either bind(Function> f) {
        return f.apply(value);
    }
}


And here are the unit tests for bind (and sample usage):

```
static c

Solution

I have a nit-pick with the logic in your Either.or(A) method. You have:

public Either or(A value) {
    return new Either(this.value, value);
}


but, since Either is immutable (oh, should Either be a final class? ... I think so...), it makes sense that the or method can return the exact instance if it is valid.... why does it have to create a new instance each time? In a stream that can create a lot of GC churn....

I would write that method:

public Either or(A value) {
    return value == null ? this : new Either(value);
}


I know that essentially duplicates the constructor, but, doing it this way avoids the constructor in (hopefully) many places entirely.

This leads on to your question:


One question I wasn't sure of the the semantics of multiple calls.
Should I carry along the original default value, or does each new
value become the default? So in psuedo code, should

Either.with("A").or("B").or(null)




result in "A" (the original default) or "B"? I thought "B" made more
sense.

If the or(A) method does not need to construct a new instance, then it makes sense to me that the semantics should return "A", since that allows skipping new instances for "B" and null.

Code Snippets

public Either<A> or(A value) {
    return new Either<A>(this.value, value);
}
public Either<A> or(A value) {
    return value == null ? this : new Either<A>(value);
}
Either.with("A").or("B").or(null)

Context

StackExchange Code Review Q#42702, answer score: 8

Revisions (0)

No revisions yet.