News for hackers. Stuff that matters.
Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @09:51AM (#26660510)
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; }

Re:Background: how we got the generics we have (2020) by vimax on Thursday April 01, 2021 @01:39PM (#26663705)
I 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.

Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @10:10PM (#26668451)
Sooooo.... 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()`

Re:Background: how we got the generics we have (2020) by vimax on Friday April 02, 2021 @05:13PM (#26676059)
That's close, but not quite what I want. The Iterator example starts to break down, but I want to pass in a subclass of Iteratable and get that subclass back.

class SpecialIterator<R> extends Iterator<R>{}

SpecialIterator<String> strings =...;

SpecialIterator<Integer> ints = process(string, magicFunc);

The Iterator example starts to break down, so here's a more concrete example:

I have 3 classes: AbstractTester, StringTester, and ListTester

class AbstractTester<R, T extends AbstractTester<R, ? super T>>

class StringTester<R> extends AbstractTester<R, StringTester<R>>

class ListTester<R, T extends AbstractTester<R, ? super T>>

I want to make a method in AbstractListTest like this: public <Z> T<Z> convert(Z z)

I have supporting code in my classes to create an return an instance of type T<Z>, but I cannot express the type T<Z> in the type system. The type parameter T can extend something with a type parameter, and be passed a type with a type parameter, but it cannot be defined to have a type parameter itself.

This is for a fluent api framework, where I need the compiler to know the type T<Z> without casting

I can do something like this: public <Z, Y extends AbstractTester<Z, ? super T>> Y convert(Z z);

but that will return an AbstractTester<Z> which can be cast to a StringTester<Z>, but the compiler does not know it is a StringTester<Z>

A subclass of AbstractTester is not required to have any type parameters itself. Converting a T to a T<Z> would not be legal for a T without a type parameter. To do what I want, Java would need to add a new type bounds operator to restrict a type parameter to subclasses with a particular type parameter.

Java would need to allow me to define ListTester like this to restrict T to only subclasses with a type parameter:

class ListTester<R, T<_> extends AbstractTester<_, ? super T<_>>

I'd love to be wrong, and would be very grateful to find a way to do this.

Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @10:12PM (#26668460)
The only caveat is that if you change `Iterable<Integer>` to say `Iterable<String>` the compilation error becomes a bit weird in that it says you provide `Iterable<Object>` while `Iterable<String>` is requested. But you do get compile time check after all.
Re:Background: how we got the generics we have (2020) by mrkeen on Friday April 02, 2021 @04:17PM (#26675490)
T is not R though. I want to preserve the static type information such that if I call:

    baz(bar(foo(t, f)));
T<A> should go into foo(..) and come out (e.g. as T<B>) such that I can then call bar(..) on it.

But in this case it leaves foo(..) as R extends Fooable, which is not something I can pass into bar(..).

Re:Background: how we got the generics we have (2020) by zeroimpl on Friday April 02, 2021 @05:25PM (#26676169)
I’d just solve this by passing in a Class<S extends Iterable<R>> arg and making the returned list be an instance of this class, instead of forcing the input collection type to be the same as the output collection type.
Re:Background: how we got the generics we have (2020) by mrkeen on Saturday April 03, 2021 @04:16PM (#26684359)
Then I can't chain method calls.

    foo.doSomething()      // returns Iterable.
       .doSomethingElse(); // Iterable doesn't implement doSomethingElse();
Re:Background: how we got the generics we have (2020) by mrkeen on Thursday April 01, 2021 @05:59PM (#26666688)
This comment explains my problem much better than I did.
Re:Background: how we got the generics we have (2020) by vimax on Friday April 02, 2021 @05:22PM (#26676142)
See my other comment for a longer explanation.

I'm curious what your were working on where you ran into this?

Re:Background: how we got the generics we have (2020) by mrkeen on Saturday April 03, 2021 @04:31PM (#26684451)
* 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.

Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @10:13PM (#26668467)
see my comment for the parent with _a_ solution =)
Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @09:54AM (#26660536)
I can turn any collection to list like that:

public <Z, T extends Collection<Z>> List<Z> process(T collectionOfInteger) { return collectionOfInteger.stream() .collect(toList()); }

Re:Background: how we got the generics we have (2020) by mrkeen on Thursday April 01, 2021 @10:14AM (#26660740)
Great!

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?
Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @11:24AM (#26661621)
I'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

Re:Background: how we got the generics we have (2020) by mrkeen on Thursday April 01, 2021 @05:32PM (#26666360)
This 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.

Re:Background: how we got the generics we have (2020) by Joker_vD on Thursday April 01, 2021 @01:30PM (#26663607)
Sure:

    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{}).

Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @11:44AM (#26661956)
Also 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...
Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @12:00PM (#26662240)
Oh my god, there's more to that, Optional is a class, not an interface and it's final :facepalm:
Re:Background: how we got the generics we have (2020) by mrkeen on Thursday April 01, 2021 @05:39PM (#26666440)
I'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.)