Re: 'Find' method for Iterable

2020-11-17 Thread Remi Forax
- Mail original -
> De: "Brian Goetz" 
> À: "Michael Kuhlmann" , "core-libs-dev" 
> 
> Envoyé: Mardi 17 Novembre 2020 20:44:17
> Objet: Re: 'Find' method for Iterable

> On 9/21/2020 4:08 AM, Michael Kuhlmann wrote:
>> But after thinking about it, I'm now convinced that it would be a bad
>> idea. Because it extends the scope of this small, tiny Iterable
>> interface to something bigger which it shouldn't be.
> 
> This response captures the essence of the problem.  You may think you
> are asking for "just one more method on Iterable", but really, what you
> are asking for is to turn Iterable into something it is not.  Iterable
> exists not to be "smallest collection", but as the interface to the
> foreach-loop.  Yes, we could have chosen a different design center for
> Iterable (Eclipse Collections did, see RichIterable), but we didn't.
> Adding this method merely sends the signal that we want to extend
> Iterable to be more than it is, which opens the floodgate to requests
> (and eventually demands) for more methods.
> 
>> 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?
> 
> While you can make an argument that forEach is excessive, the fact that
> you make this argument illustrates the essential problem with this
> proposal.  Your argument wrt forEach is "If that makes sense, then so
> does find."  If you pull on that string, then this method forms the
> basis of tomorrow's assumption: "You have forEach and find, it is
> unreasonable to not add ".

There is a good reason to have forEach,
Iterable in the interface of things that can be iterated, and in Java, there 
are two ways to do an iteration,
the internal iteration, where you ask the class to do the iteration for you 
using forEach and
the external iterator, where you ask for an Iterator and use it to iterate 
outside of the class.

In term of API design, it is push vs pull, using forEach, the element are is 
pushed to the Consumer while using an Iterator.next() allow you to pull the 
element.

Usually, forEach() is faster but it takes a Consumer, so you are limited by the 
limitation of the lambda (you can not mutate the local variables of the 
enclosing scope).
Using an Iterator is also more powerful because you can compose them.

> 
> So, Iterable should stay simple.  (The other arguments against it on
> this thread, are also valid, but this is the most important one.)

Yep.

Rémi


Re: 'Find' method for Iterable

2020-11-17 Thread Brian Goetz




On 9/21/2020 4:08 AM, Michael Kuhlmann wrote:
But after thinking about it, I'm now convinced that it would be a bad 
idea. Because it extends the scope of this small, tiny Iterable 
interface to something bigger which it shouldn't be. 


This response captures the essence of the problem.  You may think you 
are asking for "just one more method on Iterable", but really, what you 
are asking for is to turn Iterable into something it is not.  Iterable 
exists not to be "smallest collection", but as the interface to the 
foreach-loop.  Yes, we could have chosen a different design center for 
Iterable (Eclipse Collections did, see RichIterable), but we didn't.  
Adding this method merely sends the signal that we want to extend 
Iterable to be more than it is, which opens the floodgate to requests 
(and eventually demands) for more methods.



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?


While you can make an argument that forEach is excessive, the fact that 
you make this argument illustrates the essential problem with this 
proposal.  Your argument wrt forEach is "If that makes sense, then so 
does find."  If you pull on that string, then this method forms the 
basis of tomorrow's assumption: "You have forEach and find, it is 
unreasonable to not add ".


So, Iterable should stay simple.  (The other arguments against it on 
this thread, are also valid, but this is the most important one.)


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
> > >> predicate instead of an object.
> > >
> > >
> 

Re: 'Find' method for Iterable

2020-11-11 Thread Justin Dekeyser
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
> >> 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).

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
>> Iterator/Iterable instead of using a novel interface Stream.
>&

Re: 'Find' method for Iterable

2020-09-21 Thread Justin Dekeyser
I'm also thinking about something:

If `T find()` gets implemented on `Iterable` with the contract that
this method always ends, this implies that the amount of elements
available in the Iterable is finite, which makes it possible to define
a `int size()` by providing a trivial predicate.
This would in fact turn `Iterable` to a redundant interface with
`Collection`, as the only operations a collection could supply to
enrich Iterable are just the add/remove operations, which are all
optional by contract.

This would sound a bit weird. Iterable will just turn to a readonly
collection, and I think this was not the purpose (from a previous long
post there were in this newsletter, about splitting the List interface
in two interfaces, readonly and write-only).

Regards,

Justin Dekeyser

On Mon, Sep 21, 2020 at 10:31 AM Justin Dekeyser
 wrote:
>
> Hi all,
>
> Correct me if I'm wrong, but isn't the goal of Iterable be used as
> argument in a enhanced for-loop, that is: just allow a enhanced
> syntax.
> (Similarly, AUtoCloseable is what allows the try-with-resource syntax;
> Throwable is what allows the throw syntax)
>
> As such, isn't it out of scope of Iterable to implement this famous find 
> method?
> Since it's scope should just be to allow enhanced for-loop ?
>
> It's more like a general question in the Java programming language
> design actually: is one expected to code with those interfaces in a
> business-way,
> or implement them to allow a specific syntax ?
>
> Regards,
>
> Justin Dekeyser
>
> On Mon, Sep 21, 2020 at 10:08 AM Michael Kuhlmann  wrote:
> >
> > Hi Nir,
> >
> > at first I thought "Wow, it would be really cool to have that method in
> > Iterable! Why isn't it there already?"
> >
> > But after thinking about it, I'm now convinced that it would be a bad
> > idea. Because it extends the scope of this small, tiny Iterable
> > interface to something bigger which it shouldn't be.
> >
> > When some class implements Iterable, it just says "you can iterate over
> > my something which I call elements". Nothing more. Now when Iterable
> > implements find() by default, then automatically all classes which just
> > want to enable users to iterate over elements also tell them that there
> > can be something useful found in these elements, which is not
> > necessarily the case.
> >
> > For example, BitSet could immplements Iterable. That doesn't
> > make much practical sense, but from the definition of a BitSet it's
> > understandable: A BitSet can be seen as a set of integer values, why
> > shouldn't someone iterate over them. But now, when you add find() to
> > Iterable, it immediately tells users: Hey, you can find integers in me,
> > and when you found one, you get it returned. Which is beyond the use
> > case of a BitSet.
> >
> > forEach() is different, because forEach just iterates over the elements
> > and nothing more, which is in the scope of an Iterable.
> >
> > A second argument against adding find() is that such a generic method
> > could conflict with more specialized methods in subinterfaces or
> > classes. I like the idea of having indexOf(Predicate) in List
> > interface, but having both of them would be redundant.
> >
> > And a third argument is that it can break existing code. An implementor
> > of Iterable could already define a find() method, but return the index
> > of the element instead of the element itself, or throw some checked
> > exception. This code wouldn't compile any more.
> >
> > So while the idea of having find() in Iterable is great, the arguments
> > against are heavier from my point of view.
> >
> > -Michael
> >
> >
> > On 9/16/20 11:36 PM, Nir Lisker wrote:
> > > 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
> >

Re: 'Find' method for Iterable

2020-09-21 Thread Justin Dekeyser
Hi all,

Correct me if I'm wrong, but isn't the goal of Iterable be used as
argument in a enhanced for-loop, that is: just allow a enhanced
syntax.
(Similarly, AUtoCloseable is what allows the try-with-resource syntax;
Throwable is what allows the throw syntax)

As such, isn't it out of scope of Iterable to implement this famous find method?
Since it's scope should just be to allow enhanced for-loop ?

It's more like a general question in the Java programming language
design actually: is one expected to code with those interfaces in a
business-way,
or implement them to allow a specific syntax ?

Regards,

Justin Dekeyser

On Mon, Sep 21, 2020 at 10:08 AM Michael Kuhlmann  wrote:
>
> Hi Nir,
>
> at first I thought "Wow, it would be really cool to have that method in
> Iterable! Why isn't it there already?"
>
> But after thinking about it, I'm now convinced that it would be a bad
> idea. Because it extends the scope of this small, tiny Iterable
> interface to something bigger which it shouldn't be.
>
> When some class implements Iterable, it just says "you can iterate over
> my something which I call elements". Nothing more. Now when Iterable
> implements find() by default, then automatically all classes which just
> want to enable users to iterate over elements also tell them that there
> can be something useful found in these elements, which is not
> necessarily the case.
>
> For example, BitSet could immplements Iterable. That doesn't
> make much practical sense, but from the definition of a BitSet it's
> understandable: A BitSet can be seen as a set of integer values, why
> shouldn't someone iterate over them. But now, when you add find() to
> Iterable, it immediately tells users: Hey, you can find integers in me,
> and when you found one, you get it returned. Which is beyond the use
> case of a BitSet.
>
> forEach() is different, because forEach just iterates over the elements
> and nothing more, which is in the scope of an Iterable.
>
> A second argument against adding find() is that such a generic method
> could conflict with more specialized methods in subinterfaces or
> classes. I like the idea of having indexOf(Predicate) in List
> interface, but having both of them would be redundant.
>
> And a third argument is that it can break existing code. An implementor
> of Iterable could already define a find() method, but return the index
> of the element instead of the element itself, or throw some checked
> exception. This code wouldn't compile any more.
>
> So while the idea of having find() in Iterable is great, the arguments
> against are heavier from my point of view.
>
> -Michael
>
>
> On 9/16/20 11:36 PM, Nir Lisker wrote:
> > 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 ==

Re: 'Find' method for Iterable

2020-09-21 Thread Michael Kuhlmann

Hi Nir,

at first I thought "Wow, it would be really cool to have that method in 
Iterable! Why isn't it there already?"


But after thinking about it, I'm now convinced that it would be a bad 
idea. Because it extends the scope of this small, tiny Iterable 
interface to something bigger which it shouldn't be.


When some class implements Iterable, it just says "you can iterate over 
my something which I call elements". Nothing more. Now when Iterable 
implements find() by default, then automatically all classes which just 
want to enable users to iterate over elements also tell them that there 
can be something useful found in these elements, which is not 
necessarily the case.


For example, BitSet could immplements Iterable. That doesn't 
make much practical sense, but from the definition of a BitSet it's 
understandable: A BitSet can be seen as a set of integer values, why 
shouldn't someone iterate over them. But now, when you add find() to 
Iterable, it immediately tells users: Hey, you can find integers in me, 
and when you found one, you get it returned. Which is beyond the use 
case of a BitSet.


forEach() is different, because forEach just iterates over the elements 
and nothing more, which is in the scope of an Iterable.


A second argument against adding find() is that such a generic method 
could conflict with more specialized methods in subinterfaces or 
classes. I like the idea of having indexOf(Predicate) in List 
interface, but having both of them would be redundant.


And a third argument is that it can break existing code. An implementor 
of Iterable could already define a find() method, but return the index 
of the element instead of the element itself, or throw some checked 
exception. This code wouldn't compile any more.


So while the idea of having find() in Iterable is great, the arguments 
against are heavier from my point of view.


-Michael


On 9/16/20 11:36 PM, Nir Lisker wrote:

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



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
> instead of using a Map.
>
>
> Hi Nir,
>
> Rémi is correct to point out this 

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
>


Re: 'Find' method for Iterable

2020-09-16 Thread Stuart Marks




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 instead 
of using a Map.



Hi Nir,

Rémi is correct to point out this distinction between the lazy operations (which 
appear on Stream) and the eager (and possibly mutating) operations on Collections. I 
think we want to preserve this distinction.


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? 
Maybe what's necessary is a way to convert an Iterable to a Stream. In fact, this is 
already possible:


StreamSupport.stream(iterable.spliterator(), false)

Well, this is mouthful, so maybe there ought to be an easier way to convert an 
Iterable to a Stream.


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.


Does either of these sound promising?

s'marks


Re: 'Find' method for Iterable

2020-09-16 Thread Remi Forax
- 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