tag:blogger.com,1999:blog-8678405.post7765886453140779713..comments2023-09-02T15:54:52.482+01:00Comments on Ricky's technical blog: Improving Your Visitors, and a Request For More Autoboxing in Java 7Ricky Clarksonhttp://www.blogger.com/profile/13845104548520132930noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-8678405.post-32980180970559968862007-06-17T23:00:00.000+01:002007-06-17T23:00:00.000+01:00The current PEC that I have released is pre-generi...The current PEC that I have released is pre-generics and pre-annotations and I am working on an improved version that will use both. However erasure is a pain for multiple dispatch and annotations have some problems for this application also.<BR/><BR/>RE erasure: I am still working on this one, I haven't found my ideal solution yet.<BR/><BR/>RE annotations: For many design patterns you want a type, e.g. Immutable, so that you can declare methods that deal with immutables or lists of immutables. Unfortunately annotations aren't types, they aren't inherited from interfaces, and you can't extend an annotation. Therefore the new design uses a mixture of annotations and marker interfaces.hlovatthttps://www.blogger.com/profile/07048859648718746436noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-91573520568947341532007-06-17T14:15:00.000+01:002007-06-17T14:15:00.000+01:00Howard, that seems like a reasonable implementatio...Howard, that seems like a reasonable implementation. I wonder why you didn't use annotations instead of interface inheritance, and why the compareTo has Object instead of T. Is there a technical limitation, or is it just that it was written before Java 5?<BR/><BR/>I'm not sure that I've used a statically-typed system that supports dynamic dispatch other than using the visitor pattern, so I have nothing to compare your implementation to. It reminds me of how RIFE implements continuations though.Ricky Clarksonhttps://www.blogger.com/profile/13845104548520132930noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-54653411825815589322007-06-17T02:09:00.000+01:002007-06-17T02:09:00.000+01:00Here is a multiple dispatch example using the PEC ...Here is a multiple dispatch example using the PEC compiler. The PEC compiler uses interfaces as markers, in this case the marker is MultipleDispatch. Also the PEC compiler introduces **no** new syntax, so you need to add dummy methods that act as place holders. (Both these restrictions might change in a future version of PEC.)<BR/><BR/>First define an interface with multiple dispatch methods:<BR/><BR/>interface Numeric extends MDEquatable, MDComparable, MultipleDispatch {<BR/>__Numeric plus( Numeric rhs );<BR/><BR/>__Numeric minus( Numeric rhs );<BR/><BR/>__Numeric times( Numeric rhs );<BR/><BR/>__Numeric divide( Numeric rhs );<BR/>}<BR/><BR/>MDEquatable give a multiple dispatch equals method and similarly MDComparable a multiple dispatch compare to. As mentioned above the interface MultipleDispatch marks the methods as using multiple dispatch. Then define an abstract class that contains the dummy methods needed to keep the code source conforming to standard Java and hence allow interoperation with existing code and existing tools.<BR/><BR/>public abstract class AbstractNumeric implements Numeric {<BR/>__// Dummy methods for Numeric - body replaced by compiler,<BR/>__// therefore body can be anything that will compile<BR/>__public final int compareTo( final Object notUsed ) { throw new AssertionError(); }<BR/><BR/>__// As above for equals, plus, minus, times, divide<BR/><BR/>__// Default methods for Numeric - the action to take if no closer match method is found<BR/>__// These are multiple dispatch methods and are therefore declared as static methods<BR/>__public static final boolean equals( final MDEquatable notUsed, final Object notUsed2 ) { <BR/>____return false; <BR/>__}<BR/><BR/>__public static final int compareTo( final Comparable lhs, final Object rhs ) {<BR/>____throw new ClassCastException( ( rhs == null ) <BR/>______? "Argument is null"<BR/>______: "No multiple-dispatch method that can compare " + lhs + " to " + rhs );<BR/>__}<BR/><BR/>__// No default methods for plus, minus, times, and divide - they throw IllegalArgumentException<BR/>}<BR/><BR/>Then you can write different implementations and put the methods in **any** class. The methods are declared as static methods and all arguments are explicit, since you dispatch on all arguments and the methods can be in any class. E.G. a Double type<BR/><BR/>public class DoubleMD extends AbstractNumeric {<BR/>__private final double value;<BR/><BR/>__public DoubleMD( final double value ) { this.value = value; }<BR/><BR/>__// Multiple-dispatch methods for DoubleMDs – note they are static methods<BR/>__public final static int compareTo( final DoubleMD lhs, final DoubleMD rhs ) {<BR/>____return Double.compare( lhs.value, rhs.value );<BR/>__}<BR/><BR/>__public final static boolean equals( final DoubleMD lhs, final DoubleMD rhs ) {<BR/>____return Double.compare( lhs.value, rhs.value ) == 0;<BR/>__}<BR/><BR/>__public final static Numeric plus( final DoubleMD lhs, final DoubleMD rhs ) {<BR/>____return new DoubleMD( lhs.value + rhs.value );<BR/>__}<BR/><BR/>__// minus, times, and divide are similar to plus above<BR/><BR/>__ // Other methods, e.g. normal single-dispatch methods<BR/>}<BR/><BR/>The DoubleMD class isn't that interesting on its own, but now suppose we add a Complex class:<BR/><BR/>public class ComplexMD extends AbstractNumeric {<BR/> __private final double real;<BR/> <BR/>__private final double imaginary;<BR/> <BR/> __public ComplexMD( final double real, final double imaginary ) {<BR/> ____this.real = real;<BR/> ____this.imaginary = imaginary;<BR/> __}<BR/> <BR/> __// Multiple-dispatch methods for ComplexMD and DoubleMD arguments in the **same** class<BR/> __public final static int compareTo( final DoubleMD lhs, final ComplexMD rhs ) {<BR/> ____return compareTo( new ComplexMD( lhs ), rhs );<BR/> __}<BR/> <BR/> __public final static int compareTo( final ComplexMD lhs, final DoubleMD rhs ) {<BR/> ____return compareTo( lhs, new ComplexMD( rhs ) );<BR/> __}<BR/> <BR/> __public final static int compareTo( final ComplexMD lhs, final ComplexMD rhs ) {<BR/> ____return Double.compare( lhs.abs(), rhs.abs() );<BR/> __}<BR/> <BR/> __// As above for equals, plus, minus, times, and divide<BR/><BR/>__// Other methods, e.g. normal single dispatch<BR/>}<BR/><BR/>Note:<BR/><BR/>1.That compareTo( DoubleMD, ... ) methods can be in ComplexMD, they don't have to be in DoubleMD.<BR/><BR/>2.How you can control the action of compareTo by having multiple methods with different argument types. <BR/><BR/>The code when run selects the best fit method on the basis of the actual type, not the declared type like normal overloading does, e.g.:<BR/><BR/>__Numeric d = new DoubleMD( 1 );<BR/>__Numeric c = new DoubleMD( 2, 3 );<BR/>__d.compareTo( c ); // calls compareTo( DoubleMD, ComplexMD )<BR/><BR/>With single dispatch the above call would call method compareTo( Numeric ) in DoubleMD because the receiver (hidden this) is of type DoubleMD and the argument, c, is declared as Numeric, the fact that c is a ComplexMD would be ignored. Hence in single dispatch the visitor pattern would be used, but the code for a visitor is obscure.<BR/><BR/>More info at:<BR/><BR/><A HREF="https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/multipledispatch/package-summary.html" REL="nofollow"><BR/>https://pec.dev.java.net/nonav/compile/javadoc/pec/compile/multipledispatch/package-summary.html<BR/></A><BR/><BR/>If any one tries out the PEC compiler let me know how you go (howard dot lovatt at iee dot org).hlovatthttps://www.blogger.com/profile/07048859648718746436noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-90503389555537993122007-06-17T00:39:00.000+01:002007-06-17T00:39:00.000+01:00In C3S the proposal is that if a method has type V...In C3S the proposal is that if a method has type Void (any method not just inner classes and not just generic return types) then return or falling off the end is equivalent to return null. I think this is a nice solution, but like all extensions to Java you not only have to ask whether the solution works but also if it is worth it.<BR/><BR/>I included the idea in C3S because I thought it was worth it. But many other people feel that too many changes are proposed.hlovatthttps://www.blogger.com/profile/07048859648718746436noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-58704405844119601992007-06-16T19:17:00.000+01:002007-06-16T19:17:00.000+01:00After I submitted the RFE, Alex Buckley (Java 7 le...After I submitted the RFE, Alex Buckley (Java 7 lead) sent an email - here's a portion:<BR/><BR/>"I don't want to touch generics, so need to keep Void as the type arg and then omit 'return null' on Void methods."<BR/><BR/>I think I agree.Ricky Clarksonhttps://www.blogger.com/profile/13845104548520132930noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-16320233366676644252007-06-16T13:49:00.000+01:002007-06-16T13:49:00.000+01:00Well, void is no type (yet) and would be the first...Well, void is no type (yet) and would be the first primitive type to be nullable (which is its only value, of course). <BR/>For returning one could make "return" be an alias for "return null", so this could work, too.<BR/>Not sure, if null is the same as void, though. And the result of a Void method is assignable while a void method isn't (yet).Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-8678405.post-85750795952904865302007-06-15T22:45:00.000+01:002007-06-15T22:45:00.000+01:00A field of type void is hardly a problem. There's ...A field of type void is hardly a problem. There's already a Void parameter after all. There's just no way to instantiate it to anything non-null.David R. MacIverhttps://www.blogger.com/profile/17522579015536144620noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-89212879911695940732007-06-15T18:41:00.000+01:002007-06-15T18:41:00.000+01:00I'd say, allowing void as Generic Parameter would ...I'd say, allowing void as Generic Parameter would be a bit tricky:<BR/><BR/>class Holder<T> {<BR/>´ ´ private T t;<BR/>´ ´ public T get() {<BR/>´ ´ ´ ´ return t;<BR/>´ ´ }<BR/>}<BR/>new Holder<void>();<BR/><BR/>which would introduce a field of type void and return from within a void method.<BR/>Optional return on Void might work better.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-8678405.post-7322597740894569442007-06-15T04:34:00.000+01:002007-06-15T04:34:00.000+01:00See javax.lang.model packages for visitors like th...See javax.lang.model packages for visitors like this which allow <Void> as a return type.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-8678405.post-56525122015132729242007-06-14T21:37:00.000+01:002007-06-14T21:37:00.000+01:00I've used pattern matching in Haskell before, but ...I've used pattern matching in Haskell before, but it seems more useful for things that are not expressed in types, than for dispatch based on type.<BR/><BR/>I like Common Lisp's dynamic dispatch support.<BR/><BR/>(defclass card () ())<BR/>(defclass computer () ())<BR/>(defmethod draw ((card card)) "drawing a card")<BR/>(defmethod draw ((computer computer)) "drawing a computer")<BR/><BR/>> (draw (make-instance 'computer))<BR/>"drawing a computer"<BR/><BR/>The same syntax works for multiple parameters. I like it because it eliminates the choice as to which class a method that operates on two types goes in.<BR/><BR/>Alex Buckley suggested that I file an RFE, here it is: <A HREF="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6569520" REL="nofollow">http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6569520</A>Ricky Clarksonhttps://www.blogger.com/profile/13845104548520132930noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-75880758073291010312007-06-14T10:02:00.000+01:002007-06-14T10:02:00.000+01:00I second the call for multiple dispatch. Visitor p...I second the call for multiple dispatch. Visitor patterns are an amazingly ugly way of faking a worse version of multiple dispatch. :-) (indeed I generally don't even write them in favour of using instanceof checks for specialisation)<BR/><BR/>The only problem with introducing multiple dispatch to Java would be the potential for really really subtle bugs with legacy code - all previous code will still be valid, it just might do something very slightly different. Maybe a @Multiple annotation. (Gee, is it just my imagination or do all these "It would be great if we had an annotation which would let me do Foo" comments sound like "It would be great if we had an annotation driven macro system").<BR/><BR/>Properly working Void type parameters allowing void return types are clearly a good idea though, yes. Primitive type parameters would be nice too.David R. MacIverhttps://www.blogger.com/profile/17522579015536144620noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-56611735647624546622007-06-14T05:35:00.000+01:002007-06-14T05:35:00.000+01:00Two comments:1. C3S infers type Void for all metho...Two comments:<BR/><BR/>1. C3S infers type Void for all methods not just inner classes/closures, i.e. it does what you want. Rule 13 in:<BR/><BR/><A HREF="http://www.artima.com/weblogs/viewpost.jsp?thread=182412" REL="nofollow"><BR/>http://www.artima.com/weblogs/viewpost.jsp?thread=182412<BR/></A><BR/><BR/>2. The pattern enforcing compiler has multiple dispatch as a pattern. Multiple dispatch is easier to follow than visitor.<BR/><BR/><A HREF="http://pec.dev.java.net/nonav/compile/index.html" REL="nofollow"><BR/>http://pec.dev.java.net/nonav/compile/index.html<BR/></A>hlovatthttps://www.blogger.com/profile/07048859648718746436noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-50536535565455447772007-06-13T11:07:00.000+01:002007-06-13T11:07:00.000+01:00Talking about improvements to Visitor, another tec...Talking about improvements to Visitor, another technique that is used in functional languages is Pattern Matching. Scala implements a more powerful Visitor through case classes and pattern matching. And since Scala runs on the JVM, you can get the benefits of an improved Visitor through much less boilerplates.<BR/>Just another thought ..Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-24788967471041105932007-06-13T07:07:00.000+01:002007-06-13T07:07:00.000+01:00Neal, does it allow the same for an ordinary metho...Neal, does it allow the same for an ordinary method (i.e., not a closure)? What I'd like is:<BR/><BR/>public Void x() { }<BR/><BR/>or<BR/><BR/>'void' as a valid type parameter.Ricky Clarksonhttps://www.blogger.com/profile/13845104548520132930noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-64720812963246795972007-06-13T06:47:00.000+01:002007-06-13T06:47:00.000+01:00The current closure spec allows you to elide the r...The current closure spec allows you to elide the result expression if the closure result type is Void. It's the first sub-bullet in the section entitled "Closure Conversion".Neal Gafterhttps://www.blogger.com/profile/08579466817032124881noreply@blogger.comtag:blogger.com,1999:blog-8678405.post-26562781907251556432007-06-13T04:47:00.000+01:002007-06-13T04:47:00.000+01:00Nice post. It would be nice syntactic sugar if for...Nice post. It would be nice syntactic sugar if for all methods that return "Void", a 'return null' was inserted automatically as necessary.swankjessehttps://www.blogger.com/profile/04905794974441087900noreply@blogger.com