You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/04/06 16:23:43 UTC

[isis] branch master updated: ISIS-2877: converts Either to an interface

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new e3ce23efcb ISIS-2877: converts Either<L, R> to an interface
e3ce23efcb is described below

commit e3ce23efcb79c6f068f7780426b1d62822c7ebfb
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Apr 6 18:23:32 2022 +0200

    ISIS-2877: converts Either<L, R> to an interface
    
    - and adds type composition support
---
 .../applib/value/semantics/ValueDecomposition.java |  27 ++-
 .../org/apache/isis/commons/functional/Either.java | 226 +++++++++++++++------
 2 files changed, 183 insertions(+), 70 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueDecomposition.java b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueDecomposition.java
index 891855fce5..44194e5c31 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueDecomposition.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueDecomposition.java
@@ -18,25 +18,38 @@
  */
 package org.apache.isis.applib.value.semantics;
 
+import java.io.Serializable;
+
 import org.apache.isis.applib.util.schema.CommonDtoUtils;
 import org.apache.isis.commons.functional.Either;
+import org.apache.isis.commons.functional.Either.HasEither;
 import org.apache.isis.schema.common.v2.TypedTupleDto;
 import org.apache.isis.schema.common.v2.ValueType;
 import org.apache.isis.schema.common.v2.ValueWithTypeDto;
 
-public final class ValueDecomposition extends Either<ValueWithTypeDto, TypedTupleDto> {
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+
+@RequiredArgsConstructor(access=AccessLevel.PROTECTED)
+@ToString @EqualsAndHashCode
+public final class ValueDecomposition
+implements
+    HasEither<ValueWithTypeDto, TypedTupleDto>,
+    Serializable {
     private static final long serialVersionUID = 1L;
 
+    @Getter
+    private final Either<ValueWithTypeDto, TypedTupleDto> either;
+
     public static ValueDecomposition ofFundamental(final ValueWithTypeDto valueWithTypeDto) {
-        return new ValueDecomposition(valueWithTypeDto, null);
+        return new ValueDecomposition(Either.left(valueWithTypeDto));
     }
 
     public static ValueDecomposition ofComposite(final TypedTupleDto typedTupleDto) {
-        return new ValueDecomposition(null, typedTupleDto);
-    }
-
-    private ValueDecomposition(final ValueWithTypeDto left, final TypedTupleDto right) {
-        super(left, right);
+        return new ValueDecomposition(Either.right(typedTupleDto));
     }
 
     // used by RO-Viewer to render values
diff --git a/commons/src/main/java/org/apache/isis/commons/functional/Either.java b/commons/src/main/java/org/apache/isis/commons/functional/Either.java
index 964586764a..6c9a88c7ae 100644
--- a/commons/src/main/java/org/apache/isis/commons/functional/Either.java
+++ b/commons/src/main/java/org/apache/isis/commons/functional/Either.java
@@ -25,10 +25,8 @@ import java.util.function.Consumer;
 import java.util.function.Function;
 
 import lombok.AccessLevel;
-import lombok.EqualsAndHashCode;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
-import lombok.ToString;
 
 /**
  * The {@link Either} type represents a value of one of two possible types (a disjoint union),
@@ -39,98 +37,200 @@ import lombok.ToString;
  *
  * @since 2.0 {@index}
  */
-@RequiredArgsConstructor(access=AccessLevel.PROTECTED)
-@ToString @EqualsAndHashCode
-public class Either<L, R> implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    private final L left;
-    private final R right;
+public interface Either<L, R>  {
 
     // -- FACTORIES
 
     public static <L, R> Either<L, R> left(final @NonNull L left) {
-        return new Either<>(left, null);
+        return new Left<>(left);
     }
 
     public static <L, R> Either<L, R> right(final @NonNull R right) {
-        return new Either<>(null, right);
+        return new Right<>(right);
     }
 
     // -- ACCESSORS
 
-    public final Optional<L> left() {
-        return Optional.ofNullable(left);
-    }
+    Optional<L> left();
+    Optional<R> right();
 
-    public final Optional<R> right() {
-        return Optional.ofNullable(right);
-    }
-
-    public final L leftIfAny() {
-        return left;
-    }
-
-    public final R rightIfAny() {
-        return right;
-    }
+    L leftIfAny();
+    R rightIfAny();
 
     // -- PREDICATES
 
-    public final boolean isLeft() {
-        return left!=null;
-    }
-
-    public final  boolean isRight() {
-        return right!=null;
-    }
+    boolean isLeft();
+    boolean isRight();
 
     // -- MAPPING
 
-    public final <T> Either<T, R> mapLeft(final @NonNull Function<L, T> leftMapper){
-        return isLeft()
-                ? Either.left(leftMapper.apply(left))
-                : Either.right(right);
-    }
-
-    public final <T> Either<L, T> mapRight(final @NonNull Function<R, T> rightMapper){
-        return isLeft()
-                ? Either.left(left)
-                : Either.right(rightMapper.apply(right));
-    }
+    <T> Either<T, R> mapLeft(final @NonNull Function<L, T> leftMapper);
+    <T> Either<L, T> mapRight(final @NonNull Function<R, T> rightMapper);
 
-    public final <X, Y> Either<X, Y> map(
+    <X, Y> Either<X, Y> map(
             final @NonNull Function<L, X> leftMapper,
-            final @NonNull Function<R, Y> rightMapper){
-        return isLeft()
-                ? left(leftMapper.apply(left))
-                : right(rightMapper.apply(right));
-    }
+            final @NonNull Function<R, Y> rightMapper);
 
     // -- FOLDING
 
-    public final <T> T fold(final @NonNull BiFunction<L, R, T> biMapper){
-        return biMapper.apply(left, right);
-    }
+    <T> T fold(@NonNull BiFunction<L, R, T> biMapper);
 
-    public final <T> T fold(
-            final @NonNull Function<L, T> leftMapper,
-            final @NonNull Function<R, T> rightMapper){
-        return isLeft()
-                ? leftMapper.apply(left)
-                : rightMapper.apply(right);
-    }
+    <T> T fold(
+            @NonNull Function<L, T> leftMapper,
+            @NonNull Function<R, T> rightMapper);
 
     // -- TERMINALS
 
-    public final void accept(final Consumer<L> leftConsumer, final Consumer<R> rightConsumer) {
-        if(isLeft()) {
+    void accept(
+            @NonNull Consumer<L> leftConsumer,
+            @NonNull Consumer<R> rightConsumer);
+
+    // -- LEFT
+
+    @lombok.Value
+    @RequiredArgsConstructor(access=AccessLevel.PROTECTED)
+    static final class Left<L, R> implements Either<L, R>, Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private final L left;
+
+        @Override public Optional<L> left() { return Optional.ofNullable(left); }
+        @Override public Optional<R> right() { return Optional.empty(); }
+
+        @Override public L leftIfAny() { return left; }
+        @Override public R rightIfAny() { return null; }
+
+        @Override public final boolean isLeft() { return true; }
+        @Override public final boolean isRight() { return false; }
+
+        @Override public final <T> Either<T, R> mapLeft(final @NonNull Function<L, T> leftMapper){
+            return Either.left(leftMapper.apply(left)); }
+        @Override public final <T> Either<L, T> mapRight(final @NonNull Function<R, T> rightMapper){
+            return Either.left(left); }
+
+        @Override
+        public final <X, Y> Either<X, Y> map(
+                final @NonNull Function<L, X> leftMapper,
+                final @NonNull Function<R, Y> rightMapper){
+            return Either.left(leftMapper.apply(left));
+        }
+
+        @Override
+        public final <T> T fold(final @NonNull BiFunction<L, R, T> biMapper){
+            return biMapper.apply(left, null);
+        }
+
+        @Override
+        public final <T> T fold(
+                final @NonNull Function<L, T> leftMapper,
+                final @NonNull Function<R, T> rightMapper){
+            return leftMapper.apply(left);
+        }
+
+        @Override
+        public final void accept(
+                final @NonNull Consumer<L> leftConsumer,
+                final @NonNull Consumer<R> rightConsumer) {
             leftConsumer.accept(left);
-        } else {
+        }
+
+    }
+
+    // -- RIGHT
+
+    @lombok.Value
+    @RequiredArgsConstructor(access=AccessLevel.PROTECTED)
+    static final class Right<L, R> implements Either<L, R>, Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private final R right;
+
+        @Override public Optional<L> left() { return Optional.empty(); }
+        @Override public Optional<R> right() { return Optional.ofNullable(right); }
+
+        @Override public L leftIfAny() { return null; }
+        @Override public R rightIfAny() { return right; }
+
+        @Override public final boolean isLeft() { return false; }
+        @Override public final boolean isRight() { return true; }
+
+        @Override public final <T> Either<T, R> mapLeft(final @NonNull Function<L, T> leftMapper){
+            return Either.right(right);
+        }
+        @Override public final <T> Either<L, T> mapRight(final @NonNull Function<R, T> rightMapper){
+            return Either.right(rightMapper.apply(right));
+        }
+
+        @Override
+        public final <X, Y> Either<X, Y> map(
+                final @NonNull Function<L, X> leftMapper,
+                final @NonNull Function<R, Y> rightMapper){
+            return Either.right(rightMapper.apply(right));
+        }
+
+        @Override
+        public final <T> T fold(final @NonNull BiFunction<L, R, T> biMapper){
+            return biMapper.apply(null, right);
+        }
+
+        @Override
+        public final <T> T fold(
+                final @NonNull Function<L, T> leftMapper,
+                final @NonNull Function<R, T> rightMapper){
+            return rightMapper.apply(right);
+        }
+
+        @Override
+        public final void accept(
+                final @NonNull Consumer<L> leftConsumer,
+                final @NonNull Consumer<R> rightConsumer) {
             rightConsumer.accept(right);
         }
+
     }
 
+    // -- TYPE COMPOSITION
+
+    public static interface HasEither<L, R> extends Either<L, R> {
+
+        Either<L, R> getEither();
+
+        @Override default Optional<L> left() { return getEither().left(); }
+        @Override default Optional<R> right() { return getEither().right(); }
+
+        @Override default L leftIfAny() { return getEither().leftIfAny(); }
+        @Override default R rightIfAny() { return getEither().rightIfAny(); }
+
+        @Override default boolean isLeft() { return getEither().isLeft(); }
+        @Override default boolean isRight() { return getEither().isRight(); }
+
+        @Override default <T> Either<T, R> mapLeft(final @NonNull Function<L, T> leftMapper){
+            return getEither().mapLeft(leftMapper); }
+        @Override default <T> Either<L, T> mapRight(final @NonNull Function<R, T> rightMapper){
+            return getEither().mapRight(rightMapper); }
+
+        @Override default <X, Y> Either<X, Y> map(
+                final @NonNull Function<L, X> leftMapper,
+                final @NonNull Function<R, Y> rightMapper){
+            return getEither().map(leftMapper, rightMapper);
+        }
+
+        @Override default <T> T fold(final @NonNull BiFunction<L, R, T> biMapper){
+            return getEither().fold(biMapper);
+        }
+
+        @Override default <T> T fold(
+                final @NonNull Function<L, T> leftMapper,
+                final @NonNull Function<R, T> rightMapper){
+            return getEither().fold(leftMapper, rightMapper);
+        }
+
+        @Override  default void accept(
+                final @NonNull Consumer<L> leftConsumer,
+                final @NonNull Consumer<R> rightConsumer) {
+            getEither().accept(leftConsumer, rightConsumer);
+        }
+
+    }
 
 }