Extend switch .. case statement for all types and simple expressions (2nd update)

Ulf Zibis Ulf.Zibis at gmx.de
Thu May 28 07:40:42 PDT 2009


I just want to see the switch..case construct serving as general purpose 
_n-way fork_ in program flow. IMHO it's a smart syntax providing perfect 
readability.
Only for _2-way fork_ the if..else construct is smart syntax.
Additionally if..else_if..else_if.. construct has the disadvantage of 
missing fall-through facility.

I have rethought my proposal and come to more general syntax:

Proposal for SYNTAX SPECIFICATION:

    switch (expression1 | booleanExpressionTemplate(?) | 
substitution_of_?) {
        case: [booleanOperator ]expression2 | substitution_of_? | 
booleanExpressionTemplate(?)
            {...}
        ...
    }
if 'booleanOperator' is missing:
  - expression1 is primitive value  --> execute: expression1 == expression2
  - expression1 is reference       --> execute: 
expression1.equals(expression2)
  (sophisticated special case to aviod potential NPE):
  - expression1 is reference and expression2 is CONSTANT   --> execute: 
expression2.equals(expression1)


Examples for booleanExpressionTemplate(?) and it's possible substitution:
"Math.sin(?) > 0.5"  -->  foo(bar), floatVar, intVar, PRIM_CONST 
(including autoboxed Number objects)
"? >= 10 && ? < 20"  -->  foo(bar), primitiveVar, PRIM_CONS (including 
autoboxed Number objects)
"?.equals(objectExp)"  -->  foo(bar), objectVar, OBJ_CONST (allows 
objectVar to be null)
"objectExp.equals(?)"  -->  foo(bar), objectVar, OBJ_CONST (allows ? to 
be null)
"stringExp.equalsIgnoreCase(?)"  -->  string(bar), stringVar, 
STRING_CONST, "litteral"

Examples for "expression1.. [booleanOperator ]expression2" and mixed :
switch (stringExp) {
    case == STRING_CONST1 :  // compare for identity
        {...}
    case STRING_CONST2 :  // compare for equality
        {...}
    case STRING_CONST3.equals(?) :  // compare for equality, avoiding NPE
        {...}
    case STRING_CONST4.equalsIgnoreCase(?) :  // compare for equality 
ignoring case
        {...}
    case ?.subString(?.indexOf(STRING_CONST5)).startsWith(STRING_CONST6) 
:  // sophisticated
        {...}
    default:
        {...}
    }
switch (primitiveExp) {
    case == CONST1 :  // compare for equality
        {...}
    case CONST2 :  // compare for equality
        {...}
    case myList.get(3) :  // autoboxing
        {...}
    case > CONST3 :  // compare for greater than
        {...}
    case ? >= 10 && ? < 20 :  // range check
        {...}
    ...
    }


-Ulf


Am 31.03.2009 00:13, Ulf Zibis schrieb:
> AUTHOR(S): Ulf Zibis, Cologne, Germany
>
> OVERVIEW
> FEATURE SUMMARY: Extend switch .. case statement for all types and simple expressions.
> MAJOR ADVANTAGE:
> - Increases readability of source in concurrence to if .. else if .. else syntax.
> - Sophisticated jumps.
> - maybe in some cases javac and hotspot has chance to compute better optimized code.
> MAJOR BENEFIT:
> Stop some programmers escaping to some modern scripting language.
> MAJOR DISADVANTAGE:
> Programmers from other languages, especially C, may be confused about such rich syntax.
>
> EXAMPLES
> SIMPLE EXAMPLE:
> (1):
>      switch( myObject) {
>          case CONSTANT1 : doSomething(); break;
>          case CONSTANT2 : doSomethingElse(); break;
>          default : doSomethingDefault();
>      }
> (2):
>      switch( myString) {
>          case equals("red") : stop(); break;
>          case equals("green") : go(); break;
>          default : openYourEyesForCrossingTraffic();
>      }
> (3):
>      switch( myString) {
>          case equalsIgnoreCase("RED") : sureStop(); break;
>          case equalsIgnoreCase("GREEN") : sureGo(); break;
>          default : beAwareOfPoliceWachtingYou();
>      }
>
> ADVANCED EXAMPLE:
> (4):
>      switch( primitiveInt) {
>          case == 10 : doOnlyIf10(); // alternative syntax for 'case 10:'
>          case < 10 :
>          case >= 20 : break;
>          default : doOnlyInRange();
>      }
> (5):
>      switch( primitiveInt) {
>          case (>= 10 && < 20) : doOnlyInRange();
>          default : throw new Exception("Out of range");
>      }
> (6):
>      switch( myString) {
>          case contains("foo") : doSomething(); break;
>          case regionMatches(true, 2, otherString, 4, 6) : doSomethingElse(); break;
>          default : doSomethingDefault();
>      }
> (7):
>      switch( myString.equals()) { // alternative: myString.equals(..)
>          case "foo" : foo(); break;
>          case "bar" : bar(); break;
>          default : dontCare();
>      }
> (8):
>      switch( className.startsWith("String", ..)) { // alternative: className.startsWith("String", ?)
>          case 0 : doForSimpleName(); break;
>          case 9 : doForFullName(); break;
>          default : canNotDecide();
>      }
> (9):
>      switch( anyObjectOrPrimitive instanceof) { // note, that casting is solved implicit
>          case boolean, byte, ... float : break; // Don't do anything
>          case double : forDouble(anyObjectOrPrimitive);
>          case HashMap :
>          case TreeMap : forPlattformMap(anyObjectOrPrimitive); break;
>          case Map : forOtherMap(anyObjectOrPrimitive); break;
>          default : forObject(anyObjectOrPrimitive);
>      }
> (10): (minimizee chance for NPE)
>      switch( .equals(myString)) { // alternative: ?.equals(myString)
>          case "foo" : foo(); break;
>          case "bar" : bar(); break;
>          default : dontCare();
>      }
> (11):
>      switch( some_lethargic_function_we_cant_call_much().equals(..) ) {
>          case "this":
>          case "that":       this_or_that(); break;
>          case "bigjump":    big();    // fall
>          case "jump":       jump(); break;
>          case "secondlastchance":
>          case "lastchance": last_chance(); break;
>          default:           do_default();
>      }
> .. as replacement for:
>      String sSomeString = some_lethargic_function_we_cant_call_much();
>      if( sSomeString.equals( "this" ) || sSomeString.equals( "that" ) )
>          this_or_that();
>      else if( sSomeString.equals( "jump" ) || sSomeString.equals( "bigjump" ) )
>      {
>          if( sSomeString.equals( "bigjump" ) )
>              big();
>          jump();
>      } else if( sSomeString.equals( "secondlastchance" ) ||
>              sSomeString.equals( "lastchance" ) )
>      {
>          last_chance();
>      } else do_default();
>
> ALTERNATIVES:
> (12):
>      switch( myString) {  // note the '.', I personally would prefer this alternative!
>          case .equals("red") : stop(); break;
>          case .equals("green") : go(); break;
>          default : openYourEyesForCrossingTraffic();
>      }
> (13):
>      switch( primitiveInt) {  // note the '.'
>          case (. >= 10 && . < 20) : doOnlyInRange();
> //        case (? >= 10 && ? < 20) : doOnlyInRange(); // alternative
>          default : throw new Exception("Out of range");
>      }
>
>
> DETAILS
> SPECIFICATION:
> The new syntax should be interpreted as
>      switch ( leftExpressionPart ) {
>          case rightExpressionPart1 :
>          case rightExpressionPart2 :
>          ...
>          default :
>      }
> The result of entire expression should be boolean type.
> There is shortcut for:
>      leftExpressionPart: intVariable
>      rightExpressionPart: == intLiteral
> (the '==' could be ommitted.)
>
> COMPILATION:
> Compiler could first pre-compile to appropriate if..then..else syntax.
> Bytecode would not be affected, but in special cases it could be more compact, if noted 
> pre-compilation would be replaced by sophisticated optimization.
> TESTING:
> Compiler byte-code results for new syntax should be same than from equivalent hand-coded legacy 
> if..then..else syntax
> . Exception: sophisticated optimization.
> LIBRARY SUPPORT: No supporting libraries are needed for the feature?
> REFLECTIVE APIS: There should not be any affection to reflection API.
> OTHER CHANGES: No.
> MIGRATION:
> No refactoring is needed to stay compatible.
>
> COMPATIBILITY
> BREAKING CHANGES:
> No previously valid programs are now invalid.
> ... but ATTENTION:
> If proposals from some other guys regarding "Strings in switch" would be taken into JDK 7, there 
> won't be any compatible way to implement my more general proposal in future version of JDK !!!
> --> So switch .. case statement should compare for IDENTITY if not syntactically determined otherwise.
> --> compare for EQUALITY would also break semantic of existing switch .. case statement.
> Another reason, why I'm against comparing for equality by default syntax, is, that it is good 
> practice to use String constants instead of widely spreaded String literals with same signature for 
> numerous reasons (performance, error prone, ...). The "only-for-String" syntax would lead 
> programmers to stay on widely spreaded String literals of same value.
> If constant is not available for switch variable (e.g. if read from stream), variable could be 
> internalized before, so it's instance becomes identical to the existing constant.
> ===>> If just "Strings in switch" is taken over for JDK 7, there is NO NEED, to compare for equality.
> EXISTING PROGRAMS:
> Source and class files of earlier platform versions interact with the feature without any notice.
>
> REFERENCES
> http://mail.openjdk.java.net/pipermail/coin-dev/2009-February/000001.html
> http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000213.html
> http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000855.html
> http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001089.html
> http://forums.java.net/jive/thread.jspa?messageID=27781&#27781
> http://forums.java.net/jive/thread.jspa?messageID=15769&#15769
> http://forums.java.net/jive/thread.jspa?messageID=27773&#27773
> http://forums.java.net/jive/thread.jspa?messageID=11393&#11393
> http://lasu2string.blogspot.com/2008/12/string-switch-small-language-changes-on.html
> EXISTING BUGS:
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5012262
> URL FOR PROTOTYPE (optional):
>
>
>
>
>
>
>
>   




More information about the coin-dev mailing list