valhalla-dev Digest, Vol 6, Issue 3

Thomas W twhitmore.nz at gmail.com
Fri Dec 26 01:28:49 UTC 2014


Hi Brian, people,

Thanks for your thoughts! A few responses, some questions and a couple of
other points:

1)  Re: List<int>.remove() disambiguation
-----------------------------------------------------------

Your solution here amounts to a deprecation mechanism with hints, which is
> an OK solution to the remove(int)/remove(Object) problem.
>

Yes, but having thought further, it would probably be clearest to
definitively rename the methods & annotate the "legacy compatibility" name
to generate a bridge method.

@LegacyName(whenUnambiguous="remove")
public T removeAt (int index);


2)  Type signature of removeAll(Collection<?>), remove(Object item)
-----------------------------------------------------------
-------------------------------------

I made a start on addressing this in my previous post;  in regards to the
type of remove() 'item' parameter.

At that stage I called the concept "compatible" -- which is perhaps too
strong, as the specific & exact intent is "any subtype or ancestor of T" --
essentially, any inheritance relative that could _potentially_ be
compatible.

Now my understanding -- which may or may not be exactly correct -- is that
remove() and removeAll() signatures were typed wider, to allow for clients
(with less knowledge of specific type) to remove elements from collections
created with a more-specific type.

So the possibility I proposed, was to express this as a type expression.
For reference types, it would resolve as before;  for value types, absent
any notion of inheritance, it would just flatten to the value type.

<CT compatible T> public boolean removeItem (CT item);
<CT compatible T> public boolean removeAll (Collection<CT> items);

Of course, syntax is just invented here :)


3)  General thoughts & new proposal on Method-Level vs Layers
--------------------------------------------------------------------------------------------

Essentially there are two ways to solve the kind of problems we're
discussing.
1)  annotations & type-expression syntaxes, at the method level
2)  groups of the above, as a "Layer".

I'm now going to propose a third alternative, for consideration:
3)  method level, using shared type-expressions visible only within the
class.

public interface ListLike <T> {
    protected type CT compatible T;     // type-expression shared across
methods, but not public
    public boolean removeItem (CT item);
    public boolean removeAll (Collection<CT> items);
}

This third alternative achieves "sharing" similar to Layers/Peeling of type
expressions, while keeping method declarations & annotations independent.

We would gain some of the benefits of layering, but only introduce a new
member type -- which can be ignored for almost all other purposes -- rather
than a major structural level.


4)  Combinatorial & Utility-class drawbacks to Layering
-------------------------------------------------------------------------------

Layers/Peeling have been proposed as an approach, initially for classes
genericized on one type-parameter. I'm not super mathematical/ or an expert
on this, but I wonder if there are some potential problems:

1)  Classes parameterized on >1 parameter, are going to suffer a
combinatorial explosion of layer signatures.
- whereas the actual requirement to specialize on, is typically going to be
one (or occasionally two) of those type-parameters.
- layering<X,Y,Z> selectors when we wish to target <X> or <X,Y> will be
awkward and ugly.

I think it may be the case that method-specific type expressions, may be
easier & more efficient to correctly express our requirements for classes
genericized on >1 parameter.

2)  Utility classes which genericize individual methods/ or groups of
methods, rather than being generically typed themselves.
- Layering as proposed, applies only within the class-level.
- Layering as proposed, also requires a type-parameter to genericize on.
- generics in Java are currently perfectly usable at the method level.
- should we be ruling out specialization entirely, in all perpetuity, for
utility classes/ and individual methods?

I know nobody to date has proposed/ or envisaged specializing static
methods. We've all been thinking about collections.

But should we/ do we actually need to permanently rule this out? It may be
"a scope too far" for this iteration, but I think it's an interesting
question.


5)  Map<int>.get() and "sentinel values"
--------------------------------------------------------

You misunderstand. 'Sentinel' or special values have two purposes:
1)  for APIs, to return "nothing present";
2)  for internals, to store "nothing present".

We are both largely against the second use. But, for a large number of uses
Map.get() returning 'null' works great.

There is much code already -- Map.get() -- returning a sentinel for "not
found". My proposal is to expressly recognize that; and ensure that better
values than 0 are used.

My initial proposal was to use -1;  not perfect I agree, but the bulk of C
library APIs has been happy to do without this number for a very long time
:) However, I'm happy to revise it to Integer.MIN_VALUE. 'double' could use
either MIN_VALUE or NaN. 'boolean' will have false, and that's the best we
can do.

Since efficiency is the main reason to specialize, we shouldn't require
Map.get()'s single-word return to be "blown out" to two; nor should
wrapping in Optional be required.

Unless we're going to drop Map.get() from the API, which we shouldn't, a
sentinel is proveably the only solution.

As with Objects, anybody who actually needs to distinguish
Integer.MIN_VALUE from "not present" in Map<?,int> can use the same
approaches as present:
1)  check containsKey() first, then call get()
2)  use getOrDefault()
3)  "mask" the sentinel with another value.

Usage of the sentinel (for single-return APIs, or -- less recommended --
for internal storage) will be up to the collection author.

Given the efficiency of a single machine-word, rather than two, and the
absence of multiple-returns or out-parameters from the Java language, this
solution is sane, efficient & suitable for performant use.


6)  "Syntax digressions"
-----------------------------------

My point was to propose _clean and meaningful syntax_ as part of the
mechanism -- rather than having us discuss horrible hacks like (cast)null.

I'm also suggesting that perhaps, 'null' might become invalid syntax --
having to being explicitly replaced by either of the two meaningful uses
for it, 'emptyValue' or 'sentinelValue'.


7)  </Rant off>
--------------------

Well, it's good that we are introducing some FP functionality into Java. My
rant came from deep & long-held feelings and experience.

There has been, I guess, an amazing blindness in refusal to address
null-handling. Many application developers spend 10% of their lives
cleaning up other people's null-handling.

I, however, had it sorted. I had beautiful syntax. I had perfect naming. I
had it sweet..  Optional.eq() was what i called it :)

It's good that we've finally got java.util.Objects, with an
Objects.equals() method; soon, we'll no longer need to be 6-compatible and
can actually use that class.

Here are some constructive suggestions, based on what I actually did:
- Objects.text() method returning "" rather than "null", is extremely
useful.
- eqNoCase() also very useful for business applications.

Thanks for your good work on FP.. I know it's not all complete yet.
(Optional -> Stream of 0/1 is yet lacking). See:
http://stackoverflow.com/questions/22725537/using-java-8s-optional-with-streamflatmap


8)  ArrayList<boolean> & custom specialization
---------------------------------------------------------------------

We shouldn't be trying to specialize this down to the 'bit' level --
machine addressing runs at the byte level only.

I'm largely against custom specializations -- there's a perfectly good
Class mechanism to let more-specific implementations of an interface be
provided. For example, you can implement a collection based on BitSet.

-------------------------

Thanks Brian & Timo for your feedback, I appreciate everyone's thoughts.
Merry Christmas everybody & enjoy the holidays!


Regards,
Thomas Whitmore


More information about the valhalla-dev mailing list