Fwd: Mechanism to maintain backwards compatibility when moving classes to different packages

2019-07-02 Thread Jacob Glickman
Friendly reminder :)
-- Forwarded message -
From: Jacob Glickman 
Date: Sat, Jun 22, 2019 at 4:42 PM
Subject: Mechanism to maintain backwards compatibility when moving classes
to different packages
To: 


Yesterday, Mark Reinhold introduced the idea of a java.util.random
subpackage[1]. Obviously, moving java.util.Random into that subpackage is
not currently an option, as that would break backwards compatibility.
Assuming the subpackage is created, it would make sense to ultimately move
java.util.Random into it. For that reason, I propose a new language feature
that could make this possible:

package java.util.random previously java.util;

The syntax isn't important at the moment, but this mechanism should allow
for users to run previously-compiled code with newer versions of Java, even
if their code points to a class that has since been moved to a different
package.

To eliminate potential bugs, users compiling new code shouldn't be allowed
to reference java.util.Random, even if java.util.random.Random states that
it previously resided in java.util.

I'm curious what you all would think of this, as it is not just applicable
to this single example. There have been plenty of times that I've realized
that my packages were named badly, but I'm forced to stick with that naming
(unless I want my users to have to modify their code).

Thanks,

Jacob Glickman

[1]:
http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-June/060995.html


Mechanism to maintain backwards compatibility when moving classes to different packages

2019-06-22 Thread Jacob Glickman
Yesterday, Mark Reinhold introduced the idea of a java.util.random
subpackage[1]. Obviously, moving java.util.Random into that subpackage is
not currently an option, as that would break backwards compatibility.
Assuming the subpackage is created, it would make sense to ultimately move
java.util.Random into it. For that reason, I propose a new language feature
that could make this possible:

package java.util.random previously java.util;

The syntax isn't important at the moment, but this mechanism should allow
for users to run previously-compiled code with newer versions of Java, even
if their code points to a class that has since been moved to a different
package.

To eliminate potential bugs, users compiling new code shouldn't be allowed
to reference java.util.Random, even if java.util.random.Random states that
it previously resided in java.util.

I'm curious what you all would think of this, as it is not just applicable
to this single example. There have been plenty of times that I've realized
that my packages were named badly, but I'm forced to stick with that naming
(unless I want my users to have to modify their code).

Thanks,

Jacob Glickman

[1]:
http://mail.openjdk.java.net/pipermail/core-libs-dev/2019-June/060995.html


Stream Method Proposal: long count(Predicate predicate)

2018-11-09 Thread Jacob Glickman
Hello!

I see myself having to often call count() as a terminal operation on a
Stream immediately after performing a filter operation. How feasible would
it be to add an overloaded count() method that accepts a Predicate, which
it uses as a filter before returning the count of elements in the Stream?
If this is supported, I'd gladly create the webrev & tests for it!

I suppose the method signature can be something along the lines of:

long count(Predicate predicate)

It would also seem reasonable to give this method to IntStream,
DoubleStream, and LongStream, but allowing them to use IntPredicate,
DoublePredicate, and LongPredicate respectively.

Thanks,

Jacob Glickman


Re: Stream Method Proposal: long count(Predicate predicate)

2018-11-08 Thread Jacob Glickman
There was a typo in my last e-mail:

`.count("Java::equals")` should be `.count("Java"::equals)`

Thanks,

Jacob Glickman

On Thu, Nov 8, 2018 at 9:02 AM Jacob Glickman  wrote:

> Tagir,
>
> Nothing is wrong with it, but I think the addition of the convenience
> method(s) would help to improve readability in some cases. Personally, I'd
> much rather have the option of writing `.count("Java::equals")` than
> `.filter("Java"::equals).count()`. As Zheka stated, this type of
> convenience method could also be useful for findFirst, in addition to
> findAny, distinct, etc.
>
> Thanks,
>
> Jacob Glickman
>
> On Thu, Nov 8, 2018 at 4:46 AM Tagir Valeev  wrote:
>
>> What's wrong with `filter(predicate).count()`? Saving nine characters?
>>
>> With best regards,
>> Tagir Valeev.
>> On Thu, Nov 8, 2018 at 8:02 AM Jacob Glickman 
>> wrote:
>> >
>> >  Hello!
>> >
>> > I see myself having to often call count() as a terminal operation on a
>> > Stream immediately after performing a filter operation. How feasible
>> would
>> > it be to add an overloaded count() method that accepts a Predicate,
>> which
>> > it uses as a filter before returning the count of elements in the
>> Stream?
>> > If this is supported, I'd gladly create the webrev & tests for it!
>> >
>> > I suppose the method signature can be something along the lines of:
>> >
>> > long count(Predicate predicate)
>> >
>> > It would also seem reasonable to give this method to IntStream,
>> > DoubleStream, and LongStream, but allowing them to use IntPredicate,
>> > DoublePredicate, and LongPredicate respectively.
>> >
>> > Thanks,
>> >
>> > Jacob Glickman
>>
>


Re: Stream Method Proposal: long count(Predicate predicate)

2018-11-08 Thread Jacob Glickman
Tagir,

Nothing is wrong with it, but I think the addition of the convenience
method(s) would help to improve readability in some cases. Personally, I'd
much rather have the option of writing `.count("Java::equals")` than
`.filter("Java"::equals).count()`. As Zheka stated, this type of
convenience method could also be useful for findFirst, in addition to
findAny, distinct, etc.

Thanks,

Jacob Glickman

On Thu, Nov 8, 2018 at 4:46 AM Tagir Valeev  wrote:

> What's wrong with `filter(predicate).count()`? Saving nine characters?
>
> With best regards,
> Tagir Valeev.
> On Thu, Nov 8, 2018 at 8:02 AM Jacob Glickman  wrote:
> >
> >  Hello!
> >
> > I see myself having to often call count() as a terminal operation on a
> > Stream immediately after performing a filter operation. How feasible
> would
> > it be to add an overloaded count() method that accepts a Predicate, which
> > it uses as a filter before returning the count of elements in the Stream?
> > If this is supported, I'd gladly create the webrev & tests for it!
> >
> > I suppose the method signature can be something along the lines of:
> >
> > long count(Predicate predicate)
> >
> > It would also seem reasonable to give this method to IntStream,
> > DoubleStream, and LongStream, but allowing them to use IntPredicate,
> > DoublePredicate, and LongPredicate respectively.
> >
> > Thanks,
> >
> > Jacob Glickman
>


Stream Method Proposal: long count(Predicate predicate)

2018-11-07 Thread Jacob Glickman
 Hello!

I see myself having to often call count() as a terminal operation on a
Stream immediately after performing a filter operation. How feasible would
it be to add an overloaded count() method that accepts a Predicate, which
it uses as a filter before returning the count of elements in the Stream?
If this is supported, I'd gladly create the webrev & tests for it!

I suppose the method signature can be something along the lines of:

long count(Predicate predicate)

It would also seem reasonable to give this method to IntStream,
DoubleStream, and LongStream, but allowing them to use IntPredicate,
DoublePredicate, and LongPredicate respectively.

Thanks,

Jacob Glickman


Re: BiCollector

2018-06-18 Thread Jacob Glickman
Agreed.  Not sure if this has been suggested, but what about duplex(ing)?

On Mon, Jun 18, 2018 at 5:29 PM Brian Goetz  wrote:

> "bisecting" sounds like it sends half the elements to one collector and
> half to the other ...
>
> "tee" might be a candidate, though it doesn't follow the `ing
> convention.  "teeing" sounds dumb.
>
>
>
> On 6/15/2018 7:36 PM, Paul Sandoz wrote:
> > Hi Tagir,
> >
> > This is looking good.
> >
> > My current favorite name for the factory method is “bisecting” since we
> are dividing the collector into two collectors, the results of which are
> then merged.
> >
> > Suggested first paragraph of the factory method:
> >
> >"Returns a collector that passes the input elements to two specified
> collectors and merges their results with the specified merge function.”
> >
> > Paul.
> >
> >
> >> On Jun 15, 2018, at 4:26 AM, Tagir Valeev  wrote:
> >>
> >> Hello!
> >>
> >> I created a preliminary webrev of my own implementation (no testcases
> yet):
> >> http://cr.openjdk.java.net/~tvaleev/patches/pairing/webrev/
> >> If anybody wants to sponsor my implementation, I will happily log an
> issue and write tests.
> >>
> >> The name "pairing" was invented by me, but as I'm not a native English
> speaker I cannot judge whether it's optimal, so better ideas are welcome.
> >> Also I decided to remove accumulator types from public type variables.
> They do not add anything to type signature, only clutter it
> >> increasing the number of type parameters from 4 to 6. I think it was a
> mistake to expose the accumulator type parameter in other cascading
> collectors
> >> like filtering(), collectingAndThen(), groupingBy(), etc. I'm not
> insisting though, if you feel that conformance to existing collectors is
> >> more important than simplicity.
> >>
> >> With best regards,
> >> Tagir Valeev.
> >>
> >> On Fri, Jun 15, 2018 at 5:05 AM Brian Goetz 
> wrote:
> >>
> >>> Well, I don't see the need to pack the two results into a Map.Entry
> >>> (or any similar) container as a drawback.
> >>   From an "integrity of the JDK APIs" perspective, it is unquestionably
> a
> >> drawback.  These items are not a Key and an associated Value in a Map;
> >> it's merely pretending that Map.Entry really means "Pair".  There's a
> >> reason we don't have a Pair class in the JDK (and no, let's not reopen
> >> that now); using something else as a Pair proxy that is supposed to have
> >> specific semantics is worse. (It's fine to do this in your own code, but
> >> not in the JDK. Different standards for code that has different
> audiences.)
> >>
> >> Tagir's proposed sidestepping is nice, and it will also play nicely with
> >> records, because then you can say:
> >>
> >>record NameAndCount(String name, int count);
> >>
> >>stream.collect(pairing(collectName, collectCount,
> NameAndCount::new));
> >>
> >> and get a more properly abstract result out.  And its more in the spirit
> >> of existing Collectors.  If you want to use Map.Entry as an
> >> _implementation detail_, that's fine.
> >>
> >> I can support this form.
> >>
> >>> I also don't see a larger abstraction like BiStream as a natural fit
> >>> for a similar thing.
> >> I think the BiStream connection is mostly tangential.  We tried hard to
> >> support streams of (K,V) pairs when we did streams, as Paul can attest,
> >> but it was a huge complexity-inflater and dropping this out paid an
> >> enormous simplification payoff.
> >>
> >> With records, having streams of tuples will be simpler to represent, but
> >> no more performant; it will take until we get to value types and
> >> specialized generics to get the performance we want out of this.
> >>
> >>
>
>


Discussion: Introduce a `Stream.reject` method, the opposite of `Stream.filter`

2018-05-18 Thread Jacob Glickman
Seeing as `Predicate.not` was just proposed, I think it would be a good
idea to also introduce `Stream.reject`, which would be logically equivalent
to calling `Stream.filter` with a negated `Predicate`, but with fewer
method calls.

Instead of:

Stream.of("", "A", "B", "C")
 .filter(s -> !s.isEmpty())
 .count();

You could call:

Stream.of("", "A", "B", "C")
 .reject(String::isEmpty)
 .count();

I welcome any suggestions for better names other than `reject`.  If this
suggestion is supported, then I'll happily submit an RFE and the code,
tests, etc.

- Jacob


Discussion: Efficient ByteBuffer -> String that avoids additional copying

2018-05-16 Thread Jacob Glickman
Paul,

Would you mind explaining more about what you're looking for regarding
this?  I'm curious if `ByteBuffer#getString` is what you're after, or
rather something similar to `String.from(ByteBuffer)`.  I'll definitely
have a look at jdk.internal.misc.SharedSecrets in the meantime.  Thanks!

- Jacob

>Hi Jacob,
>I do have one idea (that i don’t think is currently represented as a bug,
though i have not searched JBS), if you are willing to take it on. It will
require some investigation, and careful testing, it’s not necessarily a
starter bug :-), but i can help guide.
>Investigate new methods to more efficiently support ByteBuffer -> String
method on ByteBuffer that can avoid additional copying and makeappropriate
use of charsets given String’s compact string support. You need to look at
jdk.internal.misc.SharedSecrets for clues on how to trampoline between the
nio and lang packages.
>Paul.


[PATCH] 8202521: Add overloaded methods of Map#compute, Map#computeIfAbsent, Map#computeIfPresent

2018-05-08 Thread Jacob Glickman
 Hi Paul,

Thank you for the response!  I understand I should have discussed this
before submitting a patch, and will do so from now on.  I would be happy to
contribute to fixing some starter bugs, and I'd be very grateful if you are
able point me to some!

- Jacob


[PATCH] 8202521: Add overloaded methods of Map#compute, Map#computeIfAbsent, Map#computeIfPresent

2018-05-03 Thread Jacob Glickman
Hello!  This is my first patch, so I apologize in advance if I've done
anything incorrectly (including botching the formatting of the mercurial
diff below).

I think it would be beneficial to have an overloaded `Map.computeIfAbsent`
method where the computed value does not depend on the key; for that
reason, I submitted [1].  By taking a `Supplier`, this
will allow users to utilize method references where applicable.  For
example, if they create a `Map>`, then the
following can be used when computing values:

map.computeIfAbsent("key", ArrayList::new).add(1);

I originally planned to add overloaded methods for `Map.computeIfPresent`
and `Map.compute` as well, but it would make more sense for them to take a
`Function` (instead of a `Supplier`) if the computed value does not depend
on the key.  If this patch is successful, then I'll go forward with that
planned change.  To clarify, an overloaded `Map.computeIfAbsent` method was
the only change, along with the unit test.

I used JMH to benchmark my implementation versus an inlined implementation
(not calling the existing `Map.computeIfAbsent` with the result of the
supplier), and the difference was negligible (maybe the compiler inlined
it?).  Please let me know if I should inline it so I can change my
implementation.

[1]: https://bugs.openjdk.java.net/browse/JDK-8202521

--
# HG changeset patch
# User jhg023
# Date 1525366367 25200
#  Thu May 03 09:52:47 2018 -0700
# Node ID 395def2871e8d077b382d722efc59b38373327d1
# Parent  ea246151be08995543d0c9281099608bc9207a19
8202521: Add overloaded methods of Map#compute, Map#computeIfAbsent,
Map#computeIfPresent
Summary: Added "Map.computeIfAbsent(K key, Supplier supplier)"
Reviewed-by: N/A
Contributed-by: Jacob Glickman 

diff -r ea246151be08 -r 395def2871e8
src/java.base/share/classes/java/util/Hashtable.java
--- a/src/java.base/share/classes/java/util/Hashtable.java  Wed May 02
11:21:27 2018 -0700
+++ b/src/java.base/share/classes/java/util/Hashtable.java  Thu May 03
09:52:47 2018 -0700
@@ -29,6 +29,7 @@
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.BiFunction;
+import java.util.function.Supplier;
 import jdk.internal.misc.SharedSecrets;

 /**
@@ -1054,6 +1055,21 @@
  * {@inheritDoc}
  *
  * This method will, on a best-effort basis, throw a
+ * {@link java.util.ConcurrentModificationException} if the
+ * supplier modified this map during computation.
+ *
+ * @throws ConcurrentModificationException if it is detected that the
+ * supplier modified this map
+ */
+@Override
+public synchronized V computeIfAbsent(K key, Supplier
supplier) {
+return computeIfAbsent(key, k -> supplier.get());
+}
+
+/**
+ * {@inheritDoc}
+ *
+ * This method will, on a best-effort basis, throw a
  * {@link java.util.ConcurrentModificationException} if the remapping
  * function modified this map during computation.
  *
diff -r ea246151be08 -r 395def2871e8
src/java.base/share/classes/java/util/Map.java
--- a/src/java.base/share/classes/java/util/Map.javaWed May 02 11:21:27
2018 -0700
+++ b/src/java.base/share/classes/java/util/Map.javaThu May 03 09:52:47
2018 -0700
@@ -28,6 +28,7 @@
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.io.Serializable;

 /**
@@ -1010,6 +1011,85 @@
 }

 /**
+ * If the specified key is not already associated with a value (or is
mapped
+ * to {@code null}), attempts to compute its value using the given
supplier
+ * and enters it into this map unless {@code null}.
+ *
+ * If the supplier returns {@code null}, no mapping is recorded.
+ * If the supplier itself throws an (unchecked) exception, the
+ * exception is rethrown, and no mapping is recorded. The most
+ * common usage is to construct a new object serving as an initial
+ * mapped value or memoized result that does not depend on the key,
+ * as in:
+ *
+ *  {@code
+ * map.computeIfAbsent(key, () -> new Value());
+ * }
+ *
+ * Or to implement a multi-value map, {@code Map>},
+ * supporting multiple values per key:
+ *
+ *  {@code
+ * map.computeIfAbsent(key, HashSet::new).add(v);
+ * }
+ *
+ * The supplier should not modify this map during computation.
+ *
+ * @implSpec
+ * The default implementation is equivalent to the following steps for
this
+ * {@code map}, then returning the current value or {@code null} if now
+ * absent:
+ *
+ *  {@code
+ * if (map.get(key) == null) {
+ * V newValue = supplier.get();
+ * if (newValue != null)
+ * map.put(key, newValue);
+ * }
+ * }
+ *
+ * The default implementation