The Artima Developer Community
Sponsored Link

Weblogs Forum
Clear, Consistent, and Concise Syntax (C3S) for Java

23 replies on 2 pages. Most recent reply: Apr 16, 2007 5:31 PM by Howard Lovatt

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 23 replies on 2 pages [ 1 2 | » ]
Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Clear, Consistent, and Concise Syntax (C3S) for Java (View in Weblogs)
Posted: Oct 27, 2006 4:09 AM
Reply to this message Reply
Summary
Many people think that inner classes in Java could be better; this Blog presents a new syntax that emphasizes Clarity, Consistency, and Conciseness (in that order!). An example usage is: withLock lock, method { out.println "Hello" };
Advertisement

Clear, Consistent, and Concise Syntax (C3S) for Java

Many people think that inner classes in Java could be better and many proposals have been put forward. However none of these proposals, including this author's, have really gained broad support. This Blog presents an alternative, building on and hopefully unifying past proposals, that emphasizes Clarity, Consistency, and Conciseness (in that order!). An example usage is: withLock lock, method{out.println "Hello"};

Like normal writing a program code should express intent clearly; you should not be left wondering what a line does and the compiler should not have to make assumptions that may or may not agree with the programmers assumptions. The language should be consistent; it should not have many similar concepts or syntaxes with usage overlap (a few general features are better than many specific features even if for some use cases the specific features are better than the general features). The syntax should be concise, since verbosity can obscure intent (not to save keystrokes). In the ideal world you would meet all three Cs (Clear, Consistent, and Concise), however the Cs are at times contradictory and a compromise has to be made. It is therefore important to prioritise the Cs and for a language like Java that aspires to ubiquity the priority order should be: Clear, Consistent, and Concise. Much of the Consistent constraint will be consistency with existing Java features and the existing Java syntax style, e.g. non-abbreviated keywords rather than symbols. The consistency constraint also precludes lifting syntax directly from other languages unless that syntax is similar in style to existing Java syntax. From the priority given it is obvious that I am not equating minimum typing with simplicity, however I am advocating conciseness because I think that in places the current verbosity obscures intent.

Previous proposals are summarized in a previous blog; telling comment on that blog about these proposals include: “... all of the syntax you've shown me is more painful than just doing without” (Todd Blanchard), “The heavy reliance on the correct use use of differently shaped brackets, colon and semi-colons is steadily reducing Java's scope from being a language for use by general programmers to a notation decipherable only by geeks” (Vincent O'Sullivan), and “All of the proposals are a bit painful syntactically” (Martin Odersky). These comments strike at the crux of the problem, the proposals are not Clear or Consistent. Also Neal Gafter pointed out in an email that there are more use cases than iterating over collections and therefore the examples given in the previous blog were not the complete story. The new proposal is in the Appendix 1, along with justifications, and three examples are given below: time, withLock, and each. It is hoped that this proposal unifies other proposals by adopting features from other proposals and by suggesting a staged introduction of features (see Appendix) and that the use cases are considered realistic.

Examples

Java time

Method time times a series of methods and reports their timings, and as is the case for all the examples I will present the current Java code first to provide a basis of comparison. Formatting of the example is close to what I use in practice; this choice of formatting although realistic is less concise than often shown in blogs and other example forums where an unrealistically short format is used to save space and also confer (sometimes inadvertently) simplicity. In my preferred style I declare variables final (except for ones that do change!); which is common (or mandatory) in functional languages, but unusual in Java. As an aside – take a look at your own code, I bet nearly all variables should be final so that it is clear to humans and machines that the variable is a pure declaration. This use of final in the example below is not because variables are passed to inner classes; though in some of the other examples it is necessary to use final.

Use:
    final Method0< R, RuntimeException > method1 = new Method0< R, RuntimeException >() { 
      public void call() { ... }
      public String toString() { return "Method1"; }
    } );
    final Method0< R, RuntimeException > method2 = new Method0< R, RuntimeException >() { 
      public void call() { ... }
      public String toString() { return "Method2"; }
    } );
    time( method1, method2 );

Given:
  public interface Method0< R, Ts extends Throwable > { R call() throws Ts; }
  ...
    public static < R, Ts extends Throwable > void time( final Method0< R, Ts >... methods ) throws Ts {
      for ( final Method0< R, Ts > m : methods ) {
        final long start = currentTimeMillis();
        final R result = m.call();
        final long end = currentTimeMillis();
        out.println( m + " returned " + result + " and took " + (end - start) + " ms." );
      }
    }

C3S time

The same example above in the new syntax is given below, the most striking features are the use of type inference and the new method declaration using the keyword method. The method declaration using a keyword is similar syntax to other languages, e.g. Javascript, however method is chosen instead of function because it emphasizes dynamic dispatch instead of a static binding.

Use:
    final method1 = Method0.new { 
      method call { ... }
      method toString { "Method1" }
    };
    final method2 = Method0.new { 
      method call { ... }
      method toString { "Method2" }
    };
    time method1, method2;

Or shorter:
    time new { 
      method call { ... }
      method toString { "Method1" }
    }, new { 
      method call { ... }
      method toString { "Method2" }
    };

Or shorter still:
    time enum { 
      Method1 { method { ... } },
      Method2 { method { ... } }
    }.values;

Given:
  public interface< R, Throwable... Ts > Method0 { method R call throws Ts }
  ...
    public static method< R, Throwable... Ts > void time( final Method0< R, Ts >... methods ) throws Ts {
      for ( final m : methods ) {
        final start = currentTimeMillis;
        final result = m.call;
        final end = currentTimeMillis;
        out.println m + " returned " + result + " and took " + (end - start) + " ms."
      }
    }

The new syntax is explained fully in Appendix 1. The most interesting aspects, not all of which are demonstrated above, are:

  • Keyword final infers a variables type (there is an equivalent keyword, declare, for non-final variables).

  • Keyword return as the last statement of a method may be omitted, even if it returns a value. If the method is of type Void (object not primitive) then the method always returns null, even if an explicit return or return value aren't given.

  • Keyword new follows the type and it uses a dot to closely associate it with the type in a manor similar to a static call. Keyword new can also be used for constructor declaration within a class and for creating instances of classes for method arguments. When used for constructor declarations constructor name, modifiers, argument types, and simple argument copy to fields are inferred by new. When used to create an instance for a class the type of the class to be created is inferred.

  • Keyword method identifies the block as a method block with the given arguments and body and also indicates object creation. The syntax mimics the established syntax for other blocks, e.g. if as in keyword brackets braces, and it uses a dot to closely associate it with the object type in a manor similar to a static call. Keyword method can also be used for method declaration within a class and for creating instances of classes for method arguments. When used within a class method name, method modifiers, and argument types are inferred by method. When used to create an instance for a method argument, method also infers the type of the class to be created.

  • Keywords enum, interface, and class can be used to declare anonymous types, as opposed to anonymous instances of anonymous types that new and method create. Static methods can be called on these anonymous types, as they can on anything of type Class. The notation Base.class { ... } declares an anonymous class type that extends Base, similarly enum and interface. If anonymous types are used in a method call the type to extend is inferred, like new and method.

  • Generic type declarations are unified to appear in the same position in a declaration, generalized to any declaration including variables, their syntax for common cases changed to shorter variable like declarations, and varargs for Throwables and derivatives are allowed.

  • The number of brackets and semicolons are reduced.

Java withLock

Method withLock allows the use of the new concurrent locks conveniently. Medium formatting is adopted in this example.

Use:
    withLock(lock, new Block0() {
      public Void call() { out.println( "Hello" ); } 
    });

Given:
  public interface Block0extends Throwable> extends Method0 {}
  ...
    public static extends Throwable> void withLock(Lock lock, Block0 block) throws Ts {
      try {
        lock.lock();
        block.call();
      }
      finally { lock.unlock }
    }

C3S withLock

Use:
    withLock lock, method { out.println "Hello" };

Given:
  public interface Block0 extends Method0<Void, Ts> {}
  ...
    public static method void withLock(Lock lock, Block0 block) throws Ts {
      try {
        lock.lock;
        block.call
      }
      finally { lock.unlock }
    }

Java each

Method each steps through each item in a collection. The example assumes that collections are given new members functions (i.e. each) and given vararg constructors. (However, modifying the collections library is really a separate issue to C3S.) The example uses short names and is shown with minimum white space and it inlines definitions. I don't consider this extra short formatting realistic; but it is used in other blogs, some people prefer it, and a proposal must look OK in many different formatting styles.

Use:
    final ArrayList list=new ArrayList(1,2,3);
    final Tuple1 sum=new Tuple1(0);
    list.each(new Block1(){
      public void call(x){sum.e1+=x;}
    });

Given:
  public class Tuple1{
    public E1 e1;
Tuple1(E1 e1){this.e1=e1;}
  }
  ...
  public interface Block1extends Throwable>extends Method1{}
  ...
    public extends Throwable> void each(Block1 b)throws Ts{
      for(E e:es){b.call(e)}
    }

C3S each

Use:
    final list=ArrayList.new(1,2,3);
    declare sum=0;
    list.each method(x){sum+=x};

Given:
  ...
    public method void each(Method1.interface{} b)throws Ts{
      for(final e:es){b.call(e)}
    }

Summary

Whilst the syntax proposed is not the shortest possible; I think it is the best proposal to date because it balances: Clarity, Consistency, and Conciseness and because it unifies previous proposals. The syntax synergy of the proposal is demonstrated in the table below (syntax in table slightly simplified to keep table short).

Table 1: Syntax Synergy in C3S

Example

Keywords

Comment

Modifiersopt Keyword< ... >opt Typeopt Nameopt Extrasopt ( ... )opt { ... ; ... }

Standard Template

             if                                         ( ... )    { ... ; ... }

if, for, while

Loops and Branches

Modifiersopt class< ... >opt          Nameopt Extrasopt             { ... ; ... }

class, interface, enum

Type Declarations

Modifiersopt method< ... >opt  Typeopt Nameopt Extrasopt ( ... )opt { ... ; ... }

method, new

Method and Constructor Declarations Inside Type Declarations

Modifiersopt final< ... >opt   Typeopt Name                           ... , ... ;

final, declare

Fields, Locals, and Arguments

     Type.optKeyword< ... >opt Typeopt Nameopt Extrasopt ( ... )opt { ... ; ... }

Qualified Template

     Type.optinterface                                             { ... ; ... }

class, interface, enum

Anonymous Type Declaration

     Type.optmethod< ... >opt  Typeopt Nameopt Extrasopt ( ... )opt { ... ; ... }
new, method

Anonymous Instance as Method Arguments or Variable Assignment

What do other people think – is this syntax an improvement on the other proposals? Does this proposal unify the other proposals?

Appendix 1 – C3S Rules

Stage 1

The concept is to implement stage 1 rules and then see if stage 2 suggestions are still considered necessary.

Rule 0: For a method call allow brackets, (), to be omitted if there are no arguments and for the last call in a chain of Top Level calls (method, constructor, or modified new, see Rules 2 and 3 below); provided that the call isn't ambiguous with respect to a field. Top Level means the call isn't an argument to another call. Note braces start a new statement with a new top level. The last call means that for the top level calls only: it is either the only call (and that call isn't qualified) or it is the call following the last dot. The last call rule means it must follow the last dot, even if that dot is a qualifier dot rather than a call dot; so that an integer argument is distinct from a real argument (see last example Rule 3). This rule is more concise. E.g.:

     size = list.size;
     list.set 0, 'A';
     list.add( 'A' ).add 'B';
     list.add string.charAt( 0 );

Rule 1: Allow final and a new keyword, declare, to infer the type of a declaration based on the initial value. If no initial value is given or the value is given as null then the type must be specified as normal (also the declare keyword may be used like final is currently used). Function arguments are as is, except that declare may prefix the declaration to emphasize that the parameter isn't final. To specify primitives the type must explicitly be given, see first example below. Generic arguments follow the keyword and are useful for recursive or repeated types. This rule improves clarity by using a keyword, consistency by always using a keyword and allowing generic parameters, and conciseness of by allowing type inference. E.g. (also see rules 2 and 3 for new new notation):

     declare sum = 0; // Integer, for int use: int sum = 0 or declare int sum = 0
     final< X > Tuple2< X, X > duplicate; // Not the same as Tuple< ?, ? >!
     declare strings = ArrayList< String >.new.add "A";
     final strings = ArrayList< String >.new;

Rule 2: Allow new to be used as a qualifier with a . (dot) like a static method call (but generic arguments retain their normal position after the type) instead of as a prefix operator. This rule improves readability and hence clarity since it tightly associated with the type, is more consistent with the rest of Java, and (importantly) enables Rule 3. E.g.:

     declare strings = ArrayList< String >.new( "a", "b", "c" ); // Assuming ArrayList had a vararg constructor!
     declare numbers = (T[])Number.new[ 1 ]; // where T extends Number

Rule 3: Allow new to infer generic type from constructor argument and use <> to mean a raw type. This rule considerably shortens generic declarations and also instances of anonymous inner classes. E.g.:

     declare strings = ArrayList<>.new; // Explicit raw type
     final strings = ArrayList< String >.new; // Explicit generic type
     final strings = ArrayList.new( "a", "b", "c" ); // Inferred generic type, assuming vararg constructor

Rule 4: Allow new to declare constructors in classes and to infer argument types from fields of the same name if no argument types are given (like final and declare do for variables – see Rule 1). If argument names are given without qualification and body is given as default then infer a simple Assignment of arguments to fields. This inferring of Assignment is similar default functionality to ML, Scala, and Fortress, but is more flexible since multiple constructors with different access and annotation modifiers are possible. Inside an instance method the notation this.new( ... )opt may be used. This use of new improves clarity since new is a keyword, improves consistency since it emphasizes the similarity between constructors and static methods and is consistent with the new use of .new after a type name (Rule 2), and is more concise. E.g. (also see Rule 5 for omitting trailing ; and Rule 15 for position of generic arguments):

     class< E1 > T1 {
       declare E1 i;
       new( final E1 i ) { this.i = i }
     }

     class< E1 > T1 {
       declare E1 i;
       new( final i ) { this.i = i } // Infer argument type from field
     }

     class< E1 > T1 {
       declare E1 i;
       new( i ) { default } // Infer argument type from field and infer copy of argument into field
     }

Rule 5: If an expression ends in } then there is no need for ; before the brace (like , in array initializers and also note , at end of argument lists is an error). IE treat ; as a statement separator rather than a statement terminator. This rule helps the readability of instances of anonymous classes and encourages braces to always be used even if a single statement is possible. E.g.:

     if ( end ) { break }

Rule 6: Introduce a new keyword, method, for declaring methods which is syntactically placed just before any generic parameters (i.e. Immediately after annotations and modifiers). If the method overrides a method then optionally infer @Override, other modifiers, return type, method argument types, and throws clause. If there is only one method to override then the method name can be inferred. If the method has no arguments the brackets may be omitted. This new keyword is clearer because it is a keyword, is more consistent because other declarations have keywords, and is more concise because it allows inference. E.g. (also see Rule 9 for new generic type syntax and Rule 12 for omitting keyword return):

     public static method< K, V > Map< K, V > unmodifiableMap( Map< K ?, V ? > map ) ...
     method toString { "Hello" }

Rule 7: Keyword, method, can also be used with a type followed by a dot notation to be a shorthand for creating an anonymous instance of an anonymous inner class. This new syntax is clearer because its intent is not obscured by verbosity, is more consistent because its syntax is like other blocks (e.g. if), and is more concise because of inference. E.g.:

     final action = AbstractAction.method ( final notUsed ) {
       controller.updateAllViews updateModel
     };

Rule 8: Keyword, method, can also be used to create anonymous instances of anonymous inner classes without a type and a dot notation if the type can be inferred from a methods arguments. This new syntax is clearer because its intent is not obscured by verbosity, is more consistent because its syntax is like other blocks (e.g. if), and is more concise because of inference. E.g.:

     final button = JButton.new method ( final notUsed ) {
       controller.updateAllViews updateModel
     };

Rule 9: Allow extends type generic arguments to be shortened to < Type name > (i.e. like normal variable declarations), e.g.:

     public static method< K, V > Map< K, V > unmodifiableMap( Map< K ?, V ? > map ) ...
     public class Enum< Enum< E > E > ...
 
   Which are equivalent to
     public static < K, V > Map< K, V > unmodifiableMap( Map< ? extends K, ? extends K > map ) ...
     public class Enum< E extends Enum< E > > ...

Rule 10: A throws clause can be empty, which means the method doesn't throw anything (equivalent to an absent throws clause). This is useful in conjunction with generics, see Rule 11 below. E.g.:

     method Void call() throws;

Rule 11: Generics are extended to allow varargs (only for use with Throwables and derivatives). An empty generics varargs list is allowed and it is equivalent to an absent throws clause (note Rule 10 above). E.g.:

     method< R, Throwable... Ts > R call() throws Ts;

Rule 12: Keyword return may be omitted for last line of a method and the returned value is the value of the last expression, e.g.:

     method toString { "Hello" };

Rule 13: If a method returns a Void, then make the end of a method without a return and a return without an argument synonymous with return null. E.g. the following are identical.

   Given:
     interface< Throwable... Ts > Block0 extends Method0< Void, Throwable... Ts > {}
   
  Then:
     final block = Block0.method {};
     final block = Block0.method { return };
     final block = Block0.method { return null };
     final block = Block0.new {
       method { return null }
     };
     final block = Block0.new {
       @Override method call { return null }
     };
     final block = Block0.new {
       method call { return null }
     };
     final Block0< RuntimeException > block = new Block0< RuntimeException >() {
       Void call() { return null; }
     };

  Are all the same.

Rule 14: Non-final locals that are referenced by an inner class are automatically wrapped in a final-tuple instance, like C# 3.0 does. Note: special treatment, name mangled temporary required, of non-final arguments is needed (not shown in example below). E.g.:

   Given:
     public class< E1 > Tuple1 {
       public E1 e1;
       public new( e1 ) { default }
     }
     public class< E1, E2 > Tuple2 extends Tuple1< E1 > ...
     public interface< R, A1, Throwable... Ts > Method1 { R call( A1 a1 ) throws Ts }
     public interface< A1, Throwable... Ts > Predicate1 extends Method1< Boolean, A1, Ts > {}
     ...
       public static method< T, Throwable... Ts > List< T > select( final Iterable< T > c, final Predicate1< T ?, Ts > f ) throws Ts ...
   
  Then:
     final beginning = "Fred";
     final names = ArrayList.new "Frederick";
     final filtered = names.select method ( name ) { name.startsWith beginning };
   
  Which is equivalent to the following verbose version:
     final Tuple1< String > beginning = new Tuple1< String >( "Fred" );
     ArrayList< String > names = (new ArrayList< String >( "Frederick" ));
     ArrayList< String > filtered = names.select( new Predicate1< String >() {
       public Boolean call( final String name ) {
         return name.startsWith( beginning.e1 );
       }
     } );

Rule 15: Allow generic parameters to follow keyword for class and interface, i.e. like method and like Type[] for arrays. This improves consistency since in some circumstances it cannot follow the name, e.g. method declarations. E.g.:

     public class< E1 > Tuple1 {
       public E1 e1;
       public new( e1 ) { default }
     }

Rule 16: Allow anonymous type declarations, TypeToExtend.optclass { ... }, for class, interface, and enum. This is intentionally similar syntax to anonymous instances of anonymous classes, i.e.: similar syntax to Type.optnew ( ... )opt { ... } and Type.optmethod ( ... )opt { ... }. If used as an initializer for a variable the type is inferred. as Class< $1 >. If used as a method argument the type to extend may be inferred. This is a useful generalization of the notion of creating anonymous instances of anonymous classes to the creation of anonymous types. E.g. (also see Rule 17):

    public method< Throwable... Ts > void each( final Method1< Void, E, Ts >.interface{} b )throws Ts {
      for ( final e : es ) { b.call( e ) }
    }

    final singleton = Method0.enum { // Singleton is of type Class< $1 > where $1 implements Method0 and is an Enum
      Method1 { method { ... } },
      Method2 { method { ... } }
    };
    time singleton.values;

    time enum { // Infer Method0
      Method1 { method { ... } },
      Method2 { method { ... } }
    }.values;

Rule 17: Allow static methods to be called on variables of type Class< T > using the normal dot notation. This is consistent with the concept that static members are what other languages call class members, e.g. smalltalk. E.g. (also see Rule 16):

    final singleton = Method0.enum { // Singleton is of type Class< $1 > where $1 implements Method0 and is an Enum
      Method1 { method { ... } },
      Method2 { method { ... } }
    };
    time singleton.values;

Rule 18: Allow variable declarations . E.g.:

    final singleton = Method0.enum { // Singleton is of type Class< $1 > where $1 implements Method0 and is an Enum
      Method1 { method { ... } },
      Method2 { method { ... } }
    };
    time singleton.values;

Stage 2

Having implemented stage 1 and gained some experience a second stage could be added with the following suggestions (these are very much suggestions and this section should be treated as a list of open issues). I have stuck with syntax related suggestions that are essentially sugar and no new semantics or modifications to JVM.

Suggestion A: Add support for statements break, continue, and exit multiple enclosing blocks using break, continue, or return. The syntax for break and continue for an enclosing loop would be unchanged. For exiting an enclosing method the syntax could be MethodName.return value;. This could be implemented using pre-made checked exceptions, thus allowing compile time checking of multiple block exits. Syntax could be unified by allowing Name.break and Name.continue and named blocks, e.g. if Name ( ... ) { ... }.

Suggestion B: Add support for long strings with embedded variables using a new keyword, string, e.g.:

    string { // Trailing white space and single new line on { line not part of string
Embed variables including optional formatting, e.g.: %2.1f{ real }
    } // Leading white space and single new line on } line not part of the string

Suggestion C: Add support for union of types using & like generics (particularly for catch blocks).

Suggestion D: Allow final and declare to be used for the variable declaration in a catch block and allow type inference as the union of all declared or inferred (checked or not) exceptions.

Suggestion E: Add support for properties by inferring bodies and declarations for: method getName { default }and method setName { default }; i.e. like new { default }.

Suggestion F: Universally allow () in C3S to be omitted, e.g. if condition { ... ; ... } and method Type name ..., ... { ... ; ... }.

Suggestion G: Unify variable (field, local, and argument) declarations around the standard syntax, e.g. final Type { name1; name2 }.

Suggestion H: Make new line act as a semicolon and allow ,, +, -, =, etc. as last non-white space or non-comment on a line to mean continued on next line.


Eirik Maus

Posts: 15
Nickname: eirikma
Registered: Oct, 2005

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 29, 2006 1:57 PM
Reply to this message Reply
This looks interesting. It wouldn't be Java, but it might be something better that would run in the JVM/rt.jar environment and interact vith java libraries. Maybe you should write at C3S-to-java compiler. Or, better, develop the syntax with IntelliJ MetaProgramming System and give us all an interactive editor/compiler.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 29, 2006 8:59 PM
Reply to this message Reply
> This looks interesting. It wouldn't be Java,

I would still consider it Java, because it is just syntax sugar and because current Java is a subset

> but it might
> be something better that would run in the JVM/rt.jar
> environment and interact vith java libraries.

Scala does this, but its syntax isn't upwardly compatible with Java and it has some very un-Java like features (not that these features are a bad thing - Scala is a well designed language)

> Maybe you
> should write at C3S-to-java compiler. Or, better, develop
> the syntax with IntelliJ MetaProgramming System and give
> us all an interactive editor/compiler.

I am not familiar with IntelliJ, but hear good things about it. I use Netbeans and unfortunately its transformation engine for refactoring, Jackpot, requires its input and its output to be current Java. Therefore you can't extend the syntax of Java in Netbeans :(

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 30, 2006 4:33 AM
Reply to this message Reply
Ehmm...what happened to the simple object-oriented language for the masses called Java? more bloat, more rules, more exceptions is not good for the language, is it?

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 30, 2006 6:21 AM
Reply to this message Reply
I don't really see anything here that is valuable to me. There are some typing time savers, but IDEs like NB and others can trivially solve this problem for you. I have abreviations in the editor for th e most common action listener and other anonymous classes and methods that I use.

The added rules and syntaxes will just make more things that the developer who is coding, or reading has to remember the symantics for.

I haven't been watching this debate, so I'm tempted to just ask a simple question. What problem needs to be solved by all of this? Is it just that a few people don't feel that the current annonymous class implementation is "pretty" enough?

I guess my view is that the current implementation is very simple, completely readable, and I really had no problem jumping in and using it immediately.

What barriers are there really, to using anonymous classes?

It seems like a lot of the discussion presented here is about less text. That can be good for typing speed improvement, but it can lead to ambiguity and lack of information for those reading.

I didn't grasp how I would implement a MouseAdapter that overroad mousePressed() and mouseReleased(), and checked for isPopupTrigger() to display a menu.

I'm also not sure how I would declare multiple methods that each throughs 2 or more exceptions each that are unrelated. It looked to me like the trailing Throwable... e would only handle a single method.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 30, 2006 8:10 PM
Reply to this message Reply
@Achilleas & Gregg,

> I don't really see anything here that is valuable to me.
> There are some typing time savers, but IDEs like NB and
> d others can trivially solve this problem for you. I have
> abreviations in the editor for th e most common action
> listener and other anonymous classes and methods that I
> use.

I agree with you that a good IDE goes a long way to solve the problem and I also agree that we don't really need any new semantics. IE I think what ever is done should have a direct mechanical translation into current Java.

> The added rules and syntaxes will just make more things
> that the developer who is coding, or reading has to
> remember the symantics for.

Assuming that the new syntax becomes the norm then it will reduce the load on the developer because the syntax is more consistent. I can't see a way forward without introducing new syntax, so the proposal is to keep the syntax as much like Java currently is as possible whilst at the same time cleaning up the rough edges on the current syntax. Particularly round generics where the declarations get a uniform position in the statement and most declarations are considerably shorter.

> I haven't been watching this debate, so I'm tempted to
> just ask a simple question. What problem needs to be
> solved by all of this? Is it just that a few people don't
> feel that the current annonymous class implementation is
> "pretty" enough?
>
> I guess my view is that the current implementation is very
> simple, completely readable, and I really had no problem
> jumping in and using it immediately.
>
> What barriers are there really, to using anonymous
> classes?

Some people find the code hard to read because the verbosity hides the intent. It is also difficult to teach, for the same reason. There is also competition, when inner classes were introduced they were a step up from mainstream languages. But now that Ruby has become popular they are not quite so leading edge. The verbosity definitely discourages people from using them. Generics have also increased the verbosity somewhat as well. Although I totally agree with you that inner classes are quite serviceable.

> It seems like a lot of the discussion presented here is
> about less text. That can be good for typing speed
> improvement, but it can lead to ambiguity and lack of
> information for those reading.

Hopefully the proposal isn't ambiguous, I will try some examples on you below and see what you think. I think they present well and are more readable than current Java because intent isn't obscured by verbosity and because the new keyword method helps clarify that you are declaring a method not a field or local.

> I didn't grasp how I would implement a MouseAdapter that
> overroad mousePressed() and mouseReleased(), and checked
> for isPopupTrigger() to display a menu.

The example doesn't use generics which have increased the verbosity somewhat, but never the less it is still pleasingly shorter than current Java and I would say clearer because of the extra keyword, method.
    final mouse = MouseAdapter.new {
      method mousePressed( event ) {
        if ( !event.isPopupTrigger ) { return }
        ...
      }
      method mouseReleased( event ) {
        if ( !event.isPopupTrigger ) { return }
        ...
      }
    };
    panel.addMouseListener mouse;
or
    panel.addMouseListener new {
      method mousePressed( event ) {
        if ( !event.isPopupTrigger ) { return }
        ...
      }
      method mouseReleased( event ) {
        if ( !event.isPopupTrigger ) { return }
        ...
      }
    };


> I'm also not sure how I would declare multiple methods
> that each throughs 2 or more exceptions each that are
> unrelated. It looked to me like the trailing
> Throwable... e would only handle a single method.

Is this the sort of example you had in mind. Note the nearest you can do at present is to throw a single Throwable or use a fixed sized set of exceptions, each with its own generic parameter. This is a good example of how the proposal simplifies things.
    interface TwoMethodsTwoExceptions {
      method< Throwable... T1s > void method1( boolean which ) throws T1s;
      method< Throwable... T2s > void method2( boolean which ) throws T2s;
    }
which might be used like:
    final example = TwoMethodsTwoExceptions.new {
      method method1( which ) {
        throw which ? Exception1A.new : Exception1B.new;
      }
      method method2( which ) {
        throw which ? Exception2A.new : Exception2B.new;
      }
    }
In current Java the above is roughly (only two exceptions):
    interface TwoMethodsTwoExceptions {
      < T1A extends Throwable, T1B extends Throwable > void method1( boolean which ) throws T1A, T1B;
      < T2A extends Throwable, T2B extends Throwable > void method2( boolean which ) throws T2A, T2B;
    }
which might be used like:
    final TwoMethodsTwoExceptions example = new TwoMethodsTwoExceptions() {
      public void method1( boolean which ) throws Exception1A, Exception1B {
        throw which ? (new Exception1A()) : (new Exception1B());
      }
      public void method2( which ) throws Exception2A, Exception2B {
        throw which ? (new Exception2A()) : (new Exception2());
      }
    }

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 2:12 AM
Reply to this message Reply
Personally I have no interest in using such syntax beautifications, and neither will my software team. Our aim is to have good and consistent design...these low level details are irrelevant to good code.

Furthermore, I find syntactic exceptions dangerous: they make the code easier to write, but harder to read, especially if you go back a few months and want to change it or incorporate a new member in the development team.

I prefer simplicity, even if it takes a few more keystrokes.

Eivind Eklund

Posts: 49
Nickname: eeklund2
Registered: Jan, 2006

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 3:43 AM
Reply to this message Reply
Greg, while I agree on reading being more important than writing, there are SERIOUS reading problems in Java that this syntax partially fix.

The primary problem with Java is that there is extreme amounts of redundancy - "boilerplate code" - that you still need to process on reading. This is noise that is in the way of seeing real differences.

The proposal remove a lot of that noise. This is important. Whether you can use an editor template to save typing is unimportant - removing the boilerplate you inserted from my reading is critical.

Marcin Kowalczyk

Posts: 40
Nickname: qrczak
Registered: Oct, 2004

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 5:08 AM
Reply to this message Reply
I prefer simplicity and conciseness.

This seems to be impossible to archieve if Java is taken as the base.

Lots of rules with subtle constraints on when they can and cannot be used are ugly, and vanilla Java is verbose. The only way out of this mess is to start from scratch. It can be done (I'm quite happy with the syntax of my language).

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 6:16 AM
Reply to this message Reply
> The proposal remove a lot of that noise.

The proposal doesn't actually remove anything. Instead, it introduces alternative ways of doing things that can already be done, more syntax variations and therefore more barriers to learning the language.

The benefit of removing some boilerplate code is lost by the need for everyone to now know what is being implicitly coded that which was explicitly coded before. In any case, since the 'old' forms are still valid, programmers still need to be able to deal with them.

Michael Feathers

Posts: 448
Nickname: mfeathers
Registered: Jul, 2003

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 7:19 AM
Reply to this message Reply
I really can't imagine a world in which Java makes a set of syntax changes that are that radical. IMHO, I think you're better off giving it a new name, compiling it to the JVM and announcing it as a new language.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 7:54 AM
Reply to this message Reply
> I really can't imagine a world in which Java makes a set
> of syntax changes that are that radical. IMHO, I think
> you're better off giving it a new name, compiling it to
> the JVM and announcing it as a new language.

I agree with that. If its going to be radically different, then there is no point in mixing the two...a different language that targets the same VM is preferrable than throwing everything in the same language.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 3:00 PM
Reply to this message Reply
If you are wanting a new language for the JVM then perhaps you should take a look at Scala, which has very concise syntax that at least to my eyes is clear. However it has many ways of doing the same thing, essentially long hand and short hand. Particularly with respect of inner classes.

If no changes to Java are made then I think it will eventually stagnate, this is what has happened to other languages in the past. I think it is valuable to update the language and keep it fresh and it has happened in the past. For example inner classes and generics. In both cases they offered nothing that wasn't already possible in Java but provided some syntax sugar to make the programmers intent clearer. I would like to continue along that path and to also deprecate the old syntax and when a syntax is replaced have the -Xlint option to the compiler issue a warning that the old syntax is deprecated. Java already has examples of this, e.g. Type[] name and Type name[]. I feel the trick is to be respectful to the original design of the language but to not treat it as ever finished but always work in progress.

(The above statement re. inner classes isn't quite true; they assign to the pointer to the enclosing class before calling super which isn't possible in standard Java.)

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 11:06 PM
Reply to this message Reply
> If no changes to Java are made then I think it will
> eventually stagnate, this is what has happened to other
> languages in the past. I think it is valuable to update
> the language and keep it fresh and it has happened in the
> past. For example inner classes and generics.

Inner classes and generics are not examples of changes introduced to the language to "keep it fresh". They were introduced to extend the capabilities of the language in line with current thinking on software development practise.

Change for the sake of change (to "keep it fresh") is sterile and will fool no-one into thinking a language is still growing.

> In both cases they offered nothing that wasn't already possible in
> Java but provided some syntax sugar to make the
> programmers intent clearer. I would like to continue along
> that path and to also deprecate the old syntax and when a
> syntax is replaced have the -Xlint option to the compiler
> issue a warning that the old syntax is deprecated.

Deprecating language features without ever deleting them has proven to be a poor long term strategy by Sun. It's unwanted baggage that is never discarded. Even if developers themselves never use those features they need to be familiar with them so that they can, as professionals, deal with version 1.0 code that might be recompiled under version 1.6, etc. (does that ever really happen?) or code developed by others who have ignored depecation warnings to implement something that works in a way they are familiar with.

So, should new features be introduced to Java? Yes, if they extend the language in a useful manner, and yes if they make a simplification that outweighs the complification of introducing that simplification (sic.). No, if their purpose is to keep the language "fresh" or if they are just trivial syntactic tweaks that do no more than save typing.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Clear, Consistent, and Concise Syntax (C3S) for Java Posted: Oct 31, 2006 11:57 PM
Reply to this message Reply
@Vincent,

Hang on a minute, inner classes and generics implemented nothing that could be done before their introduction. I can hand code an inner class (well almost as I previously noted) and I can use casts instead of generics (generics do increase compile time safety). In both cases they primarily increased clarity and to a secondary extent reduced typing. This is what these proposals aim to do: increase clarity, increase consistency, and reduce verbosity.

Just like generics and inner classes the pre-their-introduction Java syntax remains and the programmer needs to have at least a passing familiarity with the old way. E.G. the example from the Javadoc for java.util.concurrent.Future<V>:
In C3S:
 interface ArchiveSearcher { method String search(String target) }
 class App {
   declare executor = ...
   declare searcher = ...
   method void showSearch(final String target) throws InterruptedException {
     declare future = executor.submit method { searcher.search target };
     displayOtherThings; // do other things while searching
     try {
       displayText future.get // use future
     } catch (ExecutionException ex) { cleanup; return }
   }
 }
 
In Current Java (from Javadoc):
 interface ArchiveSearcher { String search(String target); }
 class App {
   ExecutorService executor = ...
   ArchiveSearcher searcher = ...
   void showSearch(final String target) throws InterruptedException {
     Future<String> future = executor.submit(new Callable<String>() {
         public String call() { return searcher.search(target); }
     });
     displayOtherThings(); // do other things while searching
     try {
       displayText(future.get()); // use future
     } catch (ExecutionException ex) { cleanup(); return; }
   }
 }
 
In Java pre inner classes and generics:
 interface ArchiveSearcher { String search(String target); }
 class Inner implements Callable {
   final App outer;
   final String target
   Inner(final App outer, final String target) {
     this.outer = outer;
     this.target = target;
   }
   public Object call() { return outer.searcher.search(target); }
 }
 class App {
   ExecutorService executor = ...
   ArchiveSearcher searcher = ...
   void showSearch(final String target) throws InterruptedException {
     Future future = executor.submit(new Inner(this, target));
     displayOtherThings(); // do other things while searching
     try {
       displayText(((String)future.get())); // use future
     } catch (ExecutionException ex) { cleanup(); return; }
   }
 }

The progression of these examples, to my eyes, starting at the top, is decreasing in clarity and increasing in verbosity. So I think shorter syntax has been and should continue to be added to Java; provided that it is consistent with previous syntax and provided that it improves clarity.

Flat View: This topic has 23 replies on 2 pages [ 1  2 | » ]
Topic: Clear, Consistent, and Concise Syntax (C3S) for Java Previous Topic   Next Topic Topic: Dreams and Nightmares

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use