jOOQ / jOOL

jOOλ - The Missing Parts in Java 8 jOOλ improves the JDK libraries in areas where the Expert Group's focus was elsewhere. It adds tuple support, function support, and a lot of additional functionality around sequential Streams. The JDK 8's main efforts (default methods, lambdas, and the Stream API) were focused around maintaining backwards compatibility and implementing a functional API for parallelism.
http://www.jooq.org/products
Apache License 2.0
2.09k stars 168 forks source link

Suggestion for new tuple methods: flattening of optionals #322

Closed jh3141 closed 6 years ago

jh3141 commented 7 years ago

I've been finding the following set of methods for order 2 tuples quite handy, and I'd imagine they'd be pretty easy to extend via your code generator...

    public static <T1, T2> Optional<Tuple2<T1,T2>> flatten1 (Tuple2<Optional<T1>, T2> tuple)
    {
        return tuple.v1.map (just1 -> Tuple.tuple(just1, tuple.v2));
    }
    public static <T1, T2> Optional<Tuple2<T1,T2>> flatten2 (Tuple2<T1, Optional<T2>> tuple)
    {
        return tuple.v2.map (just2 -> Tuple.tuple(tuple.v1, just2));
    }
    public static <T1, T2> Optional<Tuple2<T1,T2>> flatten12 (Tuple2<Optional<T1>, Optional<T2>> tuple)
    {
        return tuple.v1.flatMap ((T1 just1) ->
                tuple.v2.map ((T2 just2) -> Tuple.tuple(just1, just2)));
    }
lukaseder commented 7 years ago

Thanks for your suggestion. What's the use-case for these operations?

jh3141 commented 7 years ago

I commonly use them when fetching a group of related items from a database to perform an operation on, but the operation cannot progress if any of the items is missing.

For example, from my current project:

        stationBlacklist.save (
            Seq.seq (indexData.getItems()).crossApply (ItemIndexingData::getBlackListStations)
                .map (rpiAndStationId  -> Tuples.flatten2 (rpiAndStationId.map2 (stations::get)))   // get the actual station from its ID, if possible
                .transform (StreamUtils::flattenOptionalSeq)                                // lose the empty tuples relating to any missing stations
                .map (StationItemBlacklist::fromTuple) 
                .toList ());
lukaseder commented 7 years ago

Am I understanding this correctly, your getBlackListStations() method returns something allong the lines of a Stream<Optional<STATIONID>>? That doesn't seem like a reasonable type to me. Why not just omit the stations that are not present and return Stream<STATIONID> instead?

I'm not yet convinced that the "flattening" concept is a sufficiently reusable one to be added to the API. Besides, the number of methods to be added to the Tuples class will either explode, or we'll limit this to some degree, e.g. like 2, but in that case, why bother?

jh3141 commented 7 years ago

In the snippet provided, stations::get return Optional<Station>, so the result of:

rpiAndStationId.map2 (stations::get)

is a Tuple2<RPItem, Optional<Station>> -- as the next processing step requires a station, I need to then remove the items from the stream that don't contain a station; I do this in two steps by first moving the Optional<> to outside of the tuple, and then removing them from the stream before finally processing them.

lukaseder commented 7 years ago

stations::get return Optional<Station> ... rpiAndStationId.map2 (stations::get) is a Tuple2<RPItem, Optional<Station>>

I'm sorry would you mind posting all of your involved types in this issue, or in a gist? I'm finding it a bit hard to reason about your types right now. Alternatively, a more reduced, minimal example that does not involve any of your business logic might help, too.

lukaseder commented 6 years ago

Closing this as "won't fix". There isn't a clear enough use-case to justify the addition.