-
-
Notifications
You must be signed in to change notification settings - Fork 639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Breaking changes in 3.0.0 #1493
Comments
Consideration removing Kind1/Kind2 from core libJavaslang claims to be a functional programming library. The algebraic computation layer is important for some of our users. So I ask the question if we can remove Kind1/Kind2 from the Status QuoCurrently public interface Kind1<TYPE extends Kind1<TYPE, ?>, T> {
}
public interface Kind2<TYPE extends Kind2<TYPE, ?, ?>, T1, T2> {
} These interfaces tag types (e.g.
The List interface currently looks like this: public interface List<T> extends Kind1<List<?>, T>, LinearSeq<T>, Stack<T> {
...
} In public interface Monad<M extends Kind1<M, ?>, T> extends Functor<T> {
<U> Monad<M, U> flatMap(Function<? super T, ? extends Monad<M, U>> mapper);
@Override
<U> Monad<M, U> map(Function<? super T, ? extends U> mapper);
Kind1<M, T> narrow();
} The narrow function is the important part. It allows us to transform the Monad type back to real object type, which is needed to implement Monad.flatMap(). Example: List static <T> Monad<List<?>, T> of(List<T> list) {
return new Monad<List<?>, T>() {
@Override
public <U> Monad<List<?>, U> flatMap(Function<? super T, ? extends Monad<List<?>, U>> f) {
return Monad.of(list.flatMap((T t) -> (List<U>) f.apply(t).narrow()));
}
@Override
public <U> Monad<List<?>, U> map(Function<? super T, ? extends U> f) {
return Monad.of(list.map(f));
}
@Override
public List<T> narrow() {
return list;
}
};
} Trying to remove Kind1Our goal is to remove public interface List<T> extends LinearSeq<T>, Stack<T> {
...
} The public interface Monad<M, T> extends Functor<T> {
<U> Monad<M, U> flatMap(Function<? super T, ? extends Monad<M, U>> mapper);
@Override
<U> Monad<M, U> map(Function<? super T, ? extends U> mapper);
M narrow();
} The List Monad implementation is then constructed as follow: static <T> Monad<List<?>, T> of(List<T> list) {
return new Monad<List<?>, T>() {
@Override
public <U> Monad<List<?>, U> flatMap(Function<? super T, ? extends Monad<List<?>, U>> f) {
return Monad.of(list.flatMap((T t) -> (List<U>) f.apply(t).narrow()));
}
@Override
public <U> Monad<List<?>, U> map(Function<? super T, ? extends U> f) {
return Monad.of(list.map(f));
}
@Override
public List<T> narrow() {
return list;
}
};
} The case Removing Monad.narrow() but keeping Kind1This leads to: public interface Monad<M extends Kind1<M, ?>, T> extends Functor<T> {
<U> Monad<M, U> flatMap(Function<? super T, ? extends Monad<M, U>> mapper);
@Override
<U> Monad<M, U> map(Function<? super T, ? extends U> mapper);
} The List Monad implementation can be made safe by making use of intersection types. We can just add the static <T, M extends List<?> & Kind1<M, ?>> Monad<M, T> of(List<T> list) {
return new Monad<M, T>() {
@Override
public <U> Monad<M, U> flatMap(Function<? super T, ? extends Monad<M, U>> f) {
return Monad.of(list.flatMap((T t) -> (List<U>) f.apply(t)));
}
@Override
public <U> Monad<M, U> map(Function<? super T, ? extends U> f) {
return Monad.of(list.map(f));
}
};
} Now But we loose a common Monad.narrow() in favor of removing Kind1 (and Kind2) from the Having said this, we will stay with Kind1, Kind2 in the core lib and also keep javaslang-pure. See also |
CharSeq
|
Memoized might be worth keeping public as I actually had a use case, where I defined a new |
I ran into a situation where I need the
And in this issue I see this point, but it striked out but not completed. P.S. |
@valery1707 Do you have a suggestion what an 'empty' lazily evaluated value could be? I understand declaring a value as 'lazy' means, that there is a value but the evaluation is deferred to the moment the value is needed. Especially we currently can rely on the fact that such a value is always present. If we allow Lazy to be also empty (read: undefined), it is more like a LazyOption. We could do the same for all other Vavr types, e.g. LazyTry, LazyEither, LazyXyz... Maybe Lazy should be more like a lazy view or decorator for existing types. E.g. instead of Lazy<T> we might want to have Lazy<Option<T>>. |
Is there anything a a |
@danieldietrich I understand your point of view. |
@valery1707 nevertheless, your point is valid. I will think about Lazy (filter) for 1.0.0 |
@nfekete I think Lazy.filter cannot be expressed in the way that the result is lazy { // variant 1: still has a sub-optimal filter
Lazy<Option<T>> lazyOption = Lazy.of(() -> Option.of(...));
Option<Option<T>> filtered = lazyOption.filter(predicate);
}
{ // variant 2: not lazy anymore, also not what we want to express
Option<Lazy<T>> optLazy = Option.of(Lazy.of(() -> ...));
Option<Lazy<T>> filtered = optLazy.filter(predicate);
} |
But we can this: Lazy<Option<T>> lazyOption = Lazy.of(() -> Option.of(...));
Lazy<Option<T>> filtered = lazyOption.map(o -> o.filter(predicate)); And |
@valery1707 thx for clarification! That's a really nice solution! We should |
Breaking Changes
This is just a List of ideas. We will create separate PRs (and maybe also issues).
Remove unnecessary ballast
remove Promise (see Add factory method that allows to resolve/reject a Future #1529) - (update: it will most probably stay for we will have new Future API for promises)rethink or remove run() for Match (see Add Match.run(cases) syntax #1216, Wish for API.run((r) -> {}) method #1218)- I don't want to put too much additional effort into the Match API because Java will have native pattern matching in near future.this instanceof Option
)Widen Validation's- moved to Add more syntactic sugar to Validation #1565List<E>
toList<? extends E>
in many cases.Validation<List<E>, T>
toValidation<Seq<E>, T>
and internally useVector
instead ofList
.remove AbstractIterator and do hasNext()-checks manually in next(). (see this comment). Problem Iterator is an interface and we need to override toString(). Possible solution: make Iterator an abstract class. Better solution: Keep it as interface and do not provide toString() for Iterator - instead use hasNext() to check if it is empty.Other breaking changes
int
instead oflong
consider renaming CheckedFunction0..8 to ThrowingFunction0..8 (one more think to not think about from the user perspective - which one throws, the checked or the unchecked function?)bring (creational method names of, ofAll) and (conversion names fromXxx, toXxx) into line, e.g.should it beHashMap.ofEntries(java.util.Map.Entry...)
(current state) orHashMap.fromEntries(java.util.Map.Entry...)
?should it beTuple.fromEntry(java.util.Map.Entry)
(Add Tuple.fromEntry(java.util.Map.Entry) factory method and Tuple2.toEntry() conversion method #1545) orTuple.ofEntry(java.util.Map.Entry)
should it beValidation.fromEither(Either)
(current state) orValidation.ofEither(Either)
should it beOption.fromOptional
orOption.ofOptional(Optional)
(current state)...Hint: we use- see (Collection) factory methods #2125fromXxx()
in the presence of conversion, see this commentIt seems odd to me that Pattern0 'extracts itself'. We should consider that Pattern0.unapply() returns Option<Void>. This would be formally correct because Pattern0 extracts zero parts.static fill() methods currently take a Supplier. They should take an object instead of a supplier- will be done in Add static fill(int, T) methods #2182replace- will be done in Let Future.andThen take a Function instead of a Consumer #2183Future.andThen(Consumer<? super Try<T>> action)
withandThen(Function<? super Try<T>, ? extends U> action)
(see Scala's Future.andThen(), see also this deprecation discussion)The text was updated successfully, but these errors were encountered: