The Source for Java Technology Collaboration
User: Password:



Rémi Forax

Rémi Forax's Blog

Synchronized or confined

Posted by forax on September 17, 2006 at 01:01 PM | Comments (16)

A new version of the closure proposal has been post at the end of this week by Neal Gafter and proposes in section 3 to tag parameter with a special keyword to differenciate between synchonous and asychronous closure.

For me this section contains two flaws, the first one is that the keyword used is synchronized, the second one is to not recognize that such feature can be usefull in other contexts than closure.

In the Java API, there are existing methods that take an object as argument and don't allow to store this object in a field, by example, startElement/endElement of SAX handler or RowFilter.include().
I think a unique keyword can be used in all this cases.

Now, why not using synchronized for that ?
synchronized means thread, threading model, memory model, etc. This keyword is so important that it can't be reused to express something totally different without complexified something that is already not obvious.
I think that using an annotation in this case is better. You can name it as you want, there is already a reflexion support. I propose @Confined because the reference can't escape.

The following code shows the usage of @Confined with closure :

  public static <T> void forEach(Iterable<? extends T> iterable,@Confined void(T) func) {
    for(T item:iterable)
      func(item);
  }
  ...
  List<Integer> list=Arrays.asList(2,4,6);
  int result=0;
  forEach(list,(int value){
    result+=value;
  });
  System.out.println(result);

Rémi

With one breath, with one flow
You will know
Synchronicity
                             --- Synchronicity / Police

Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Remi, I wonder what do you think of idea to allow to annotation metadata on closures? E.g. something like this:


    void sayHello(java.util.concurrent.Executor ex) {
    ex.execute(@ThreadSafe (){ System.out.println("hello"); });
    }

    Posted by: euxx on September 17, 2006 at 11:47 PM

  • I say stick with inner classes - it is much simpler. If you want to add access to a non-final local then wrap in a tuple, this could be automatic (like C# 3.0), i.e. for your example the compiler would generate:

    List list = Arrays.asList( 2, 4, 6 );
    final Ti result = new Ti( 0 );
    forEach( list, new Functionii() {
    public int call( final int value ) { result.e1 += value; }
    } );
    System.out.println( result.e1 );

    Where Ti is tuple class (wrapper) of one integer element (called e1) and Functionii is an interface containing a method with an int argument and int return called call. You could add syntactic sugar, e.g.:

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6389769

    Your example using this style syntax might be:

    var list = Arrays.asList( 2, 4, 6);
    var result = 0;
    forEach( list, ( value ) result += value; );
    System.out.println( result );

    Which is shorter, and I would say sweeter, than the closure syntax. If you allowed trailing inner classes after the closing bracket, as proposed for closures, then it might be:

    var list = Arrays.asList( 2, 4, 6);
    var result = 0;
    forEach( list ) ( value ) result += value;
    System.out.println( result );

    Which is excellent syntax and no new concepts and therefore considerably simpler than using closures. Also note that the runtime can use escape analysis to distinguish between the use cases of synchronous and asynchronous and can also inline the methods, therefore execution time will be similar for the two proposals.

    Posted by: hlovatt on September 18, 2006 at 04:43 PM


  • Hi eugene, it's technically possible but i can't see a example where it's usefull.
    Do you have a real case ?

    @hlovatt, i've already answer to you about your syntax,
    this syntax is not inferable in Java.
    Remember that Java has


    overloaded operators like + or *
    performs auto[un]boxing.


    Futhermore, tuples are not necessary here because local variables can be
    store in fields of the closure class.


    List<Integer> list = Arrays.asList( 2, 4, 6 );
    Functionii function=new Functionii() {
    int result=0;
    public void call( Integer value ) { result += value; }
    };
    forEach( list, function);
    System.out.println( function.result );


    The compiler inferes if the closure is confined or not.
    @Confined is used when you want to write a method like forEach(),
    to express the fact that this method accepts all kind of closures
    even the one that changes local variables (synchronous closure).

    The compiler verifies that confined closure or more generally confined
    references are not stored in a field.

    Rémi

    Posted by: forax on September 19, 2006 at 03:18 AM

  • I wonder if you can combine the concepts of traits and closures, traits are rather like mixins, except that multiple mixins with methods of the same signature must be explicitly resolved when they are composed. Abstract traits are almost identical to Java interfaces.

    So we might have:

    trait Sum(Integer i) {
    void sum(Integer i) { result += i; }
    // or possibly void sum(Integer i) { setResult(i + getResult()); }
    }

    which can be added to classes:

    class Foo implements Sum {
    private int result;
    public Foo(int n) { result = n; }
    }

    which can be used as:

    Foo foo = new Foo(5);
    foo.sum(6);
    assert foo.result == 11;


    Traits may have parameters and this allows them to be curried:

    class Bar implements Sum(7) {
    private int result;
    public Bar(int n) { result = n; }
    }

    which can be used as:

    Bar bar = new Bar(5);
    bar.sum();
    assert bar.result == 12;


    and also as a closure:


    public static void forEach(Iterable iterable, VoidFunc func) {
    for(T item:iterable)
    func(item);
    }
    ...
    List list=Arrays.asList(2,4,6);
    int result=0;
    forEach(list,Sum);
    System.out.println(result);


    or even:

    forEach(list,Sum(int i) { result += i*i; } );

    As you can probably tell I haven't got the syntax or semantics fully sorted, but if it can be done then we could add two powerful language techniques to Java in one go.

    Posted by: m_r_atkinson on September 19, 2006 at 06:47 AM

  • Opps, my comment was truncated, trying again.

    and also as a closure:

    public static <T> void forEach(Iterable<? extends T> iterable, VoidFunc<T> func) {
    for(T item:iterable)
    func(item);
    }
    ...
    List<Integer> list=Arrays.asList(2,4,6);
    int result=0;
    forEach(list, Sum);
    System.out.println(result);


    or even:

    int sumSq=0;
    forEach(list, Sum(Integer value) { sumSq += value*value; } );


    In these cases Sum might have to be defined something like:

    trait <T> Sum(T i) extends VoidFunc<T> {
    void sum(T i) { result += i; }
    }


    as you can tell, I'm still working on the syntax and semantics. But if they can be combined then Java would get two powerful language features for the price of one.

    Posted by: m_r_atkinson on September 19, 2006 at 07:01 AM


  • forax, note that the synchronized (or @Confined or whatever) designation in the most recent proposal is because this version does not have function types. So your example isn't working off of the recent proposal. Rather, you need an interface with a single method that matches the signature, say like "synchronized Handler<T> handler" or something like that.

    I'm one of those who (so far) doesn't like function types, so I'm happier with this version. I've heard a good argument though that function types may provide the ability to provide static typing for decribing method signatures. I haven't thought enough about it, though. But from a closure perspective, it's much easier to define semantics (and JavaDocs) on interfaces. And it introduces fewer new features.

    Posted by: tompalmer on September 19, 2006 at 07:50 AM

  • -1 for closures. Anonymous classes are far more readable.

    Posted by: cowwoc on September 19, 2006 at 10:07 AM

  • cowwoc, I think anonymous classes are far _less_ readable. (But I think closures should be implemented behind the scenes merely as anonymous classes.) Battles of opinions here. I guess we'll see how it turns out.

    Posted by: tompalmer on September 19, 2006 at 10:42 AM

  • ...Good god help us! Please stop it with this closure non-sense. It buys little functionality outside of some convenience and only pollutes the language even further. Annotations are a bad enough of a "hack" to the language, let's stop ripping it apart and focus on more useful additions to the language, like better APIs.

    Posted by: alski on September 19, 2006 at 10:45 AM

  • I have to agree with the negative comments here. Anonymous classes already get us 90% of the way.
    I'd be all for closures if I didn't have to declare them, but declaring them makes it as bad as anonymous classes (almost). So I don't really see the benefit (maybe I'm stupid).
    Now with this talk about synchronized and confined you've convinced me that this is a direction we shouldn't take Java to. After all, the advantage of Java was that it was SIMPLER than C++.. not more obtuse!
    If you want to add something to the language, add something more original.. like some mechanism to make composition as easy as inheritance (since it seems to be more favored these days), or mechanisms to take advantage of SIMD instrucctions and multiprocessing.
    Finally, if you really like Ruby, use Ruby. If you really like C#, use C#. And if you really like Java, use Java... but don't make Java another collage language (we have Perl and C++ for that).

    Posted by: dog on September 19, 2006 at 01:14 PM

  • Remi, I think most of the annotations used by Brian Goetz in his "Java concurrency in practice" would be useful (at least for analysis, like one done by FindBugs, and other contract enforcement). Another example is @AsyncExecution, e.g. when caller don't expect immediate response and just need to go. There are some applications along clustering data and JEE transactionality (e.g. pass closure trough EJB boundaries)

    Posted by: euxx on September 19, 2006 at 02:41 PM

  • 100% agree with dog and alski on this one.

    Lets not destroy the simplicity of Java any more. It does the job and if it doesn't then use another language. I've been using Java for 10years and really can't see why people are supporting these ugly new features like annotations and generics. But how do we vote against them?

    At this rate we will need a Java-- just to restore cleaup the language spec. Heaven help us if Java goes open source.

    Peter

    Posted by: cork2005 on September 19, 2006 at 10:12 PM


  • ok, my through about allowing function types or using interfaces
    as type of closures are foggy at this time,
    i will prepare a new blog entry on that issue.

    @tompalmer, yes i have used the notation of the version 0.1. For me, @confined is independant to having or not function type.

    @m_r_atkinson, for me closure and mixin are to different features
    even if closure can be used to defined mixin.

    @cowwoc, the closure proposal is not a monolithic proposal,
    it could be just a new way to defined anonymous class.
    I hope it can be a little more.

    @dog, the way to write a sofware in 1995 in not the same than now. i don't see why programming languages can't evolve.

    @euxx, i have to confess that i haven't already read "Java concurrency in practice" but i see your point. An annotation like findBugs's CheckForNull can't be used on a result (return value) of a closure.

    @cork2005, you have been using Java for ten years and you don't see why generics or annotations exist ? i think you can
    take a look to EJB3 spec to see them in action.

    Posted by: forax on September 20, 2006 at 12:46 AM


  • @Remi,

    > @hlovatt, i've already answer to you about your syntax, this
    > syntax is not inferable in Java. ...

    I think the syntax (types) are inferable and will try and explain how. But first as an aside, both the closure proposal and mine require about the same level of inference (they are proposing auto boxing of closures into interfaces). Consider an interface and a method that uses this interface:

    interface Function1< R, A >{ R call( A a ); }
    static < T > void forEach( Collection< T > c, Function1< Void, T > f ) ...

    I propose that this method with short syntax could be used like:

    forEach( list ) ( value ) result += value;

    IE "( value ) result += value" is the definition of a Function1. The inference process is via simple textual substitution.

    Move the function inside the bracket: forEach( list, ( value ) result += value; );

    Add braces around the class and method definitions: forEach( list ) { ( value ) { result += value; } } );

    Copy from interface Function1 the return type, method name, argument types, and throws clause (it is obvoius what to copy since there is only one abstract method and the generic types, R and A, are taken from the definition of forEach): forEach( list, new Function1< Void, T >() { Void call( T value ) { result += value; } } );

    For return types of Void change return statements to return null and add a return null at the end if there is no terminating return already: forEach( list, new Function1< Void, T >() { Void call( T value ) { result += value; return null; } } );

    From the type of the list argument infer T: forEach( list, new Function1< Void, Integer >() { Void call( Integer value ) { result += value; return null; } } );

    Therefore I think the type can be infered; it is a bit more complicated than at present but many languages have sophisticated type inference, e.g. Haskel.

    > Futhermore, tuples are not necessary here because local
    > variables can be store in fields of the closure class.

    This is only true if the local variable is passed to only a single inner class. If it is passed to more than one inner class then either you have to pass the first inner class to subsequent inner classes or you use a tuple. I was proposing a tuple to keep it simple, same transformation for all inner classes, whether single or multiple.

    Posted by: hlovatt on September 21, 2006 at 05:11 PM


  • @hlovatt, let me summarize and correct me if i'm wrong,
    your point 3 says that the compiler can use the parameter types of the method of the interface to find the type of the parameter of the closure.
    I understand that but it only works with v0.2 of the proposal ;
    the one without function type.

    Bob Lee, Doug Lea and Josh Bloch write a
    document,
    i don't know if this document is antecedent or posterior
    to the Neal's posts, that seem to share your opinion.

    Posted by: forax on September 24, 2006 at 07:09 AM

  • @Remi,

    I hadn't seen the Lee, Lea, and Bloch proposal, so thanks for the reference. Thir ideas are very close to what I am proposing. Their last paragraph appears to say they are investigating whether it is possible to go even closer.

    Howard.

    Posted by: hlovatt on September 27, 2006 at 05:18 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds