Skip to content

Commit 3a863a1

Browse files
committed
New feature: Either.cond
1 parent b41ffda commit 3a863a1

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

vavr/src/main/java/io/vavr/control/Either.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,101 @@ static <L, R> Either<L, R> narrow(Either<? extends L, ? extends R> either) {
111111
return (Either<L, R>) either;
112112
}
113113

114+
/**
115+
* Decides which {@code Either<L, R>} to return, depending on the test value -
116+
* if it's true, the result will be a {@link Either.Right},
117+
* if it's false - the result will be a {@link Either.Left}
118+
*
119+
* @param test A {@code Boolean} value to evaluate
120+
* @param right A {@code Supplier<? extends R>} supplier of right value, called if test is true
121+
* @param left A {@code Supplier<? extends L>} supplier of left value, called if test is false
122+
* @param <L> Type of left value
123+
* @param <R> Type of right value
124+
*
125+
* @return {@code Either<L, R>} with right or left value, depending on the test condition evaluation
126+
*
127+
* @throws NullPointerException if any of the arguments is null
128+
* @author Adam Kopeć
129+
*/
130+
static <L, R> Either<L, R> cond(Boolean test, Supplier<? extends R> right, Supplier<? extends L> left) {
131+
Objects.requireNonNull(test, "test is null");
132+
Objects.requireNonNull(right, "right is null");
133+
Objects.requireNonNull(left, "left is null");
134+
135+
return test ? right(right.get()) : left(left.get());
136+
}
137+
138+
/**
139+
* Decides which {@code Either<L, R>} to return, depending on the test value -
140+
* if it's true, the result will be a {@link Either.Right},
141+
* if it's false - the result will be a {@link Either.Left}
142+
*
143+
* @param test A {@code Boolean} value to evaluate
144+
* @param right A n{@code R} right value, returned if test is true
145+
* @param left A {@code L} left value, returned if test is false
146+
* @param <L> Type of left value
147+
* @param <R> Type of right value
148+
*
149+
* @return {@code Either<L, R>} with right or left value, depending on the test condition evaluation
150+
*
151+
* @throws NullPointerException if any of the arguments is null
152+
* @author Adam Kopeć
153+
*/
154+
static <L, R> Either<L, R> cond(Boolean test, R right, L left) {
155+
Objects.requireNonNull(test, "test is null");
156+
Objects.requireNonNull(right, "right is null");
157+
Objects.requireNonNull(left, "left is null");
158+
159+
return cond(test, () -> right, () -> left);
160+
}
161+
162+
/**
163+
* Decides which {@code Either<L, R>} to return, depending on the test value -
164+
* if it's true, the result will be a {@link Either.Right},
165+
* if it's false - the result will be a {@link Either.Left}
166+
*
167+
* @param test A {@code Boolean} value to evaluate
168+
* @param right A {@code Supplier<? extends R>} supplier of right value, called if test is true
169+
* @param left A {@code L} left value, returned if test is false
170+
* @param <L> Type of left value
171+
* @param <R> Type of right value
172+
*
173+
* @return {@code Either<L, R>} with right or left value, depending on the test condition evaluation
174+
*
175+
* @throws NullPointerException if any of the arguments is null
176+
* @author Adam Kopeć
177+
*/
178+
static <L, R> Either<L, R> cond(Boolean test, Supplier<? extends R> right, L left) {
179+
Objects.requireNonNull(test, "test is null");
180+
Objects.requireNonNull(right, "right is null");
181+
Objects.requireNonNull(left, "left is null");
182+
183+
return cond(test, right, () -> left);
184+
}
185+
186+
/**
187+
* Decides which {@code Either<L, R>} to return, depending on the test value -
188+
* if it's true, the result will be a {@link Either.Right},
189+
* if it's false - the result will be a {@link Either.Left}
190+
*
191+
* @param test A {@code Boolean} value to evaluate
192+
* @param right A {@code R} right value, returned if test is true
193+
* @param left A {@code Supplier<? extends L>} supplier of left value, called if test is false
194+
* @param <L> Type of left value
195+
* @param <R> Type of right value
196+
*
197+
* @return {@code Either<L, R>} with right or left value, depending on the test condition evaluation
198+
*
199+
* @throws NullPointerException if any of the arguments is null
200+
* @author Adam Kopeć
201+
*/
202+
static <L, R> Either<L, R> cond(Boolean test, R right, Supplier<? extends L> left) {
203+
Objects.requireNonNull(test, "test is null");
204+
Objects.requireNonNull(right, "right is null");
205+
Objects.requireNonNull(left, "left is null");
206+
207+
return cond(test, () -> right, left);
208+
}
114209
/**
115210
* Returns the left value.
116211
*

vavr/src/test/java/io/vavr/control/EitherTest.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import static io.vavr.API.Right;
3333
import static org.assertj.core.api.Assertions.assertThatThrownBy;
3434
import static org.junit.jupiter.api.Assertions.assertThrows;
35+
import static org.junit.jupiter.api.Assertions.fail;
3536

3637
@SuppressWarnings("deprecation")
3738
public class EitherTest extends AbstractValueTest {
@@ -333,6 +334,93 @@ public void shouldNarrowLeftEither() {
333334
}
334335
}
335336

337+
@Nested
338+
public class CondTests {
339+
340+
@Test
341+
public void shouldReturnRightIfTestTrue() {
342+
Either<String, Integer> either = Either.cond(true, () -> 21, () -> "vavr");
343+
assertThat(either).isEqualTo(Either.right(21));
344+
}
345+
346+
@Test
347+
public void shouldReturnLeftIfTestFalse() {
348+
Either<String, Integer> either = Either.cond(false, () -> 21, () -> "vavr");
349+
assertThat(either).isEqualTo(Either.left("vavr"));
350+
}
351+
352+
@Test
353+
public void shouldNotEvaluateRightSupplierOnFalse() {
354+
Either<String, Integer> either = Either.cond(false, () -> {
355+
fail("Should not be called");
356+
return 21;
357+
}, () -> "vavr");
358+
assertThat(either).isEqualTo(Either.left("vavr"));
359+
}
360+
361+
@Test
362+
public void shouldNotEvaluateLeftSupplierOnTrue() {
363+
Either<String, Integer> either = Either.cond(true, () -> 21, () -> {
364+
fail("Should not be called");
365+
return "vavr";
366+
});
367+
assertThat(either).isEqualTo(Either.right(21));
368+
}
369+
private class Animal {
370+
String name;
371+
Animal(String name) { this.name = name; }
372+
373+
@Override
374+
public boolean equals(Object o) {
375+
if (this == o) return true;
376+
if (!(o instanceof Animal)) return false;
377+
Animal other = (Animal) o;
378+
return name.equals(other.name);
379+
}
380+
381+
@Override
382+
public int hashCode() {
383+
return name.hashCode();
384+
}
385+
}
386+
387+
private class Dog extends Animal {
388+
Dog(String name) { super(name); }
389+
}
390+
391+
private class Cat extends Animal {
392+
Cat(String name) { super(name); }
393+
}
394+
395+
@Test
396+
public void shouldBeFineWithCovariantLeft() {
397+
Either<Animal, Integer> either = Either.cond(false, () -> 21, () -> new Cat("vavr"));
398+
assertThat(either).isEqualTo(Either.left(new Cat("vavr")));
399+
}
400+
401+
@Test
402+
public void shouldBeFineWithCovariantRight() {
403+
Either<String, Animal> either = Either.cond(true, () -> new Dog("vavr"), () -> "vavr");
404+
assertThat(either).isEqualTo(Either.right(new Dog("vavr")));
405+
}
406+
407+
@Test
408+
public void shouldMakeTheSameDecisionNoMatterHowItsCalled() {
409+
Either<String, Integer> e1 = Either.cond(true, () -> 21, () -> "vavr");
410+
Either<String, Integer> e3 = Either.cond(true, 21, "vavr");
411+
Either<String, Integer> e2 = Either.cond(true, 21, () -> "vavr");
412+
Either<String, Integer> e4 = Either.cond(true, () -> 21, "vavr");
413+
414+
Either<String, Integer> e5 = Either.cond(false, () -> 21, () -> "vavr");
415+
Either<String, Integer> e6 = Either.cond(false, 21, "vavr");
416+
Either<String, Integer> e7 = Either.cond(false, 21, () -> "vavr");
417+
Either<String, Integer> e8 = Either.cond(false, () -> 21, "vavr");
418+
419+
assertThat(List.of(e1, e2, e3, e4)).allMatch(e -> e.equals(Either.right(21)));
420+
assertThat(List.of(e5, e6, e7, e8)).allMatch(e -> e.equals(Either.left("vavr")));
421+
}
422+
}
423+
336424
@Nested
337425
public class OrElseTests {
338426

0 commit comments

Comments
 (0)