On 02/13/2015 11:02 AM, Paul Sandoz wrote:
Hi,

I am not sure everyone is aware of the sandbox repo that was setup, but it's 
rather handy to see the changes:

   http://hg.openjdk.java.net/jdk9/sandbox/jdk/rev/9a02f23ca186

On Feb 12, 2015, at 11:02 PM, Roger Riggs <roger.ri...@oracle.com> wrote:

Hi,

The Process and ProcessHandle API javadoc has been updated with the comments
and suggestions including the loose coupling of the Process from the 
CompletableFutures
that are linked to process termination.
The improved implementation from Peter is incorporated and the method 
descriptions
updated to reflect its behavior.

Updated javadoc:   http://cr.openjdk.java.net/~rriggs/ph-apidraft/

I ran into a issue with the generics on CompletableFuture<? extends...> 
completableFuture()
in ProcessHandle and Process.
The JDK compiles fine but the javac has a problem with the assignment in a test.
I'll come back to it after a long weekend in a warmer climate.

The use of wild cards in this context is generally discouraged because it 
propagates to the caller as you have found out. You cannot do what you want for 
the same reasons you cannot do this:

   List<? extends Number> len = Arrays.asList(1, 2, 3);

   // As this point we do not know the lower bound of elements in len
   // Is it Integer or is it BigInteger?
   List<Number> ln = len;  // error
   ln.add(new BigInteger(...)); // Potential heap pollution

Which means you are stuck if you want to provide CF<Process> and 
CF<ProcessHandle> using the same overloaded method name.


It *is* inconvenient for the user to have to use wildcards in specifying types:

CompletableFuture<? extends Process> cf = process.completableFuture();

...but it doesn't hinder the use of above 'cf' quite so much as 'len' in List example above, since 'T' in CompletableFuture<T> is used mostly in co-variant positions. The only methods that use it in contra-variant positions are:

cf.getNow(?);
cf.complete(?);
cf.obtrudeValue(?);

of which I can imagine only the 1st one to be useful in ProcessHandle/Process situations and even that one only with 'null' as the argument which is allowed.

Other methods taking functions behave correctly with CompletableFuture<? extends Process>, for example:

    CompletableFuture<? extends Process> cf = process.completableFuture();

    cf.handle((p, ex) -> {
        p....
    });

So it really boils down to what is less inconvenient: using wildcards in type specifications or casting in cases like:

    CompletableFuture<ProcessHandle> cf = process.completableFuture();

    cf.handle((ph, ex) -> {
        Process p = (Process) ph;
        p....
    });


Regards, Peter



You could do:

   abstract class ProcessHandle<T extends ProcessHandle<T>> {
       CompletableFuture<T> completableFuture() { ... }
   }

   class Process extends ProcessHandle<Process> {
       CompletableFuture<Process> completableFuture() { ... }
   }

But i am not sure it's worth it, especially as it exposes the sub-type of 
process handle.

Paul.

Suggestions appreciated, Roger


p.s.

ws/jdk9-sandbox/jdk/test/java/lang/ProcessHandle/CompletionTest.java:67: error: 
incompatible types: CompletableFuture<CAP#1> cannot be converted to 
CompletableFuture<Process>
                CompletableFuture<Process> future = p.completableFuture();
^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends ProcessHandle from capture of ? extends ProcessHandle

Reply via email to