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.dekey...@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 <j...@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 <fo...@univ-mlv.fr> wrote: > > > > > >> ----- Mail original ----- > > >>> De: "Nir Lisker" <nlis...@gmail.com> > > >>> À: "core-libs-dev" <core-libs-dev@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 > > >>