'Find' method for Iterable

Justin Dekeyser justin.dekeyser at gmail.com
Mon Sep 21 09:21:20 UTC 2020


I'm also thinking about something:

If `T find()` gets implemented on `Iterable<T>` 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<T>` to a redundant interface with
`Collection<T>`, 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
<justin.dekeyser at gmail.com> 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 <jdk at fiolino.de> 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<Integer>. 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<T>) 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 <forax at univ-mlv.fr> wrote:
> > >
> > >> ----- Mail original -----
> > >>> De: "Nir Lisker" <nlisker at gmail.com>
> > >>> À: "core-libs-dev" <core-libs-dev at openjdk.java.net>
> > >>> 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<T> be useful, along the lines of:
> > >>>
> > >>> public <T> Optional<T> find(Predicate<T> 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
> > >>


More information about the core-libs-dev mailing list