Submission: switch (...) instanceof feature

Jeroen van Maanen jeroen at lexau.org
Mon May 4 04:21:23 PDT 2009


Reinier Zwitserloot wrote:
> Why is this neccessary? We have a similar situation here as the 
> inherited exception issue: Rare and definitely broken (at runtime) code 
> will now break at compile time. This is technically 'backwards 
> incompatible', insofar that code that used to compile no longer does. 

It is not necessary, but I think it is highly desirable for readability to make this recognizable in the code. In all other cases the code between the parentheses behind the "if" is just an expression. It is easy to mistake the new form for a normal "if" if the extended syntax resembles the normal syntax too closely:

Integer value;
boolean isInteger;
if (isInteger = (x instanceof Integer)) {
  value = x; // Compiler error?
} else if (x instanceof String) {
  value = Integer.valueOf(x)
} else if (x == null) {
  value = 0;
} else {
  throw IllegalArgumentException("Can't convert to an Integer: [" + x + "]");
}

I would say that the following code is much clearer:

Integer value;
boolean isInteger = false;
if instanceof (Integer x) {
  isInteger = true;
  value = x;
} else if instanceof (String x) {
  value = Integer.valueOf(x)
} else if (x == null) {
  value = 0;
} else {
  throw IllegalArgumentException("Can't convert to an Integer: [" + x + "]");
}

The special syntax could also support multiple tests/redeclarations in the same if:

if instanceof (Integer x, Integer y) {
  x += y;
}

whereas the alternative

if (x instanceof Integer && y instanceof Integer) {
  x += y;
}

asks for a pretty complicated analysis of the test to see whether any subexpression of the test narrows the type of one of the variables involved. Beware of boolean negation and "or":

if (!(x instanceof BigInteger) && y instanceof Integer) { // Doesn't narrow the type of "x"
  return add(x, y);
}

But sure, it would be possible to detect the form "if (<name> instanceof <type-decl>)" and magically narrow the type of <name> for this specific kind of test only.

Jeroen

> However, I believe the decision was made that this technical 
> incompatibility was acceptable, because the code made no runtime sense 
> in the first place. You have the same situation here:
> 
> 
> old code:
> 
> Object x = foo();
> 
> if ( x instanceof String ) {
>   Integer y = (Integer)x;
> }
> 
> would compile, eventhough it's clearly bogus. With this change:
> 
> if ( x instanceof String ) {
>    //within this block, 'x' is considered to be both a String and 
> whatever x's actual type is, if it's not a strict supertype of String.
> }
> 
> the original clearly broken code would all of a sudden produce a compile 
> error, because casting a String to an Integer is not allowed (at 
> compile-time too, not just at runtime). You could make a rule to relax 
> this restriction (and generate a warning instead). Personally I'd say 
> that clearly broken code should generate compile-time exceptions, that's 
> why we went with static typing in the first place, so there's no need to 
> complicate the JLS with such a relaxation just to be backwards 
> compatible. That's kind of like Windows Vista taking the trouble to be 
> compatible with viruses written for XP, just so they can say "we're 100% 
> compatible!". (That's a hypothetical, not a comment on Microsoft's 
> programming division. I don't even use windows, I have no idea if Vista 
> works like that).
> 
> 
> Why would we possibly want to introduce new syntax here?
> 
> 
>  --Reinier Zwitserloot
> Like it? Tip it! 
> http://tipit.to <http://tipit.to/>
> 
> 
> 
> On May 4, 2009, at 10:58, Jeroen van Maanen wrote:
> 
>> A colleague of mine pointed out that "if (... instanceof ...)" is 
>> currently syntactically correct code. Suddenly the "if" statement 
>> would show kind of a meta side effect for a highly specific subset of 
>> tests. He suggested that the new "type narrowing if" would get a 
>> clearly distinguished syntax, for example:
>>
>> a concise syntax similar to the extended "for" statement:
>>
>> if (name : Type) { ... }
>>
>> or verbose:
>>
>> if instanceof (name : Type) { ... }
>>
>> or like a declaration rather that a test, which clearly emphasizes the 
>> side effect:
>>
>> if instanceof (Type name) { ... }
>>
>> Jeroen
>>
>> Jeroen van Maanen schreef:
>>> I agree that "if (... instanceof ...)" is more readable than the 
>>> extension of "switch" that I proposed originally. I believe that this 
>>> feature that avoids an unnecessary new name and cast would be of 
>>> great benefit to the Java language.
>>> Jeroen
>>> Derek Foster schreef:
>>>> I notice that the example you gave is actually an argument for an 
>>>> "if" that respects instanceOf, rather than a 'switch' that does. It 
>>>> seems to me like an abuse of notation to use a 'switch' in a case 
>>>> like this where only one decision (it is or it isn't a subtype of a 
>>>> given type) is being made.
>>>>
>>>> Although I am skeptical of the 'switch instanceof' feature, for the 
>>>> reasons I outlined below, I would very much like to see Java 
>>>> implement the 'if instanceof' feature that is implied in the 
>>>> proposal, and which various people have been suggesting, so that 
>>>> this very common coding pattern:
>>>>
>>>> if (foo instanceof Bar) {
>>>>     Bar bar = (Bar)foo;
>>>>     doSomethingWith(bar);
>>>> }
>>>>
>>>> could be simplified to:
>>>>
>>>> if (foo instanceof Bar) {
>>>>     doSomethingWith(foo);
>>>> }
>>>>
>>>> with no loss of type safety. It seems to me that your example would 
>>>> be more readable with such a construct than it is with the 'switch 
>>>> instanceof' feature.
>>>>
>>>> I had intended to submit a proposal along these lines myself, but 
>>>> simply ran out of time to put it together. Still, it seems to me 
>>>> that there's been widespread agreement on the list that the 'if 
>>>> instanceof' sub-proposal is a good idea.
>>>>
>>>> Derek
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> -----Original Message-----
>>>>> From: Ulf Zibis <Ulf.Zibis at gmx.de <mailto:Ulf.Zibis at gmx.de>>
>>>>> Sent: Apr 22, 2009 5:17 AM
>>>>> To: Derek Foster <vapor1 at teleport.com <mailto:vapor1 at teleport.com>>
>>>>> Cc: Gabriel Belingueres <belingueres at gmail.com 
>>>>> <mailto:belingueres at gmail.com>>, Jeroen van Maanen 
>>>>> <jeroen at entreact.com <mailto:jeroen at entreact.com>>, 
>>>>> coin-dev at openjdk.java.net <mailto:coin-dev at openjdk.java.net>
>>>>> Subject: Re: Submission: switch (...) instanceof feature
>>>>>
>>>>> Am 22.04.2009 06:55, Derek Foster schrieb:
>>>>>> Like Gabriel, I have severe reservations about this proposal. I am 
>>>>>> concerned that it will encourage people to avoid the common OOP 
>>>>>> "best practice" of using virtual method dispatch in favor of doing 
>>>>>> an explicit "switch" on each subtype of a type, in cases where 
>>>>>> doing so is not necessary.
>>>>>>
>>>>>> I concede that there are a few (FEW!) places where doing the 
>>>>>> equivalent of a switch on instances of a type is necessary (for 
>>>>>> instance, if the type is in a library you don't have the ability 
>>>>>> to change). I can see some value in this proposal for that 
>>>>>> purpose. However, I would very much not like to see use of this 
>>>>>> construct become commonplace. I already see too many instances of 
>>>>>> people doing the equivalent of "if (object.type == FOO) {doThis(); 
>>>>>> } else if (object.type == BAR) { doThat(); }" instead of writing 
>>>>>> "object.doSomething();"
>>>>>>
>>>>>>  
>>>>> I like to provide an example where
>>>>>
>>>>> "object.doSomething();"
>>>>>
>>>>> doesn't work:
>>>>>
>>>>>   synchronized Charset lookup(String lowCanonical) {
>>>>>       // cache is initialized with available Charset classes names
>>>>>       Object o = cache.get(lowCanonical);
>>>>>       // Check cache first
>>>>>       if (o instanceof String) {
>>>>>           // Instantiate new charset
>>>>>           Charset cs = newCharset((String)o, lowCanonical);
>>>>>           // Cache it
>>>>>           if (cs != null)
>>>>>               cache.put(lowCanonical, cs);
>>>>>           return cs;
>>>>>       }
>>>>>       return (Charset)o;
>>>>>   }
>>>>>
>>>>>
>>>>> This would look much nicer, as it avoids casting:
>>>>>
>>>>>   synchronized Charset lookup(String lowCanonical) {
>>>>>       // cache is initialized with available Charset classes names
>>>>>       switch (Object o = cache.get(lowCanonical) instanceof ?) {
>>>>>           case String :
>>>>>               // Instantiate new charset
>>>>>               Charset cs = newCharset(o, lowCanonical);
>>>>>               // Cache it
>>>>>               if (cs != null)
>>>>>                   cache.put(lowCanonical, cs);
>>>>>               return cs;
>>>>>           case Charset :
>>>>>               return o;
>>>>>       }
>>>>>   }
>>>>>
>>>>>
>>>>> Refer:
>>>>> https://java-nio-charset-enhanced.dev.java.net/source/browse/java-nio-charset-enhanced/tags/milestone4/src/sun/nio/cs/FastCharsetProvider.java?rev=684&view=markup 
>>>>> <https://java-nio-charset-enhanced.dev.java.net/source/browse/java-nio-charset-enhanced/tags/milestone4/src/sun/nio/cs/FastCharsetProvider.java?rev=684&view=markup> 
>>>>>
>>>>> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6790402
>>>>> http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001182.html
>>>>> http://mail.openjdk.java.net/pipermail/coin-dev/2009-April/001328.html
>>>>>
>>>>> - My example could also be smartly coded without switch..case 
>>>>> statement, if we would enhance if statement accordingly
>>>>> - I also would like to have possibility to declare variables in if 
>>>>> clause, like it's possible in for clause:
>>>>>
>>>>>       if ((Object o = cache.get(lowCanonical)) instanceof String)
>>>>>           ... ;
>>>>>       else if (o instanceof Charset)
>>>>>           ... ;
>>>>>
>>>>> -Ulf
>>>>>
>>>>>
>>>>>> Derek
>>>>>>
>>>>>> -----Original Message-----
>>>>>>
>>>>>>> From: Gabriel Belingueres <belingueres at gmail.com 
>>>>>>> <mailto:belingueres at gmail.com>>
>>>>>>> Sent: Mar 30, 2009 7:31 AM
>>>>>>> To: Jeroen van Maanen <jeroen at entreact.com 
>>>>>>> <mailto:jeroen at entreact.com>>
>>>>>>> Cc: coin-dev at openjdk.java.net <mailto:coin-dev at openjdk.java.net>
>>>>>>> Subject: Re: Submission: switch (...) instanceof feature
>>>>>>>
>>>>>>> IMO I'm against this.
>>>>>>>
>>>>>>> First, it is against current best practices for the design of
>>>>>>> object-oriented software to make easier to code something with a case
>>>>>>> statement on types/classes.
>>>>>>>
>>>>>>> Second:
>>>>>>> void log(Object object) {
>>>>>>>  switch (object) instanceof {
>>>>>>>  case String:
>>>>>>>    logger.debug("'" + object + "'");
>>>>>>>  case Date:
>>>>>>>    logger.debug(object.getTime());
>>>>>>>  case void:
>>>>>>>    logger.debug("null");
>>>>>>>  default:
>>>>>>>    logger.debug("<" + object.toString() + ">");
>>>>>>>  }
>>>>>>> }
>>>>>>>
>>>>>>> It think it is clearer (when possible) writing it with several
>>>>>>> overloaded methods and double dispatching.
>>>>>>>
>>>>>>> ....
>>>>>>>    
>>>>
>>
> 


More information about the coin-dev mailing list