Re: New Collections interface - Sized

2021-04-23 Thread forax
- Mail original -
> De: "Brian Goetz" 
> À: "Remi Forax" , "Stephen Colebourne" 
> 
> Cc: "core-libs-dev" 
> Envoyé: Samedi 24 Avril 2021 00:40:54
> Objet: Re: New Collections interface - Sized

>> This is basically Spliterator, an iterator + a size, with the iterator is 
>> "push"
>> instead of "pull" because it's more efficient.
>>
>> In details a Spliterator is either
>> - an Iterable (with no SIZED characteristic)
>> - an Iterable + size (if SIZED and estimateSize() != Long.MAX_VALUE)
>> - an Iterable + comparator (if SORTED and comparator != null)
>> - an Iterable + split (if trySplit != null)
>>
>> and all combinations of the above.

oops, i've written Iterable instead of Iterator. 

>>
> So, you're asking for Spliterable, no?   :)

a Supplier> is a Spliterable, as in StreamSupport.stream() 
[1].

Rémi

[1] 
https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/stream/StreamSupport.html#stream(java.util.function.Supplier,int,boolean)



Re: New Collections interface - Sized

2021-04-23 Thread Remi Forax
- Mail original -
> De: "Stephen Colebourne" 
> À: "core-libs-dev" 
> Envoyé: Vendredi 23 Avril 2021 11:23:03
> Objet: New Collections interface - Sized

> Hi all,
> While a discussion on ReversibleCollection is going on, I'd like to
> raise the interface I've always found most missing from the framework
> - Sized
> 
> public interface Sized {
>   int size();
>   default boolean isEmpty() {
> return size() == 0;
>   }
>   default boolean isNotEmpty() {
> return !isEmpty();
>   }
> }
> 
> This would be applied to Collection and Map, providing a missing
> unification. Anything else that has a size could also be retrofitted,
> such as String. Ideally arrays too, but that could come later. Note
> that Iterable would not implement it.
> 
> WDYT?

There are 3 ways to have instances of different classes to have a common 
behavior in Java,
- either thy implement a common super-type
- or you use a structural type conversion (a method ref on an instance)
  here:
Sized sized = list::size;
- or you use pattern matching (or a cascade of if/else if you are like the old 
fashion)
int size(Object o) {
  return switch(o) {
case List list -> list.size();
case Object[] array -> array.length();
case String s -> s.length();
default -> throw ...
  };
}

The advantage of pattern matching is that it does not have a global impact, out 
of where you want to use it,
by example, here, you can use s.length() instead of s.codepoints().count() 
without having to think what the default size of a String means for all program 
that can be written. 

> 
> Stephen

Rémi


Re: New Collections interface - Sized

2021-04-23 Thread Brian Goetz




This is basically Spliterator, an iterator + a size, with the iterator is "push" instead 
of "pull" because it's more efficient.

In details a Spliterator is either
- an Iterable (with no SIZED characteristic)
- an Iterable + size (if SIZED and estimateSize() != Long.MAX_VALUE)
- an Iterable + comparator (if SORTED and comparator != null)
- an Iterable + split (if trySplit != null)

and all combinations of the above.


So, you're asking for Spliterable, no?   :)



Re: New Collections interface - Sized

2021-04-23 Thread Remi Forax
- Mail original -
> De: "Stephen Colebourne" 
> À: "core-libs-dev" 
> Envoyé: Samedi 24 Avril 2021 00:14:51
> Objet: Re: New Collections interface - Sized

> On Fri, 23 Apr 2021 at 23:07, Brian Goetz  wrote:
>> >> Is there a compelling example of where this would be used by clients?
>> > Here are some examples:
>> > https://stackoverflow.com/questions/10988634/java-global-isempty-method
>> Without passing judgment on the sort of dynamically typed programs that
>> need a method like this
> 
> The other example is better as it benefits from declaring an API that
> only accepts instances of `Sized` and does not need to get the
> contents.
> 
>> But again, if you are treating these things as containers, then a Sized
>> doesn't get you very far, because if you conclude the thing isn't empty,
>> you're going to want to get stuff out, and Sized has no methods for
>> that.  So presumably there's some companion to Sized for accessing
>> elements by index:
>>
>>  interface HasStuff extends Sized {
>>  T get(int index);
>>  }
> 
> I don't think there has to be. the more useful interface would be this
> one, but to date there has been strong resistance in unifying the
> Collection and Map interfaces:
> 
> interface Stuff extends Sized {
> int size();
> int isEmpty();
> int isNotEmpty();
>Iterator iterator();
> }

This is basically Spliterator, an iterator + a size, with the iterator is 
"push" instead of "pull" because it's more efficient.

In details a Spliterator is either
- an Iterable (with no SIZED characteristic)
- an Iterable + size (if SIZED and estimateSize() != Long.MAX_VALUE)
- an Iterable + comparator (if SORTED and comparator != null)
- an Iterable + split (if trySplit != null)

and all combinations of the above.

> 
> Stephen

Rémi


Re: New Collections interface - Sized

2021-04-23 Thread Stephen Colebourne
On Fri, 23 Apr 2021 at 23:07, Brian Goetz  wrote:
> >> Is there a compelling example of where this would be used by clients?
> > Here are some examples:
> > https://stackoverflow.com/questions/10988634/java-global-isempty-method
> Without passing judgment on the sort of dynamically typed programs that
> need a method like this

The other example is better as it benefits from declaring an API that
only accepts instances of `Sized` and does not need to get the
contents.

> But again, if you are treating these things as containers, then a Sized
> doesn't get you very far, because if you conclude the thing isn't empty,
> you're going to want to get stuff out, and Sized has no methods for
> that.  So presumably there's some companion to Sized for accessing
> elements by index:
>
>  interface HasStuff extends Sized {
>  T get(int index);
>  }

I don't think there has to be. the more useful interface would be this
one, but to date there has been strong resistance in unifying the
Collection and Map interfaces:

 interface Stuff extends Sized {
 int size();
 int isEmpty();
 int isNotEmpty();
Iterator iterator();
 }

Stephen


Re: New Collections interface - Sized

2021-04-23 Thread Brian Goetz




Is there a compelling example of where this would be used by clients?

Here are some examples:
https://stackoverflow.com/questions/10988634/java-global-isempty-method
Without passing judgment on the sort of dynamically typed programs that 
need a method like this, or wondering what monstrosities such code uses 
to actually _get_ the data out of this weird ad-hoc union, note that 
this code becomes dramatically simpler with pattern matching:


    return switch (c) {
    case null -> true;
    case CharSequence cs -> cs.length() == 0;
    case Collection c -> c.isEmpty();
    case Object[] os -> os.length == 0;
    default -> { weird reflective thingy }
    }

Note also that a Sized abstraction only addresses two of these five 
cases -- CharSequence and Collection.  The others would still require 
such ad-hoc treatment.


And while it may seem like I have pattern matching on the brain, there's 
a point to bringing up pattern matching -- which is that real code often 
ends up dealing with ad-hoc unions, and a linguistic mechanism for 
abstracting computations over ad-hoc unions is often a better solution 
if you find yourself in ad-hoc land than trying to partially unify it.


But again, if you are treating these things as containers, then a Sized 
doesn't get you very far, because if you conclude the thing isn't empty, 
you're going to want to get stuff out, and Sized has no methods for 
that.  So presumably there's some companion to Sized for accessing 
elements by index:


    interface HasStuff extends Sized {
    T get(int index);
    }

And note that in order for HasStuff to be useful, it has to extend 
Sized, because, no intersection types.  Which suggests Sized is not the 
abstraction you are looking for.


And again, pattern matching:

    Object getElement(Object thingWithStuff, int index) {
    return switch (thingWithStuff) {
    case null -> null;
    case Object[] os -> os[index];
    case Collection c -> c.get(index);
    ... more if you can think of them ...
   };




Re: New Collections interface - Sized

2021-04-23 Thread Stephen Colebourne
On Fri, 23 Apr 2021 at 17:08, Brian Goetz  wrote:
> This has come up before.  For example, during an early iteration of the 
> Stream design, before parallelism entered the picture.  The first 
> scrawled-on-a-napkin prototype for streams was based on Iterator, and it took 
> about a minute to realize that we could do a much better job if we had a 
> slightly broader interface to work with, essentially Iterator+Sized.
>
> When you pull on this string, you end up with a lot of new interfaces, such 
> as SizedIterator, SizedIterable, etc, in part because ... we have no 
> intersection types.  Having lots of fine-grained interfaces for "has X" and 
> "has Y" is nice from a "bucket of lego bricks" library-design perspective, 
> but when the user goes to express "I need an aggregate that has sizes, 
> iterators, and encounter order", you end up with code like:
>
> > void foo(X x) { ... }
>
> and then you run into the wall of "but I can only use intersection types in 
> these places in the language."  The idiom of having fine-grained mix-in-ish 
> interfaces really wants a language with intersection types.
>
> Additionally, I am having a hard time imagining how Sized would be usable by 
> a client; no method will *take* a Sized (it's just not broad enough), and I 
> can't immediately imagine what would even *return* a Sized.  If the type is 
> not suitable for use by clients, then it serves only to organize the library 
> itself, and that's a weaker motivation.
>
> Is there a compelling example of where this would be used by clients?

Here are some examples:
https://stackoverflow.com/questions/10988634/java-global-isempty-method
https://github.com/OpenGamma/Strata/blob/main/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java#L404

ie. the ability to spot an "empty" object, or ensure input is
non-empty. Use cases are generally in low-level/framework code like
this, where the actual input data type is not known.

Stephen


Re: New Collections interface - Sized

2021-04-23 Thread Brian Goetz
This has come up before.  For example, during an early iteration of the 
Stream design, before parallelism entered the picture.  The first 
scrawled-on-a-napkin prototype for streams was based on Iterator, and it 
took about a minute to realize that we could do a much better job if we 
had a slightly broader interface to work with, essentially Iterator+Sized.


When you pull on this string, you end up with a lot of new interfaces, 
such as SizedIterator, SizedIterable, etc, in part because ... we have 
no intersection types.  Having lots of fine-grained interfaces for "has 
X" and "has Y" is nice from a "bucket of lego bricks" library-design 
perspective, but when the user goes to express "I need an aggregate that 
has sizes, iterators, and encounter order", you end up with code like:


    > void foo(X x) { ... }

and then you run into the wall of "but I can only use intersection types 
in these places in the language."  The idiom of having fine-grained 
mix-in-ish interfaces really wants a language with intersection types.


Additionally, I am having a hard time imagining how Sized would be 
usable by a client; no method will *take* a Sized (it's just not broad 
enough), and I can't immediately imagine what would even *return* a 
Sized.  If the type is not suitable for use by clients, then it serves 
only to organize the library itself, and that's a weaker motivation.


Is there a compelling example of where this would be used by clients?


On 4/23/2021 5:23 AM, Stephen Colebourne wrote:

Hi all,
While a discussion on ReversibleCollection is going on, I'd like to
raise the interface I've always found most missing from the framework
- Sized

  public interface Sized {
int size();
default boolean isEmpty() {
  return size() == 0;
}
default boolean isNotEmpty() {
  return !isEmpty();
}
}

This would be applied to Collection and Map, providing a missing
unification. Anything else that has a size could also be retrofitted,
such as String. Ideally arrays too, but that could come later. Note
that Iterable would not implement it.

WDYT?

Stephen




New Collections interface - Sized

2021-04-23 Thread Stephen Colebourne
Hi all,
While a discussion on ReversibleCollection is going on, I'd like to
raise the interface I've always found most missing from the framework
- Sized

 public interface Sized {
   int size();
   default boolean isEmpty() {
 return size() == 0;
   }
   default boolean isNotEmpty() {
 return !isEmpty();
   }
}

This would be applied to Collection and Map, providing a missing
unification. Anything else that has a size could also be retrofitted,
such as String. Ideally arrays too, but that could come later. Note
that Iterable would not implement it.

WDYT?

Stephen