[Records] Transparency and effects on collections

Tagir Valeev amaembo at gmail.com
Tue Mar 17 10:41:49 UTC 2020


Hello!

I can imagine that we have somewhere in the library a FunctionHelper
interface like this:

interface FunctionHelper<R, T> {
    default Predicate<? super R> is(T value) {
        return r -> Objects.equals(map().apply(r), value);
    }

    default Predicate<? super R> not(T value) {
        return r -> !Objects.equals(map().apply(r), value);
    }

    default Consumer<? super R> consume(Consumer<? super T> consumer) {
        return r -> consumer.accept(map().apply(r));
    }

    // maybe more function adapters

    Function<? super R, ? extends T> map();

    static <R, T> FunctionHelper<R, T> forAccessor(Function<? super R,
? extends T> accessor) {
        return () -> accessor;
    }
}


Then we generate static fields that correspond to every record component:

record Point(int x, int y) {
    public static final FunctionHelper<Point, Integer> X =
FunctionHelper.forAccessor(Point::x);
    public static final FunctionHelper<Point, Integer> Y =
FunctionHelper.forAccessor(Point::y);
}

Then we can use them:

var points = List.of(new Point(1, 2), new Point(3, 4), new Point(5, 6));
points.forEach(Point.X.consume(System.out::println));
points.stream().filter(Point.Y.is(4)).forEach(System.out::println);
points.stream().filter(Point.Y.not(4)).forEach(System.out::println);

Of course, nobody will do this but it looks nice to me.

With best regards,
Tagir Valeev

On Tue, Mar 17, 2020 at 4:58 PM Remi Forax <forax at univ-mlv.fr> wrote:

> Hi Daniel,
> Pooling of Java objects in memory usually do more harm than good, because
> you artificially change the liveness of the pooled objects which doesn't
> work well with modern GC algorithms.
> Obviously, if objects are stored in a database, it can still be a win but
> usually the pool is more or less coupled with the ORM and use off-heap
> memory.
>
> EnumSet/EnumMap are specialized because Enum.ordinal() is a perfect
> hashcode function, so you can implement fast and compact set and map. It's
> not clear to me why there is a need for a specialized version of set/map
> for record given has you said a record is a class. Do we miss something ?
>
> About filtering fields value on stream, adding a method isEqual that takes
> a mapping function and a value should be enough,
>   Predicate<Point> filter = Predicate.isEqual(Company::name, "Apple");
> I remember the lambda EG discuss that method (and its primitive
> variations), i don't remember why it's was not added.
>
> About introducing a typesafe representation of fields, we currently
> provide a non-typesafe representation, j.l.r.RecordComponent.
> There is no typesafe representation because what :: means on a field is
> still an open question.
> And if we go that way, a static final field is not the best representation
> in term of classfile because it is initialized too early. A ldc
> constantdynamic + a static method or something along that line is a better
> idea.
>
> regards,
> Rémi
>
> ------------------------------
>
> *De: *"Brian Goetz" <brian.goetz at oracle.com>
> *À: *"amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> *Envoyé: *Lundi 16 Mars 2020 21:24:04
> *Objet: *Fwd: [Records] Transparency and effects on collections
>
> Received on the -comments list.
>
>
> -------- Forwarded Message --------
> Subject: [Records] Transparency and effects on collections
> Date: Wed, 11 Mar 2020 07:45:32 -0700 (PDT)
> From: Daniel Latrémolière <daniel.latremoliere at gmail.com>
> <daniel.latremoliere at gmail.com>
> To: amber-spec-comments at openjdk.java.net
>
>
> I understand that records are transparent and have correct
> equals/hashcode, then are useful as keys in collections. When trying to
> find classes to evolve to records, I found classes having more or less the
> same use-cases in memory than a multi-column primary key would have in SQL.
> ------------------------------------------------------------------------
> Records are a sugar above classes, like enum but for another use case, is
> it planned to have more evolved collections (like enum has with
> EnumSet/EnumMap)? Given records are explicitly transparent, API for pooling
> records would need to use this explicit transparency to allow partial
> queries and not only the Set/Map exact operations.
>
> If this is the case, it would probably need some specialised subtype of
> Set, like a new RecordSet (similar to a simple table without join, contrary
> to SQL). Current Java's Stream API would probably be perfect with some
> small enhancements, JPA-like (on a sub-type RecordStream<R>) allowing to
> refer directly to the field to be filtered.
>
> In this case, the compiler would need to generate for each record one
> static field per instance field of the record to allow typed queries, like
> in the following example.
>
> |record R(|||String foo, ...)| {||
> ||   ...||
> ||}||
> |
> desugarized more completely in:
>
> |class R {||
> ||  public static final RecordField<R, String> FOO;||
> ||  private String foo;||
> ||   ...||
> ||}||
> |
> It would allow some typed code for partial querying, like:
>
> |RecordSet<R> keyPool;||
> ||Predicate<String> fooFilter;||
> ||keyPool.stream().filter(R.FOO, fooFilter).forEach(...);||
> |
>
> Thanks for your attention,
> Daniel.
> ------------------------------------------------------------------------
> NB: in desugarization, I used standard static fields, like JPA, and not an
> enum containing all meta-fields (which would probably be more correct and
> efficient). This is due to the lack of JEP 301 (needed for typed constants
> in enum). If allowed, the desugarized record will become something like:
>
> |class R {||
> ||  public static enum META<X> implements RecordField<R, X> {||
> ||    FOO<String>(String.class);||
> ||  }||
> ||  private String foo;||
> ||  ...||
> ||}||
> |
> In query, it would be used as R.META.FOO for filtering on field "foo" of
> the record:
>
> |keyPool.stream().filter(R.META.FOO, fooFilter).forEach(...)|
> ------------------------------------------------------------------------
> PS: I am not interested in interning records but using them in pools
> defined by programmer. Pooling would improve memory and performance to
> deduplicate records, because equals would more frequently succeed at
> identity test without continuing to real equality test (field by field).
> Having specialized implementations of collections, using fields of records
> following the order given by user, would probably be useful for performance
> against simple Set/Map: structures like a hierarchical Map of Map of ...,
> field by field, can be more efficient if partial queries are frequently
> used or if the pool is big.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200317/3494b364/attachment.htm>


More information about the amber-spec-experts mailing list