8 ms·
No worries in Java (and I bet in C#) in works no problemo: public <T extends Collection<Integer>> T process(T collectionOfInteger) { return collectionO
by p2t2p 6y ago
No worries in Java (and I bet in C#) in works no problemo:
public <T extends Collection<Integer>> T process(T collectionOfInteger) {
return collectionOfInteger;
}
And basically your T will be as wide as the interface/class it extends in the generic parameter.
I guess the most Java way to do that would be using Iterable:
public <Z, T extends Iterable<Z>> T process(T iterable) {
return iterable;
}
- p2t2p 6y agoI can turn any collection to list like that: public <Z, T extends Collection<Z>> List<Z> process(T collectionOfInteger) { return collectionOfInteger.stream() .collect(toList()); }
- deleted 6y ago[deleted]
- mrkeen 6y agoGreat! These are the three implementations I want to hide behind a single abstraction: // java.util.Optional public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) // java.util.concurrent.CompletionStage: public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn); // java.util.stream.Stream: <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); Any suggestions?
- p2t2p 6y agoI'm not sure if I catch your drift, but if I do: public <T, Z, F extends Function<? super T, Z>> Z apply(Function<F, Z> target, F fn) { return target.apply(fn); } @Test public void test() throws Exception { Stream<String> stream = Stream.of("foo", "bar", "baz"); stream = apply(stream::flatMap, s -> Stream.of(s + "_a", s + "_b")); System.out.println(stream.collect(toList())); Optional<String> bean = Optional.of("bean"); bean = apply(bean::flatMap, b -> Optional.of("soy")); System.out.println(bean); CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello"); CompletableFuture<String> future2 = apply(future1::thenCompose, string -> CompletableFuture.supplyAsync(() -> string + " world")); System.out.println(future2.get()); } Output: [foo_a, foo_b, bar_a, bar_b, baz_a, baz_b] Optional[soy] hello world
- mrkeen 6y agoThis is interesting stuff. I'm trying to figure out how to refer to flatMap directly from the abstract function, e.g. flatMapTwice(x, fun) { return x.flatMap(fun).flatMap(fun); } or chain(x, fun1, fun2) { return x.flatMap(fun1).flatMap(fun2); } It should also preserve the type information (just like you did above). I don't want the caller to need to downcast from FlatMappable. It doesn't need to be x.flatMap(f) - I'd be interested seeing a flatMap(x, f) version.
- p2t2p 6y agoAlso I don't understand why would you need HKT here. I don't see language limitation here, I see poorly designed inheritance in the standard library. They should've introduced "FlatMappable" type and make Option and Stream extend it. CompletionStage, I'm torn on it, on one hand yes, it is a flatMap essentially but semantics is a bit different...
- p2t2p 6y agoOh my god, there's more to that, Optional is a class, not an interface and it's final :facepalm:
- mrkeen 6y agoI've made my peace with those aspects of the libraries. I'm happy to wrap the standard classes in MyOption, MyStream, etc. Then I can extend FlatMappable myself. I just don't know how to declare and implement FlatMappable in a sane way (preserving type information, not needing casts, etc.)
- Joker_vD 6y agoSure: public interface FlatMappable<T> { <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper); } public class FlatMappableOption<T> implements FlatMappable<T> { private final Option<T> value; public FlatMappableOption<T>(Option<T> value) { this.value = value; } <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) { return value.flatMap(mapper); } } // similar wrappers for CompletionStage and Stream Now whenever you want to pass a Stream/CompletionStage/Option to something that accepts FlatMappable, you either a) already has it wrapped in FlatMappable, so pass that wrapper in; or b) has a naked value of known type, so wrap it in the propper wrapper class and pass the resulting wrapper in. Of course, it would be nice to have this wrapping done automatically instead of manually, but that's pretty much how it's actually implemented behind the scenes (dictionary passing, or look at Go's way to wrap things inside interface{}).
- vimax 6y agoI want to do something like this: public <Z, T extends Iterable<Z>, R> T<R> process(T, Function<Z,R>) change the type parameter of T<Z> to T<R> and return an instance of T<R>, but the best I can do is return an instance of Iterable<R> because I cannot define T to have a type parameter.
- mrkeen 6y agoThis comment explains my problem much better than I did.
- p2t2p 6y agosee my comment for the parent with _a_ solution =)
- vimax 6y agoSee my other comment for a longer explanation. I'm curious what your were working on where you ran into this?
- mrkeen 6y ago* At a previous job, I needed to change a fairly large codebase from using Guava futures to Java 8 futures. * At the same job, a coworker expressed a desire to rewrite it with Observables. * At a different job, a different coworker rewrote a chunk of code from Observables into futures. * At my current job, we use micronaut, which has announced it's switching from rxjava2 to project reactor. In the above cases, having interfaces would really help in changing the code piece-by-piece. And the rewrites wouldn't be necessary if they were behind interfaces. In the general case I just want to program to the interface, and not pin my business logic to any particular implementation.
- p2t2p 6y agoSooooo.... A bit more involved than what you describe but I managed to do that: public <A, B, T extends Iterable<A>, R extends Iterable<B>> R process(T input, Function<? super A, ? extends B> transformer, Function<Iterable<B>, R> helper) { return helper.apply(StreamSupport.stream(input.spliterator(), false) .map(transformer) .collect(toList())); } @Test public void testProcess() { Iterable<Integer> ints = process(Arrays.asList("1", "2", "3"), Integer::parseInt, identity()); System.out.println(ints); } Outputs nicely integers nicely converted from strings: [1, 2, 3] :-P `identity()` is a static import of `Function.identity()`