Skip to content

Commit

Permalink
Collection functions (#2267)
Browse files Browse the repository at this point in the history
* Removed PartialFunction and Function1 from collection interfaces

* Added asPartialFunction() to Seq, Map and Multimap
  • Loading branch information
danieldietrich authored Jul 27, 2018
1 parent 23b5232 commit ffcacd0
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 391 deletions.
2 changes: 1 addition & 1 deletion vavr/generator/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2519,7 +2519,7 @@ def generateTestClasses(): Unit = {
@$test
public void shouldCreate${func}From${i}Pairs() {
$MapType<Integer, Integer> map = $func(${(1 to i).gen(j => s"$j, ${j*2}")(", ")});
${(1 to i).gen(j => s"assertThat(map.apply($j)).isEqualTo(${j*2});")("\n")}
${(1 to i).gen(j => s"assertThat(map.get($j).get()).isEqualTo(${j*2});")("\n")}
}
"""
})("\n\n")}
Expand Down
330 changes: 165 additions & 165 deletions vavr/src-gen/test/java/io/vavr/APITest.java

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions vavr/src/main/java/io/vavr/collection/IndexedSeq.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,21 @@ static <T> IndexedSeq<T> narrow(IndexedSeq<? extends T> indexedSeq) {
@Override
IndexedSeq<T> asJavaMutable(Consumer<? super java.util.List<T>> action);

@Override
default PartialFunction<Integer, T> asPartialFunction() throws IndexOutOfBoundsException {
return new PartialFunction<Integer, T>() {
private static final long serialVersionUID = 1L;
@Override
public T apply(Integer index) {
return get(index);
}
@Override
public boolean isDefinedAt(Integer index) {
return 0 <= index && index < length();
}
};
}

@Override
<R> IndexedSeq<R> collect(PartialFunction<? super T, ? extends R> partialFunction);

Expand Down Expand Up @@ -177,11 +192,6 @@ default int indexOfSlice(Iterable<? extends T> that, int from) {
@Override
IndexedSeq<T> intersperse(T element);

@Override
default boolean isDefinedAt(Integer index) {
return 0 <= index && index < length();
}

@Override
default T last() {
if (isEmpty()) {
Expand Down
22 changes: 16 additions & 6 deletions vavr/src/main/java/io/vavr/collection/LinearSeq.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,22 @@ static <T> LinearSeq<T> narrow(LinearSeq<? extends T> linearSeq) {
@Override
LinearSeq<T> asJavaMutable(Consumer<? super java.util.List<T>> action);

@Override
default PartialFunction<Integer, T> asPartialFunction() throws IndexOutOfBoundsException {
return new PartialFunction<Integer, T>() {
private static final long serialVersionUID = 1L;
@Override
public T apply(Integer index) {
return get(index);
}
@Override
public boolean isDefinedAt(Integer index) {
// we can't use length() because of infinite long sequences
return 0 <= index && drop(index).nonEmpty();
}
};
}

@Override
<R> LinearSeq<R> collect(PartialFunction<? super T, ? extends R> partialFunction);

Expand Down Expand Up @@ -160,12 +176,6 @@ default int indexWhere(Predicate<? super T> predicate, int from) {
@Override
LinearSeq<T> intersperse(T element);

@Override
default boolean isDefinedAt(Integer index) {
// we can't use length() because of infinite long sequences
return 0 <= index && drop(index).nonEmpty();
}

@Override
default int lastIndexOfSlice(Iterable<? extends T> that, int end) {
Objects.requireNonNull(that, "that is null");
Expand Down
55 changes: 21 additions & 34 deletions vavr/src/main/java/io/vavr/collection/Map.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,13 @@
* <li>{@link #transform(Function)}</li>
* <li>{@link #unzip(BiFunction)}</li>
* <li>{@link #unzip3(BiFunction)}</li>
* <li>{@link #withDefault(Function)}</li>
* <li>{@link #withDefaultValue(Object)}</li>
* </ul>
*
* @param <K> Key type
* @param <V> Value type
* @author Daniel Dietrich, Ruslan Sennov
*/
public interface Map<K, V> extends Traversable<Tuple2<K, V>>, PartialFunction<K, V>, Serializable {
public interface Map<K, V> extends Traversable<Tuple2<K, V>>, Serializable {

long serialVersionUID = 1L;

Expand Down Expand Up @@ -141,9 +139,26 @@ static <K, V> Tuple2<K, V> entry(K key, V value) {
return Tuple.of(key, value);
}

@Override
default V apply(K key) {
return get(key).getOrElseThrow(() -> new NoSuchElementException(String.valueOf(key)));
/**
* Turns this {@code Map} into a {@link PartialFunction} which is defined at a specific index, if this {@code Map}
* contains the given key. When applied to a defined key, the partial function will return
* the value of this {@code Map} that is associated with the key.
*
* @return a new {@link PartialFunction}
* @throws NoSuchElementException when a non-existing key is applied to the partial function
*/
default PartialFunction<K, V> asPartialFunction() throws IndexOutOfBoundsException {
return new PartialFunction<K, V>() {
private static final long serialVersionUID = 1L;
@Override
public V apply(K key) {
return get(key).getOrElseThrow(() -> new NoSuchElementException(String.valueOf(key)));
}
@Override
public boolean isDefinedAt(K key) {
return containsKey(key);
}
};
}

@Override
Expand Down Expand Up @@ -659,29 +674,6 @@ default Iterator<V> valuesIterator() {
return iterator().map(Tuple2::_2);
}

/**
* Turns this map from a partial function into a total function that
* returns a value computed by defaultFunction for all keys
* absent from the map.
*
* @param defaultFunction function to evaluate for all keys not present in the map
* @return a total function from K to T
*/
default Function1<K, V> withDefault(Function<? super K, ? extends V> defaultFunction) {
return k -> get(k).getOrElse(() -> defaultFunction.apply(k));
}

/**
* Turns this map from a partial function into a total function that
* returns defaultValue for all keys absent from the map.
*
* @param defaultValue default value to return for all keys not present in the map
* @return a total function from K to T
*/
default Function1<K, V> withDefaultValue(V defaultValue) {
return k -> get(k).getOrElse(defaultValue);
}

@Override
default <U> Seq<Tuple2<Tuple2<K, V>, U>> zip(Iterable<? extends U> that) {
return zipWith(that, Tuple::of);
Expand Down Expand Up @@ -746,11 +738,6 @@ default <U> Seq<U> zipWithIndex(BiFunction<? super Tuple2<K, V>, ? super Integer
@Override
io.vavr.collection.Iterator<? extends Map<K, V>> grouped(int size);

@Override
default boolean isDefinedAt(K key) {
return containsKey(key);
}

@Override
default boolean isDistinct() {
return true;
Expand Down
34 changes: 23 additions & 11 deletions vavr/src/main/java/io/vavr/collection/Multimap.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
* @param <V> Value type
* @author Ruslan Sennov
*/
public interface Multimap<K, V> extends Traversable<Tuple2<K, V>>, PartialFunction<K, Traversable<V>>, Serializable {
public interface Multimap<K, V> extends Traversable<Tuple2<K, V>>, Serializable {

long serialVersionUID = 1L;

Expand Down Expand Up @@ -154,18 +154,35 @@ static <K, V> Multimap<K, V> narrow(Multimap<? extends K, ? extends V> map) {

// -- non-static API

@Override
default Traversable<V> apply(K key) {
return get(key).getOrElseThrow(NoSuchElementException::new);
}

/**
* Converts this {@code Multimap} to a {@code Map}
*
* @return {@code Map<K, Traversable<V>>}
*/
Map<K, Traversable<V>> asMap();

/**
* Turns this {@code Multimap} into a {@link PartialFunction} which is defined at a specific index, if this {@code Multimap}
* contains the given key. When applied to a defined key, the partial function will return
* the {@link Traversable} of this {@code Multimap} that is associated with the key.
*
* @return a new {@link PartialFunction}
* @throws NoSuchElementException when a non-existing key is applied to the partial function
*/
default PartialFunction<K, Traversable<V>> asPartialFunction() throws IndexOutOfBoundsException {
return new PartialFunction<K, Traversable<V>>() {
private static final long serialVersionUID = 1L;
@Override
public Traversable<V> apply(K key) {
return get(key).getOrElseThrow(NoSuchElementException::new);
}
@Override
public boolean isDefinedAt(K key) {
return containsKey(key);
}
};
}

/**
* Maps this {@code Multimap} to a new {@code Multimap} with different component type by applying a function to its elements.
*
Expand Down Expand Up @@ -318,11 +335,6 @@ default boolean hasDefiniteSize() {
return true;
}

@Override
default boolean isDefinedAt(K key) {
return containsKey(key);
}

@Override
default boolean isDistinct() {
return true;
Expand Down
63 changes: 17 additions & 46 deletions vavr/src/main/java/io/vavr/collection/Seq.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
* <li>{@link #update(int, Object)}</li>
* </ul>
*
* Conversion:
*
* <ul>
* <li>{@link #asPartialFunction}</li>
* </ul>
*
* Filtering:
*
* <ul>
Expand Down Expand Up @@ -106,7 +112,7 @@
* @param <T> Component type
* @author Daniel Dietrich
*/
public interface Seq<T> extends Traversable<T>, PartialFunction<Integer, T>, Serializable {
public interface Seq<T> extends Traversable<T>, Serializable {

long serialVersionUID = 1L;

Expand Down Expand Up @@ -140,19 +146,6 @@ static <T> Seq<T> narrow(Seq<? extends T> seq) {
* @throws NullPointerException if {@code elements} is null
*/
Seq<T> appendAll(Iterable<? extends T> elements);

/**
* A {@code Seq} is a partial function which returns the element at the specified index by calling
* {@linkplain #get(int)}.
*
* @param index an index
* @return the element at the given index
* @throws IndexOutOfBoundsException if this is empty, index &lt; 0 or index &gt;= length()
*/
@Override
default T apply(Integer index) {
return get(index);
}

/**
* Creates an <strong>immutable</strong> {@link java.util.List} view on top of this {@code Seq},
Expand Down Expand Up @@ -205,6 +198,16 @@ default T apply(Integer index) {
@GwtIncompatible
Seq<T> asJavaMutable(Consumer<? super java.util.List<T>> action);

/**
* Turns this {@code Seq} into a {@link PartialFunction} which is defined at a specific index, if this {@code Seq}
* contains at least index + 1 elements. When applied to a defined index, the partial function will return
* the value of this {@code Seq} at the specified index.
*
* @return a new {@link PartialFunction}
* @throws IndexOutOfBoundsException if this is empty, index &lt; 0 or index &gt;= length()
*/
PartialFunction<Integer, T> asPartialFunction() throws IndexOutOfBoundsException;

@Override
<R> Seq<R> collect(PartialFunction<? super T, ? extends R> partialFunction);

Expand Down Expand Up @@ -585,16 +588,6 @@ default Option<Integer> lastIndexWhereOption(Predicate<? super T> predicate, int
return Collections.indexOption(lastIndexWhere(predicate, end));
}

/**
* Turns this sequence into a plain function returning an Option result.
*
* @return a function that takes an index i and returns the value of
* this sequence in a Some if the index is within bounds, otherwise a None.
*/
default Function1<Integer, Option<T>> lift() {
return i -> (i >= 0 && i < length()) ? Option.some(apply(i)) : Option.none();
}

/**
* Returns the index of the last occurrence of the given element before or at a given end index
* or -1 if this does not contain the given element.
Expand Down Expand Up @@ -1275,28 +1268,6 @@ default <U> U foldRight(U zero, BiFunction<? super T, ? super U, ? extends U> f)
@Override
<U> Seq<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? extends U> mapper);

/**
* Turns this sequence from a partial function into a total function that
* returns defaultValue for all indexes that are out of bounds.
*
* @param defaultValue default value to return for out of bound indexes
* @return a total function from index to T
*/
default Function1<Integer, T> withDefaultValue(T defaultValue) {
return i -> (i >= 0 && i < length()) ? apply(i) : defaultValue;
}

/**
* Turns this sequence from a partial function into a total function that
* returns a value computed by defaultFunction for all indexes that are out of bounds.
*
* @param defaultFunction function to evaluate for all out of bounds indexes.
* @return a total function from index to T
*/
default Function1<Integer, T> withDefault(Function<? super Integer, ? extends T> defaultFunction) {
return i -> (i >= 0 && i < length()) ? apply(i) : defaultFunction.apply(i);
}

@Override
default boolean isSequential() {
return true;
Expand Down
16 changes: 1 addition & 15 deletions vavr/src/main/java/io/vavr/collection/Set.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/
package io.vavr.collection;

import io.vavr.Function1;
import io.vavr.PartialFunction;
import io.vavr.Tuple3;
import io.vavr.Tuple2;
Expand Down Expand Up @@ -82,7 +81,7 @@
* @param <T> Component type
* @author Daniel Dietrich, Ruslan Sennov
*/
public interface Set<T> extends Traversable<T>, Function1<T, Boolean>, Serializable {
public interface Set<T> extends Traversable<T>, Serializable {

long serialVersionUID = 1L;

Expand Down Expand Up @@ -116,19 +115,6 @@ static <T> Set<T> narrow(Set<? extends T> set) {
*/
Set<T> addAll(Iterable<? extends T> elements);

/**
* Tests if a given {@code element} is contained in this {@code Set}.
* <p>
* This method is equivalent to {@link #contains(Object)}.
*
* @param element the element to test for membership.
* @return {@code true} if the given {@code element} is contained, {@code false} otherwise.
*/
@Override
default Boolean apply(T element) {
return contains(element);
}

/**
* Calculates the difference between this set and another set.
* <p>
Expand Down
12 changes: 12 additions & 0 deletions vavr/src/test/java/io/vavr/MatchTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package io.vavr;

import io.vavr.collection.List;
import io.vavr.collection.Set;
import io.vavr.control.Either;
import io.vavr.control.Option;
import io.vavr.control.Option.Some;
Expand Down Expand Up @@ -339,6 +340,17 @@ public void shouldDecomposeListWithNonEmptyTail() {
}
*/

// -- Set

@Test
public void shouldDecomposeSet() {
final Set<String> abc = Set("abc");
final Set<String> result = Match(abc).of( // Does not compile: the Java inference engine sees abc as a Function1<String, Boolean> before a Set<String> thus expects result to be of type Boolean
Case($(), () -> abc)
);
assertThat(result).isEqualTo(abc);
}

// -- Validation

@Test
Expand Down
Loading

0 comments on commit ffcacd0

Please sign in to comment.