Re: 'Find' method for Iterable

2020-11-17 Thread Nir Lisker
I think that the discussion is still at the level of if it's an acceptable
addition and not yet at where to implement it. I gave my reasoning in
response to Stuart's points as to what I think is acceptable and what
isn't. Whether the java.lang package has special status is a bit ahead of
where we are now.

On Wed, Nov 11, 2020 at 7:22 PM Justin Dekeyser 
wrote:

> Hello all,
>
> Were those downsides seriously considered and strongly argued against? :
>
> (1) Iterable belongs to java.lang so, at least from how it is usually
> approached, it's a feature at the very level of the language, not a
> util feature like Collection. Adding a find on it, is it really
> relevant, or should it be concerned with the simple idea of unlocking
> the enhanced-for loop syntax?
>
> (2) For the find() method to stop on any Iterable, the Iterable should
> have finite size. This mean the size() method can be implemented too,
> by this move:
> ```java
> default int size() {
>int[] dummy = { 0 };
>Predicate falsy = $ -> { dummy[0] += 1; return false; }
>find(falsy);
>return dummy[0];
> }
> ```
> At the very moment an Iterable also has a size(), a Collection
> implementation can be provided (since the altering methods add/remove
> are optional in this spec). So , long story short:
>
> Adding a find() method on Iterable with a contract that it stops
> (stops, and not just linear search time), makes it a Collection. It
> really looks like a nonsense. Or maybe you're going to relax the "this
> method is guaranteed to stop" from the spec? Is it then still
> relevant?
>
> Note: This (2) problem is not a problem for now, because all the utils
> that turns Iterable to a collection like stuff, or a Stream, are
> actually features *on those latter* classes. Hence it's not a concern
> of Iterable itself.
> The problem with (1) is really a communication problem: nothing is
> made in the Java documentation to clearly indicate whether or not
> Iterable should be used businesswise, or is it only for
> syntax-enhancement. (The same problem goes for AutoCloseable: you'll
> really find two schools out of there.)
>
> (3) To my opinion, most people are using Iterable either from a
> collection (where the .stream().filter(p).findAny() makes the job.
> It's not perfect but it's quite clear and flexible) or with a
> ResultSet, where the SQL procedure could/should be used anyway. The
> other cases look so exotic (but I might be wrong) that I really wonder
> how a find method on a Iterable (and not Collection) stuff can be felt
> so useful and language fundamental, that it should be in the java.lang
> package.
>
> Best regards,
>
> Justin Dekeyser
>
> On Tue, Nov 10, 2020 at 7:02 PM Nir Lisker  wrote:
> >
> > Did this discussion get lost?
> >
> > On Sun, Sep 20, 2020 at 1:27 AM Nir Lisker  wrote:
> >
> > > While it might not be difficult to add a find() method to Iterable, why
> > >> limit it to
> > >> the find operation, and what about all the other operations available
> on
> > >> Stream?
> > >
> > >
> > > Good question. I would say it's a matter of how much it is used and
> what
> > > it takes to implement it. The find operation is a lot more common than
> > > reduce from what I observe, for example, so I wouldn't suggest reduce
> to be
> > > added..A map(Function) operation would require creating a new
> > > collection/iterable internally, and that can be messy (you could
> > > preemptively create and pass your own, but then I doubt the worthiness
> of
> > > it). forEach already exists. I just don't see anything enticing.
> > >
> > > Maybe what's necessary is a way to convert an Iterable to a Stream.
> > >
> > >
> > > Most Iterables are Collections and arrays, and these are easy to
> convert,
> > > so I'm not sure if that really helps. Besides,the idea is to avoid
> Stream,
> > > as I've mentioned, due to the cumbersomeness and the overhead of
> creating a
> > > stream. If I need to do
> > >
> > > iterable.stream().filter(person -> person.id ==
> 123456).findAny/First()
> > >
> > > then I didn't really solve my problem.
> > >
> > > On the other hand, your examples use a list. The List interface already
> > >> has methods
> > >> indexOf/lastIndexOf which search the list for a particular object
> that's
> > >> compared
> > >> using equals(). It seems reasonable to consider similar methods that
> take
> > >> a
&

Re: 'Find' method for Iterable

2020-11-10 Thread Nir Lisker
Did this discussion get lost?

On Sun, Sep 20, 2020 at 1:27 AM Nir Lisker  wrote:

> While it might not be difficult to add a find() method to Iterable, why
>> limit it to
>> the find operation, and what about all the other operations available on
>> Stream?
>
>
> Good question. I would say it's a matter of how much it is used and what
> it takes to implement it. The find operation is a lot more common than
> reduce from what I observe, for example, so I wouldn't suggest reduce to be
> added..A map(Function) operation would require creating a new
> collection/iterable internally, and that can be messy (you could
> preemptively create and pass your own, but then I doubt the worthiness of
> it). forEach already exists. I just don't see anything enticing.
>
> Maybe what's necessary is a way to convert an Iterable to a Stream.
>
>
> Most Iterables are Collections and arrays, and these are easy to convert,
> so I'm not sure if that really helps. Besides,the idea is to avoid Stream,
> as I've mentioned, due to the cumbersomeness and the overhead of creating a
> stream. If I need to do
>
> iterable.stream().filter(person -> person.id == 123456).findAny/First()
>
> then I didn't really solve my problem.
>
> On the other hand, your examples use a list. The List interface already
>> has methods
>> indexOf/lastIndexOf which search the list for a particular object that's
>> compared
>> using equals(). It seems reasonable to consider similar methods that take
>> a
>> predicate instead of an object.
>
>
> I could have used a Set just as well. As for indexOf(Predicate), I
> would say that it is useful (but personally, I hardly ever need the index
> of an object, I need the object itself). Interestingly,
> removeIf(Predicate) exists, but remove(Predicate) doesn't. I would
> think twice before suggesting to add it though.
>
> Ultimately, you have access to a lot of analytics and codebase scans. If
> you know which patterns are used a lot more than others it would be a good
> guide. If there are a lot of iterations in order to find an object, its
> index, or to remove it (or something else), perhaps it's worth supplying
> these methods. After all, forEach(Consumer) exists and it iterates while
> calling accept(t) - not that different from iterating with test(t).
>
> P.S. lastIndexOf I find odd in the sense that it's the only method I found
> that iterates backwards, We don't have, removeLast, removeIfBackwards,
> forEachBackwards, a backwards for-each loop, or addLast (the latter is
> add(list.size()-1, e); ).
>
> - Nir
>
> On Thu, Sep 17, 2020 at 1:32 AM Stuart Marks 
> wrote:
>
>>
>>
>> On 9/16/20 1:59 PM, Remi Forax wrote:
>> > - Mail original -
>> >> De: "Nir Lisker" 
>> >> À: "core-libs-dev" 
>> >> Envoyé: Lundi 14 Septembre 2020 20:56:27
>> >> Objet: 'Find' method for Iterable
>> >
>> >> Hi,
>> >>
>> >> This has probably been brought up at some point. When we need to find
>> an
>> >> item in a collection based on its properties, we can either do it in a
>> >> loop, testing each item, or in a stream with filter and findFirst/Any.
>> >>
>> >> I would think that a method in Iterable be useful, along the lines
>> of:
>> >>
>> >> public  Optional find(Predicate condition) {
>> >> Objects.requireNonNull(condition);
>> >> for (T t : this) {
>> >>  if (condition.test(t)) {
>> >>  return Optional.of(t);
>> >> }
>> >> }
>> >> return Optional.empty();
>> >> }
>> >>
>> >> With usage:
>> >>
>> >> list.find(person -> person.id == 123456);
>> >>
>> >> There are a few issues with the method here such as t being null in
>> >> null-friendly collections and the lack of bound generic types, but this
>> >> example is just used to explain the intention.
>> >>
>> >> It will be an alternative to
>> >>
>> >> list.stream().filter(person -> person.id == 123456).findAny/First()
>> >> (depending on if the collection is ordered or not)
>> >>
>> >> which doesn't create a stream, similar to Iterable#forEach vs
>> >> Stream#forEach.
>> >>
>> >> Maybe with pattern matching this would become more appetizing.
>> >
>> > During the development of Java 8, we first tried to use

Re: 'Find' method for Iterable

2020-09-19 Thread Nir Lisker
>
> While it might not be difficult to add a find() method to Iterable, why
> limit it to
> the find operation, and what about all the other operations available on
> Stream?


Good question. I would say it's a matter of how much it is used and what
it takes to implement it. The find operation is a lot more common than
reduce from what I observe, for example, so I wouldn't suggest reduce to be
added..A map(Function) operation would require creating a new
collection/iterable internally, and that can be messy (you could
preemptively create and pass your own, but then I doubt the worthiness of
it). forEach already exists. I just don't see anything enticing.

Maybe what's necessary is a way to convert an Iterable to a Stream.


Most Iterables are Collections and arrays, and these are easy to convert,
so I'm not sure if that really helps. Besides,the idea is to avoid Stream,
as I've mentioned, due to the cumbersomeness and the overhead of creating a
stream. If I need to do

iterable.stream().filter(person -> person.id == 123456).findAny/First()

then I didn't really solve my problem.

On the other hand, your examples use a list. The List interface already has
> methods
> indexOf/lastIndexOf which search the list for a particular object that's
> compared
> using equals(). It seems reasonable to consider similar methods that take a
> predicate instead of an object.


I could have used a Set just as well. As for indexOf(Predicate), I would
say that it is useful (but personally, I hardly ever need the index of an
object, I need the object itself). Interestingly, removeIf(Predicate)
exists, but remove(Predicate) doesn't. I would think twice before
suggesting to add it though.

Ultimately, you have access to a lot of analytics and codebase scans. If
you know which patterns are used a lot more than others it would be a good
guide. If there are a lot of iterations in order to find an object, its
index, or to remove it (or something else), perhaps it's worth supplying
these methods. After all, forEach(Consumer) exists and it iterates while
calling accept(t) - not that different from iterating with test(t).

P.S. lastIndexOf I find odd in the sense that it's the only method I found
that iterates backwards, We don't have, removeLast, removeIfBackwards,
forEachBackwards, a backwards for-each loop, or addLast (the latter is
add(list.size()-1, e); ).

- Nir

On Thu, Sep 17, 2020 at 1:32 AM Stuart Marks 
wrote:

>
>
> On 9/16/20 1:59 PM, Remi Forax wrote:
> > - Mail original -
> >> De: "Nir Lisker" 
> >> À: "core-libs-dev" 
> >> Envoyé: Lundi 14 Septembre 2020 20:56:27
> >> Objet: 'Find' method for Iterable
> >
> >> Hi,
> >>
> >> This has probably been brought up at some point. When we need to find an
> >> item in a collection based on its properties, we can either do it in a
> >> loop, testing each item, or in a stream with filter and findFirst/Any.
> >>
> >> I would think that a method in Iterable be useful, along the lines
> of:
> >>
> >> public  Optional find(Predicate condition) {
> >> Objects.requireNonNull(condition);
> >> for (T t : this) {
> >>  if (condition.test(t)) {
> >>  return Optional.of(t);
> >> }
> >> }
> >> return Optional.empty();
> >> }
> >>
> >> With usage:
> >>
> >> list.find(person -> person.id == 123456);
> >>
> >> There are a few issues with the method here such as t being null in
> >> null-friendly collections and the lack of bound generic types, but this
> >> example is just used to explain the intention.
> >>
> >> It will be an alternative to
> >>
> >> list.stream().filter(person -> person.id == 123456).findAny/First()
> >> (depending on if the collection is ordered or not)
> >>
> >> which doesn't create a stream, similar to Iterable#forEach vs
> >> Stream#forEach.
> >>
> >> Maybe with pattern matching this would become more appetizing.
> >
> > During the development of Java 8, we first tried to use
> Iterator/Iterable instead of using a novel interface Stream.
> > But a Stream cleanly separate the lazy side effect free API from the
> mutable one (Collection) and can be optimized better by the VM (it's a push
> API instead of being a pull API).
> >
> > The other question is why there is no method find() on Collection, i
> believe it's because while find() is ok for any DB API, find() is dangerous
> on a Collection because the execution time is linear, so people may use it
> instea

Re: 'Find' method for Iterable

2020-09-18 Thread Nir Lisker
>
> But a Stream cleanly separate the lazy side effect free API from the
> mutable one (Collection) and can be optimized better by the VM (it's a push
> API instead of being a pull API).


No doubt, but a stream also creates overhead and is more cumbersome to use
in the example I gave. Of course, I can create a helper static method
`find(Collection, Predicate)`, but it's not much cleaner. (And the
implementation can still be through Stream or Iterable,).

I can ask about Iterable#forEach - is it there only because it was there to
begin with? Would it have been a bad idea to add one if we had streams
already?

The other question is why there is no method find() on Collection, i
> believe it's because while find() is ok for any DB API, find() is dangerous
> on a Collection because the execution time is linear, so people may use it
> instead of using a Map.


I don't see a reason to put it Collection when it extends Iterable anyway,
and the method just requires iteration. As for execution time, true, it's
faster, but Map uses a lot more memory, so it's a tradeoff. For smaller
lists, linear time is acceptable. Currently I'm using Maps actually, but I
find that when there are many small maps, having many small lists is better
for memory and the search time is similar. Additionally, a Map works only
for searching by 1 key, but with a Collection/Iterable I can search by any
property, and we're not about to use a Map for every property. So, overall,
I don't think Map is a competitor in this market. It's also possible to
specify that the complexity is linear in an @implNote to avoid surprises.

- Nir

On Wed, Sep 16, 2020 at 11:59 PM Remi Forax  wrote:

> - Mail original -
> > De: "Nir Lisker" 
> > À: "core-libs-dev" 
> > Envoyé: Lundi 14 Septembre 2020 20:56:27
> > Objet: 'Find' method for Iterable
>
> > Hi,
> >
> > This has probably been brought up at some point. When we need to find an
> > item in a collection based on its properties, we can either do it in a
> > loop, testing each item, or in a stream with filter and findFirst/Any.
> >
> > I would think that a method in Iterable be useful, along the lines of:
> >
> > public  Optional find(Predicate condition) {
> >Objects.requireNonNull(condition);
> >for (T t : this) {
> > if (condition.test(t)) {
> > return Optional.of(t);
> >}
> >}
> >return Optional.empty();
> > }
> >
> > With usage:
> >
> > list.find(person -> person.id == 123456);
> >
> > There are a few issues with the method here such as t being null in
> > null-friendly collections and the lack of bound generic types, but this
> > example is just used to explain the intention.
> >
> > It will be an alternative to
> >
> > list.stream().filter(person -> person.id == 123456).findAny/First()
> > (depending on if the collection is ordered or not)
> >
> > which doesn't create a stream, similar to Iterable#forEach vs
> > Stream#forEach.
> >
> > Maybe with pattern matching this would become more appetizing.
>
> During the development of Java 8, we first tried to use Iterator/Iterable
> instead of using a novel interface Stream.
> But a Stream cleanly separate the lazy side effect free API from the
> mutable one (Collection) and can be optimized better by the VM (it's a push
> API instead of being a pull API).
>
> The other question is why there is no method find() on Collection, i
> believe it's because while find() is ok for any DB API, find() is dangerous
> on a Collection because the execution time is linear, so people may use it
> instead of using a Map.
>
> >
> > - Nir
>
> Rémi
>


'Find' method for Iterable

2020-09-15 Thread Nir Lisker
Hi,

This has probably been brought up at some point. When we need to find an
item in a collection based on its properties, we can either do it in a
loop, testing each item, or in a stream with filter and findFirst/Any.

I would think that a method in Iterable be useful, along the lines of:

public  Optional find(Predicate condition) {
Objects.requireNonNull(condition);
for (T t : this) {
 if (condition.test(t)) {
 return Optional.of(t);
}
}
return Optional.empty();
}

With usage:

list.find(person -> person.id == 123456);

There are a few issues with the method here such as t being null in
null-friendly collections and the lack of bound generic types, but this
example is just used to explain the intention.

It will be an alternative to

list.stream().filter(person -> person.id == 123456).findAny/First()
(depending on if the collection is ordered or not)

which doesn't create a stream, similar to Iterable#forEach vs
Stream#forEach.

Maybe with pattern matching this would become more appetizing.

- Nir


JDK-8198620: New Convenient-Methods for java.util.stream.Stream

2018-10-18 Thread Nir Lisker
Hi,

A while back I commented on the suggestion to deal with an annoyance of
casting in a stream [1]. I brought an argument that was used in project
Amber for a similar case.
Like Tagir Valeev, I also see the filter-then-map pattern in various
projects I work on.

I would like to know if this issue can be re-evaluated.

Thanks,
Nir

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