Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / September 2007

Tip: Looking for answers? Try searching our database.

Java 7 features

Thread view: 
Joshua Cranmer - 02 Jul 2007 22:27 GMT
(Yes, I realize that I am about to potentially unleash strong opinions.)

Recently, I was looking around online and came across this (partial) list
of new Java 7 features. What I want to know is what support/disapproval
people have of these options:

@ Closures
@ Strings in switch statements
@ Operator overloading for BigDecimal
@ Language-level XML support
@ Reified generics
@ Superpackages
@ Removing checked exceptions

Personally, I am in support of items 2 and 5; indifferent on 3, 4, and 6;
and against items 1 and 7.
Stefan Ram - 02 Jul 2007 22:46 GMT
>@ Closures

 A lot depends on the details of how this is done.

>@ Strings in switch statements

 Does not really matter to me, because I rarely
 come across this.

>@ Operator overloading for BigDecimal

 If such an extension of the syntax would be tied to a specific
 class (BigDecimal), it would be ugly.

 As a general language feature, it's nice to have.

>@ Language-level XML support

 Should not be tied to fixed classes or an implementation
 or even XML. Whenever source code encounters

   x = <...>

 a plugable handler should be called by the compiler to convert
 the "<...>" part to a Java expression. The XML-handler by Sun
 would be the default.

 By this, S-expressions could be embedded as well.

>@ Reified generics

 Now that I've written all those FAQs explaining type erasure
 they want to devaluate them!!

>@ Superpackages

 I have not yet fully grasped this concept.

>@ Removing checked exceptions

 Indeed, a major part of my library code just consist
 of wrapping them in RuntimeExceptions. So this would
 help.

 What is missing?

 I want Derby (the SQL database that is part of the JDK) to
 become a part of the JRE. It would help to have a default
 database without any further installation.

 Simplifications for common cases:

     CLASS x = new CLASS( ... )

 It should be allowed to abbreviate this to something
 shorter like:

     CLASS x = new( ... )

 Similar

     INTERFACE x = new( ... )

 What is this? I imagine that every interface might specify
 a default implemenation. For example, for java.util.List,
 this would be java.util.ArrayList. Then

     java.util.List<String> x = new();

 would mean the same as

     java.util.List<String> x = new java.util.ArrayList<String>();

 Also, consider:

      if( x instanceof A ){ A a =( A )x; ... }
 else if( x instanceof B ){ B a =( B )x; ... }
 else if( x instanceof C ){ C a =( C )x; ... }

 Forget for a moment that »instanceof« is a code smell.
 Sometimes it's needed.

 This could be written as

      if( x instanceof A ){ ... }
 else if( x instanceof B ){ ... }
 else if( x instanceof C ){ ... }

 if the compiler would keep track of the fact that x
 in the first block is now known to have the type of A,
 so that no further cast is required. (At least for
 an identifier »x« with »final« this should hold.)
Oliver Wong - 03 Jul 2007 15:54 GMT
>  Also, consider:
>
[quoted text clipped - 15 lines]
>  so that no further cast is required. (At least for
>  an identifier »x« with »final« this should hold.)

   I don't think this change is doable while remaining backwards
compatible. If methods are called on x and those methods are overloaded
and overridden, for example, this change would change which methods
actually gets called at runtime.

   - Oliver
Stefan Ram - 03 Jul 2007 16:41 GMT
>>       if( x instanceof A ){ ... }
>If methods are called on x and those methods are overloaded
>and overridden, for example, this change would change which methods
>actually gets called at runtime.

 I believe this only applies to hiding and overloading,
 but not to overriding.

 The language could be changed, so that - by specification -
 all of this is left unchanged. The only modification would be:

 If the part »...x...« in

if( x instanceof A ){ ... ...x... ... }

 would have created an error message in Java 1.6 and if this
 error message would not appear if »x« would be downcast to A,
 then such a downcast will silently be assumed by the compiler
 and the JVM and be implemented as a no-operation.
Tom Hawtin - 02 Jul 2007 23:15 GMT
> @ Closures

But we already have (minimal) closures. I think it would be much more
sensible to improve what we already have, rather than to duplicate. It's
probably unlikely to get in before Java 1.8 anyway.

> @ Strings in switch statements

Not too fussed. It'll make switches on strings clearer, but perhaps will
encourage poor code.

> @ Operator overloading for BigDecimal

BigDecimal and BigInteger are hideous to use at the moment. The overflow
semantics of primitive integers are not something that I think should be
in a high level language. I'd prefer general operator overloading of
sensible operators.

> @ Language-level XML support

Evil and unnecessary. A lot like much of XML.

> @ Reified generics

This could have made sense in 1.5. But I don't think this is really on
given the situation we have got ourselves into.

> @ Superpackages

Good. I guess packages provide what is necessary from superpackages, but
we tend to write libraries and applications in more than one package.

> @ Removing checked exceptions

I like static type checking.

Tom Hawtin
Guillermo Schwarz - 03 Jul 2007 23:59 GMT
> > @ Closures
>
> But we already have (minimal) closures. I think it would be much more
> sensible to improve what we already have, rather than to duplicate. It's
> probably unlikely to get in before Java 1.8 anyway.

We already have Runnable. Who needs something else? Although it would
be nice if it were a la Smalltalk:

new Thread( new Runnable() { public void run() { doSomething(); } } );

Would become:

new Thread( <quote> doSomething();  );

Where <quote> could be:
1. [] a la Smalltalk, ie: [ doSomething(); ] It would look ugly in
Java, though.
2. ' (quote) a la Lisp, ie: 'doSomething(); It looks horrible in Java,
so forget about it.
3. # a la Smalltalk, ie: #doSomething(); Not bad, eh?

> > @ Strings in switch statements
>
> Not too fussed. It'll make switches on strings clearer, but perhaps will
> encourage poor code.

Simply use hashCode(), ie:

switch( str.hashCode() )
{
   case "hello".hashCode(): ...; break;
   case "bye".hashCode(): ...; break;
}

> > @ Operator overloading for BigDecimal
>
> BigDecimal and BigInteger are hideous to use at the moment. The overflow
> semantics of primitive integers are not something that I think should be
> in a high level language. I'd prefer general operator overloading of
> sensible operators.

It would be nice if all numerical classes in Java were retrofitted to
descend from Number (or implement Number), so that you could declare a
number and it could contain any number: float, int, bigdecimal, etc.

> > @ Language-level XML support
>
> Evil and unnecessary. A lot like much of XML.

Use XStream instead.

> > @ Reified generics
>
> This could have made sense in 1.5. But I don't think this is really on
> given the situation we have got ourselves into.

What do you mean?

> > @ Superpackages
>
> Good. I guess packages provide what is necessary from superpackages, but
> we tend to write libraries and applications in more than one package.

What is a superpackage?
Is it this? http://blogs.sun.com/gbracha/entry/developing_modules_for_development

I hope not.

First, EJB already have modularization, you deliver 2 jars, one for
use on the client and another for the whole implementation. It is
trivial (some could argue), but it already works.

The same approach could be used for super packages, have some "client"
package and stuff subpackages inside, and another "implementation"
package and stuff everything else, so that all interfaces and Transfer
Objects go into the "client" packages, and the rest have all the
implementations of those interfaces, great!

EJB was a dead horse because the Enterprise Java Beans did not need to
implement the remote interfaces, and besides the home interfaces were
unnecessary. If they had only one interface and one class (it could
have many implementations, but follow the idea for a minute), it would
be nice.

> > @ Removing checked exceptions
>
> I like static type checking.

Sometimes it gets in the way, but you can always convert those to
RuntimeException, what is the big deal?

Why does people need to force other into their preferences?

> Tom Hawtin
Roedy Green - 04 Jul 2007 00:18 GMT
On Tue, 03 Jul 2007 22:59:52 -0000, Guillermo Schwarz
<guillermo.schwarz@gmail.com> wrote, quoted or indirectly quoted
someone who said :

>    case "hello".hashCode(): ...; break;
>    case "bye".hashCode(): ...; break;

That won't always work.  Hashcodes are not completely unique.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Twisted - 04 Jul 2007 00:24 GMT
On Jul 3, 6:59 pm, Guillermo Schwarz <guillermo.schw...@gmail.com>
wrote:
> We already have Runnable. Who needs something else? Although it would
> be nice if it were a la Smalltalk:
[quoted text clipped - 11 lines]
> so forget about it.
> 3. # a la Smalltalk, ie: #doSomething(); Not bad, eh?

Nope, but we still don't have ones with generic argument and return
types ... of course, for use with threads, you want some sort of
ResultHolder and in the Runnable:

synchronized (resultHolder) {
   resultHolder.set(someObject);
   resultHolder.notify();
}

instead.

For this, I suppose a Foo[1] is usable for a result of type Foo.

> > Not too fussed. It'll make switches on strings clearer, but perhaps will
> > encourage poor code.
[quoted text clipped - 7 lines]
>
> }

Hashcodes aren't guaranteed to be unique. They could be used under the
hood to speed up switches on reference types, whose cases are
constants; a premade HashMap can be used at runtime to lookup a
closure that was built by the compiler to actually contain the case
body bytecode, and the found closure invoked or else a default closure
is invoked. Cases with fallthrough produce closures that chain to
other closures under the hood.

> It would be nice if all numerical classes in Java were retrofitted to
> descend from Number (or implement Number), so that you could declare a
> number and it could contain any number: float, int, bigdecimal, etc.

Ultimately, to do any serious math nicely means you need either double
dispatch to be easy to do nicely, or a "ladder" or directed acyclic
graph of potentially implicit type promotions, based on the providing
of Foo.valueOf(bar) static methods in more advanced types to upconvert
lowlier ones, including primitives. So we'd end up with

short
|   \
int  float
|  \  |
long double
|  \ |
BigI-BigD

And of course there's third party types. What about vectors, tensors,
matrices, and suchlike? What about custom bignum types, which may have
different requirements and characteristics? (JScience has a
LargeInteger with faster multiplies at large sizes, a Real
representing an error-bounded quantity, and suchlike; it unfortunately
does not provide a LargeDecimal with the LargeInteger multiply...)

> > > @ Removing checked exceptions
>
[quoted text clipped - 4 lines]
>
> Why does people need to force other into their preferences?

Because unemployment of professional soldiers would skyrocket if there
were no fascist pigs in the world for them to either a) fight against
or b) work for. :P
Arne Vajhøj - 03 Jul 2007 03:10 GMT
> (Yes, I realize that I am about to potentially unleash strong opinions.)
>
[quoted text clipped - 12 lines]
> Personally, I am in support of items 2 and 5; indifferent on 3, 4, and 6;
> and against items 1 and 7.

for: 2, 3, 5
against: 1, 4, 7
neutral: 6

Arne
Twisted - 03 Jul 2007 04:04 GMT
> (Yes, I realize that I am about to potentially unleash strong opinions.)
>
[quoted text clipped - 3 lines]
>
> @ Closures

Depends. Syntactic sugar to make anonymous inner classes easier to
use: for. Dropping the "final" requirement on referenced local
variables: for. A simple anonymous lambda function ability that
results in first class objects with the ability to compute and return
values: for (this could be had in the form of an appropriate generic
interface and easier anonymous inner classes). Anything really ugly or
hairy: against. Otherwise neutral.

> @ Strings in switch statements

I'd really like to see either switch statements deprecated, switch
statements made enum-only, or switch statements made into syntactic
sugar for ANY lengthy if-elseif-elseif-elseif-else chains.

> @ Operator overloading for BigDecimal

Either none or for any custom class, please, or better yet, require
declaring the operators in an interface, and then binary operators
work when both argument types implement a common interface specifying
that operator, and are type errors otherwise.

> @ Language-level XML support

Bleh. Either skip it or put language-level metalanguage capabilities
in, where you get a construct to declare parsers that use a context-
free-grammar in bison format to define a translation from some syntax
to Java, and you can then use a construct like "import MyLanguage
{ code in my language }" which is translated into Java if the compiler
can resolve the MyLanguage parser definition (a new package level
thing to go with classes, interfaces, and enums). This simple thing
adds no new keywords (by overloading "import") and lets you use almost
anything in your language (except }, and it should treat Java comments
as comments). No doubt there'd be a bazillion XML parser definitions
out there before you could blink anyway.

> @ Reified generics

That depends on how they work. Run-time availability of type parameter
info? If you can make it fly without being too ugly or baroque.
Numeric parameters? That might be nice for fixed-size-vector classes
and things of that nature.

> @ Superpackages

Whatever that means. If it means treating package names as a proper
hierarchy, so that (as is already implied, but untrue)
com.mysite.mystuff.foo.Bar automatically sees com.mysite.mystuff.Quux
and you can tidily import Bar into Quux as "import foo.Bar" or
"import .foo.Bar" ... sure.

> @ Removing checked exceptions

Are they out of their cotton-picking MINDS?!

P.S. a URL with more in depth explanations of what exactly is being
proposed would be handy about now.
julien.robinson2@gmail.com - 03 Jul 2007 12:40 GMT
Small comment...

> > @ Strings in switch statements
>
> I'd really like to see either switch statements deprecated, switch
> statements made enum-only, or switch statements made into syntactic
> sugar for ANY lengthy if-elseif-elseif-elseif-else chains.

I used switch statements much more in C++ than now in Java. Mainly
because, whereas Java has introduced a discrepancy between == and
equals(), switch only applies to ==.

What I would suggest is a new switch, so that we have "switch" and
"switch-equals"

switch: runs through all cases comparing with the operator "==". May
accept null, and probably useless for strings.
"switch (x) {case y:..." should be exactly the same behavior as "if (x
== y)..."
(I *think* that's the one we have... just goes to show how much I use
it!)

switch-equals:
uses "equals()" to test each case. Requires passing an object (or uses
auto-boxing?).
It could not accept null pointers, even though I would favor:
"switch (x) {case y:" should be exactly the same behavior as
"y.equals(x)"
so that x may be null
If ever some y is null, throw NullPointerException of course. :-)
and if x is null, of course it switches to default.

Problem is: what if there's y1 and y2 and both are equal? Simply
precise that only the first match will be acted upon.

This may be ugly, but I agree that:
* switch, as is it, is not very consistent with Java thinking, because
of the "equals" method
* because of this, it is not very much used (at least that's what
people around here are saying)
* making special cases for types is probably to be avoided (as much as
possible of course).

All this said with the ignorance of a non-expert programmer... :-)
JR
Oliver Wong - 03 Jul 2007 16:10 GMT
> I used switch statements much more in C++ than now in Java. Mainly
> because, whereas Java has introduced a discrepancy between == and
[quoted text clipped - 9 lines]
> (I *think* that's the one we have... just goes to show how much I use
> it!)

   Yes, I think that's an accurate mental model of how the switch
statement works

> switch-equals:
> uses "equals()" to test each case. Requires passing an object (or uses
[quoted text clipped - 5 lines]
> If ever some y is null, throw NullPointerException of course. :-)
> and if x is null, of course it switches to default.

   How about adding a new case statement for nulls, and leaving default
to their original semantics?

switchequals (x) {
 case y:
   doThis();
   break;
 case z:
   doThat();
   break;
 null:
   doSomethingElse();
   break;
 default:
   giveUp();
   break;
}

is syntatic sugar for:

if (null == x) {
 doSomethingElse();
} else if (y.equals(x)) {
 doThis();
} else if (z.equals(x)) {
 doThat();
} else {
 giveUp();
}

and

switchequals (x) {
 case y:
   doThis();
   break;
 case z:
   doThat();
   break;
 default:
   giveUp();
   break;
}

is syntatic sugar for:

if (null == x) {
 giveUp();
} else if (y.equals(x)) {
 doThis();
} else if (z.equals(x)) {
 doThat();
} else {
 giveUp();
}

Note that the compiler was smart enough to do whatever was necessary to
avoid NullPointerException.

   While we're at it, how about changing the switch statement so that
statements after a case-label MUST end in either "break;" or
"fallthrough;" (or "continue;", if you want to avoid creating a new
keyword). So the following would no longer be legal code:

switch(x) {
 case 1: //fallthrough
 case 2:
   doSomething();
}

and instead would need to be written:

switch(x) {
 case 1:
   continue;
 case 2:
   doSomething;
   break;
}

> Problem is: what if there's y1 and y2 and both are equal? Simply
> precise that only the first match will be acted upon.

   Agreed, as I think this parallels how switch currently works.

> This may be ugly, but I agree that:
> * switch, as is it, is not very consistent with Java thinking, because
> of the "equals" method

   Note that switch statements refuse to work on anything except integers
(maybe longs?) and enums. Specifically, they don't work on objects, so the
"equals" method doesn't even come up as an issue yet.

   - Oliver
Roedy Green - 03 Jul 2007 21:27 GMT
On Tue, 3 Jul 2007 11:10:03 -0400, "Oliver Wong"
<owong@castortech.com> wrote, quoted or indirectly quoted someone who
said :

>    Yes, I think that's an accurate mental model of how the switch
>statement works

There are two JVM instructions to implement a switch.  Java's N-way
branch. In the JVM there are two different ways of implementing a
switch, tableswitch and lookupswitch. The efficient tableSwitch is a
jump table used when the switch values are reasonably dense e.g.
numbered 0..N. The less efficient lookupSwitch is a binary search used
when the switch values all all over the map. It thus pays to keep your
switch values dense.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Stefan Ram - 03 Jul 2007 22:11 GMT
>There are two JVM instructions to implement a switch.  Java's N-way
>branch. In the JVM there are two different ways of implementing a
[quoted text clipped - 3 lines]
>when the switch values all all over the map. It thus pays to keep your
>switch values dense.

 Still, they might be implemented by if-sequences.
 As Ralf Ullrich recently quoted:

     »Figure 5 shows that Java dense switches (tableswitches),
     when used to implement dynamic dispatch, result in
     performance very similar to that of virtual calls on the
     IBM JVM, revealing an implementation based on jump tables.

     In the HotSpot Client JVM however, both on Pentium III and
     UltraSparc III (gures 7 and 8), tableswitch es behave
     exactly like if sequences, which indicates an actual
     implementation based on sequences of conditional branches.
     Table switches are therefore unreliable in terms of
     performance across JVMs.«

 The source according to Ralf is:

   »Evaluation of Control Structures for Dynamic Dispatch in Java«

http://www.cs.mcgill.ca/research/techreports/reports/01/SOCS.01.13.ps.gz

 I just wrote a benchmark, which showed if-sequences to be
 actually faster than switches for the special case tested.

import static java.lang.System.nanoTime;
import static java.lang.System.currentTimeMillis;
import static java.lang.System.out;
import static java.lang.System.gc;
import static java.lang.Thread.sleep;

public class Main
{ public static void main( final java.lang.String[] args )
 throws java.lang.Throwable
 { int randomizer =( int )( currentTimeMillis() / 947 ); int i1; int i2;
   int r0; int r1;
   int s;
   long d0; long d1; long d2;
   long t0, t1, t2, t3, t4, t5;
   out.printf
   ( "Benchmark running - " +
     "Please minimize activity of other processes.%n" );
   sleep( 3000 );
   double a = 0.; double c = 0.;
   out.printf
   ( "The columns"                                          + "%n" +
     "  Identification number of the outermost iteration"   + "%n" +
     "  Runtime of \"if\" divided by runtime of \"switch\"" + "%n" +
     "  Average of the preceding column"                    + "%n" );
   for( long l = 0;; ++l )
   { r0 = 0; r1 = 0; s = 0;
     d0 = 0; d1 = 0; d2 = 0;
     gc();
     Thread.sleep( 1000 );
     final long n = 100000000L;
     { { t4 = nanoTime();
         randomizer +=( int )(( t4 / 7907 )% 611953 );
         for( long i = 0; i < n; ++i )
         { randomizer = randomizer * 1103515245 + 12345;
           final int random =( randomizer / 65536 )% 10;
           s += random; }
         t5 = nanoTime();
         d2 +=( t5 - t4 ); }
       { t0 = nanoTime();
         for( long i = 0; i < n; ++i )
         { randomizer = randomizer * 1103515245 + 12345;
           final int random =( randomizer / 65536 )% 10;
           {      if( random == 0 )r0 = 20418437;
             else if( random == 1 )r0 = 94704581;
             else if( random == 2 )r0 = 45898144;
             else if( random == 3 )r0 = 49094059;
             else if( random == 4 )r0 = 77416885;
             else if( random == 5 )r0 = 91322469;
             else if( random == 6 )r0 = 40218964;
             else if( random == 7 )r0 = 93641667;
             else if( random == 8 )r0 = 29822916;
             else                  r0 =   625909; }
           s += r0; }
         t1 = nanoTime();
         d0 +=( t1 - t0 ); }
       { t4 = nanoTime();
         for( long i = 0; i < n; ++i )
         { randomizer = randomizer * 1103515245 + 12345;
           final int random =( randomizer / 65536 )% 10;
           s += random; }
         t5 = nanoTime();
         d2 +=( t5 - t4 ); }
       { t2 = nanoTime();
         for( long i = 0; i < n; ++i )
         { randomizer = randomizer * 1103515245 + 12345;
           final int random =( randomizer / 65536 )% 10;
           switch( random )
           { case  0: r1 = 16336774; break;
             case  1: r1 = 62881795; break;
             case  2: r1 = 27998504; break;
             case  3: r1 =  9612956; break;
             case  4: r1 = 25592297; break;
             case  5: r1 = 77114095; break;
             case  6: r1 = 23554325; break;
             case  7: r1 = 55380051; break;
             case  8: r1 = 47971513; break;
             default: r1 = 41100793; }
           s += r1; }
         t3 = nanoTime();
         d1 +=( t3 - t2 ); }}
   final double q =( d0 - d2 / 2.0 )/( d1 - d2 / 2.0 );
   a += q;
   out.printf( "%6d; %6.02f; %6.02f%n", l, q, a /( l +  1 ), s ); }}}

/*

Benchmark running - Please minimize activity of other processes.
The columns
 Identification number of the outermost iteration
 Runtime of "if" divided by runtime of "switch"
 Average of the preceding column

    0;   0,73;   0,73
    1;   0,93;   0,83
    2;   0,93;   0,87
    3;   0,93;   0,88
    4;   0,93;   0,89
    5;   0,93;   0,90
    6;   0,93;   0,90

*/
Roedy Green - 04 Jul 2007 01:38 GMT
>Benchmark running - Please minimize activity of other processes.
>The columns
[quoted text clipped - 9 lines]
>     5;   0,93;   0,90
>     6;   0,93;   0,90

It depends on whether you use -client or -server

Here is Java 1.6 on my AMD 64 DUAL core 2.047 Mhz

java -client SwitchTester
Benchmark running - Please minimize activity of other processes.
The columns
 Identification number of the outermost iteration
 Runtime of "if" divided by runtime of "switch"
 Average of the preceding column
    0;   1.18;   1.18
    1;   1.19;   1.19
    2;   1.14;   1.17
    3;   1.09;   1.15
    4;   1.27;   1.17
    5;   1.18;   1.18
    6;   1.18;   1.18

java -server SwitchTester
enchmark running - Please minimize activity of other processes.
he columns
Identification number of the outermost iteration
Runtime of "if" divided by runtime of "switch"
Average of the preceding column
   0;   0.75;   0.75
   1;   0.94;   0.85
   2;   0.82;   0.84
   3;   1.11;   0.91
   4;   0.86;   0.90
   5;   0.84;   0.89
   6;   0.91;   0.89
   7;   0.85;   0.89
   8;   0.91;   0.89
   9;   0.86;   0.89
  10;   0.78;   0.88
  11;   0.92;   0.88
  12;   0.83;   0.88

With Jet 5.0
Benchmark running - Please minimize activity of other processes.
The columns
 Identification number of the outermost iteration
 Runtime of "if" divided by runtime of "switch"
 Average of the preceding column
    0;   0.57;   0.57
    1;   0.87;   0.72
    2;   0.93;   0.79
    3;   0.92;   0.83
    4;   1.03;   0.87
    5;   0.65;   0.83
    6;   0.96;   0.85
    7;   0.97;   0.86

So it looks like optimisers spend more time on IFs than SWITCH.
This is puzzling.  Iin Assembler a jump table should be much faster
than any nested set of switches, even if organised in a binary search.

The -genasm+ switch in Jet seems to be discontinued so I can't easily
figure out what sort of code it is generating for both.

--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Roedy Green - 04 Jul 2007 03:14 GMT
On Wed, 04 Jul 2007 00:38:06 GMT, Roedy Green
<see_website@mindprod.com.invalid> wrote, quoted or indirectly quoted
someone who said :

>So it looks like optimisers spend more time on IFs than SWITCH.
>This is puzzling.  Iin Assembler a jump table should be much faster
>than any nested set of switches, even if organised in a binary search.

I am wondering if parallel logic in the chip is the secret of the
speed of the nested if.  Perhaps it can do several lookaheads.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Twisted - 04 Jul 2007 03:49 GMT
On Jul 3, 10:14 pm, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:
> On Wed, 04 Jul 2007 00:38:06 GMT, Roedy Green
> <see_webs...@mindprod.com.invalid> wrote, quoted or indirectly quoted
[quoted text clipped - 6 lines]
> I am wondering if parallel logic in the chip is the secret of the
> speed of the nested if.  Perhaps it can do several lookaheads.

Could be. Branch prediction is clobbered by jump tables. I wonder if
dynamic method dispatch uses a binary tree approach instead of vtable
approach to take advantage of branch prediction in any of these VMs or
in Jet?

As for examining the assembly produced by Jet, why not simply
disassemble the object code it outputs?
Roedy Green - 04 Jul 2007 14:24 GMT
>As for examining the assembly produced by Jet, why not simply
>disassemble the object code it outputs?

"simply"? Without symbol tables it is quite a bit of work to find the
code of interest, especially when it looks nothing like what you would
have written yourself.

I have a query into Jet about how to get the undocumented assembler
listing working again.

If that fails,  my curiosity may press hard enough to solve this
mystery the hard way.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Stefan Ram - 04 Jul 2007 15:49 GMT
>>So it looks like optimisers spend more time on IFs than SWITCH.
>>This is puzzling.  Iin Assembler a jump table should be much faster
>>than any nested set of switches, even if organised in a binary search.
>I am wondering if parallel logic in the chip is the secret of the
>speed of the nested if.  Perhaps it can do several lookaheads.

 I have found a bug in my benchmark. The random numbers
 generated were often negative and thus prefered one branch.

 Now, I have changed

final int random =( randomizer / 65536 )% 10;

 to

final int random =(( randomizer / 65536 )& 0x7fffffff )% 10;

 everywhere.

 After this, the if-sequence is not faster then the switch
 anymore, but both take the same time. This confirmes the text
 quoted before, which claims that the switch was implemented by
 if-sequences.

 For the special case of a dense array of values to be
 converted into other values, one might also use a look-up
 table. I have tried this, and it is indeed much faster than
 the switch.
Roedy Green - 04 Jul 2007 18:31 GMT
>final int random =(( randomizer / 65536 )& 0x7fffffff )% 10;

I look more carefully at the code, I see another problem.

Your code to calculate randoms overwhelms the cost of the code to do
the swtich.

I rewrote the code. Here is my new result with Jet.

[E:\com\mindprod\example]TestSwitch
Calculate time for IF/time for SWITCH.  >1 means IF is slower
Trial | ratio | average
    0    1.00      1.00
    1    1.01      1.00
    2    0.97      0.99
    3    0.99      0.99
    4    1.01      1.00
    5    1.00      1.00
    6    1.04      1.00
    7    1.01      1.00
    8    1.00      1.00
    9    0.99      1.00
   10    0.99      1.00

In other words IF is just as fast as switch WHY??

package com.mindprod.example;

import static java.lang.System.nanoTime;
import static java.lang.System.out;
import java.util.Random;

/**
* Compares relative speed of nested if vs switch
*
* @author Roedy Green, Canadian Mind Products, based on a program by
Stefan
*         Ram.
* @version 1.0, 2007-07-04 Created with IntelliJ IDEA.
*/
public class TestSwitch {

   // ------------------------------ FIELDS
------------------------------
   // one million iterations per trial
   final static long ITERATIONS_PER_TRIAL = 1000000L;

   // --------------------------- main() method
---------------------------

   public static void main( final java.lang.String[] args ) throws
java.lang.Throwable
       {

       out.println(
               "Calculate time for IF/time for SWITCH.  >1 means IF
is slower" );
       out.println( " Trial | ratio | average" );
       final Random wheel = new Random();

       // accumulate total machine cycles for switch
       long accumSwitchTotal = 0;

       // accumulate total machine cycles for if
       long accumIfTotal = 0;

       // force code to do something rather than be optimised out of
existence
       long forcer = 0;

       // do forever
       for ( long trial = 0; ; trial++ )
           {
           // accumulate  machine cycles for switch for this trial
           long accumSwitchTrial = 0;

           // accumulate  machine cycles for if for this trial
           long accumIfTrial = 0;

           for ( long i = 0; i < ITERATIONS_PER_TRIAL; ++i )
               {
               final int random = wheel.nextInt( 10 );
               long start = nanoTime();
               final int rif;
               {
               if ( random == 0 )
                   {
                   rif = 20418437;
                   }
               else if ( random == 1 )
                   {
                   rif = 94704581;
                   }
               else if ( random == 2 )
                   {
                   rif = 45898144;
                   }
               else if ( random == 3 )
                   {
                   rif = 49094059;
                   }
               else if ( random == 4 )
                   {
                   rif = 77416885;
                   }
               else if ( random == 5 )
                   {
                   rif = 91322469;
                   }
               else if ( random == 6 )
                   {
                   rif = 40218964;
                   }
               else if ( random == 7 )
                   {
                   rif = 93641667;
                   }
               else if ( random == 8 )
                   {
                   rif = 29822916;
                   }
               else
                   {
                   rif = 625909;
                   }
               }
               accumSwitchTrial += nanoTime() - start;
               forcer += rif;
               start = nanoTime();
               final int rswitch;
               switch ( random )
                   {
                   case 0:
                       rswitch = 16336774;
                       break;
                   case 1:
                       rswitch = 62881795;
                       break;
                   case 2:
                       rswitch = 27998504;
                       break;
                   case 3:
                       rswitch = 9612956;
                       break;
                   case 4:
                       rswitch = 25592297;
                       break;
                   case 5:
                       rswitch = 77114095;
                       break;
                   case 6:
                       rswitch = 23554325;
                       break;
                   case 7:
                       rswitch = 55380051;
                       break;
                   case 8:
                       rswitch = 47971513;
                       break;
                   default:
                       rswitch = 41100793;
                   }
               accumIfTrial += nanoTime() - start;
               forcer += rswitch;
               }// end for iterations
           double ratio = (double) accumIfTrial / (double)
accumSwitchTrial;
           accumIfTotal += accumIfTrial;
           accumSwitchTotal += accumSwitchTrial;
           double averageRatio =
                   (double) accumIfTotal / (double) accumSwitchTotal;

           out.printf( "%6d  %6.02f    %6.02f\n", trial, ratio,
averageRatio );
           }
       }
}
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Oliver Wong - 04 Jul 2007 18:51 GMT
> [E:\com\mindprod\example]TestSwitch
> Calculate time for IF/time for SWITCH.  >1 means IF is slower
[quoted text clipped - 12 lines]
>
> In other words IF is just as fast as switch WHY??

   To clarify, when I said that switch-statements behave like a bunch of
if-statements, I meant at the semantic/behaviour level, not at the
performance level.

   However, these experiments just seem to reinforce the dogma: "Don't
optimize without profiling; your intuitions about performance are probably
wrong."

   - Oliver
Roedy Green - 04 Jul 2007 19:21 GMT
On Wed, 4 Jul 2007 13:51:27 -0400, "Oliver Wong"
<owong@castortech.com> wrote, quoted or indirectly quoted someone who
said :

>    To clarify, when I said that switch-statements behave like a bunch of
>if-statements, I meant at the semantic/behaviour level, not at the
>performance level.

You said " Yes, I think that's an accurate mental model of how the
switch statement works"

That sounded to me a description of how they behave under the hood.  I
was  puzzled when I read that which you meant.

We need a pair of adjectives:

1. one for a model describes the end result but is not necessarily
anything like how it is implemented.

2. one for a model that roughly describes what goes on at the machine
code level.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Patricia Shanahan - 05 Jul 2007 12:07 GMT
>>> So it looks like optimisers spend more time on IFs than SWITCH.
>>> This is puzzling.  Iin Assembler a jump table should be much faster
[quoted text clipped - 24 lines]
>   table. I have tried this, and it is indeed much faster than
>   the switch.

I think for both an if-sequence and a table switch the time would be
dominated by the unpredicted branch. The table switch has a single
branch to a dynamically selected location, with each of the ten
locations equally probable. The if goes through a cascade of conditional
branches, most of which are taken on most executions.

I would not base any predictions about real programs on this. It is
relatively rare for all cases in a switch to have equal probability, and
for there to be zero correlation between branch history and branch
behavior. Hardware is unlikely to be optimized for that case.

Patricia
Roedy Green - 05 Jul 2007 18:27 GMT
>I think for both an if-sequence and a table switch the time would be
>dominated by the unpredicted branch. The table switch has a single
>branch to a dynamically selected location, with each of the ten
>locations equally probable. The if goes through a cascade of conditional
>branches, most of which are taken on most executions.

An IF chain would get a boost from smart hardware that noticed a
pattern in distribution, but in this case the branches are equally
probable, so that would NOT help the IF implementation. Yet for some
reason IF is STILL  doing EQUALLY well!

Perhaps IF hardware can lookahead 10 steps or so?
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Roedy Green - 04 Jul 2007 16:35 GMT
On Wed, 04 Jul 2007 00:38:06 GMT, Roedy Green
<see_website@mindprod.com.invalid> wrote, quoted or indirectly quoted
someone who said :

>The -genasm+ switch in Jet seems to be discontinued so I can't easily
>figure out what sort of code it is generating for both.

A talked with the Jet people about this anomaly.  They said the
Pentiums have such damaged lookahead logic they do very badly on jump
tables.  However, that does not explain why AMD was slow too.

Unfortunately GenAsm in Jet, an undocumented feature to view generated
asm code, has been discontinued.  To solve this I will have to find a
cheap decent disassembler.  In the old 16-bit days I used one I liked
a lot called Sourcer, but his is no longer.  I have compiled a list of
candidates at
http://mindprod.com/jgloss/disassembler.html
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
ldv@mail.com - 05 Jul 2007 08:50 GMT
On Jul 4, 10:35 pm, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:
> On Wed, 04 Jul 2007 00:38:06 GMT, Roedy Green
> <see_webs...@mindprod.com.invalid> wrote, quoted or indirectly quoted
[quoted text clipped - 6 lines]
> Pentiums have such damaged lookahead logic they do very badly on jump
> tables.

This problem and many others are specific to Pentium 4, not the entire
Pentium line. AFAIK, the current Intel chips are in fact successors of
Pentium 3.

LDV
Guillermo Schwarz - 04 Jul 2007 00:19 GMT
I would rather prefer:

Map map = new HashMap();
map.put( y, #doThis() );
map.put( z, #doThat() );
map.put( null, #doSomethingElse() );
map.put( Default, #giveUp() );
map.switchOn( x );

> <julien.robins...@gmail.com> wrote in message
>
[quoted text clipped - 127 lines]
>
>     - Oliver
Twisted - 03 Jul 2007 22:05 GMT
On Jul 3, 7:40 am, julien.robins...@gmail.com wrote:
> switch: runs through all cases comparing with the operator "==". May
> accept null, and probably useless for strings.

Interning the strings makes them viable here.

> switch-equals:
> uses "equals()" to test each case. Requires passing an object (or uses
[quoted text clipped - 5 lines]
> If ever some y is null, throw NullPointerException of course. :-)
> and if x is null, of course it switches to default.

Why not allow null anywhere? Null is unequal to anything but null,
unless some object's ".equals(null)" returns true for whatever reason.

My own recommendation is to make switch use == on primitive
types, .equals on reference types, and give a warning when floats or
doubles are compared.

switch (primitive) {
case x:
...1
case y:
...2
break;
default:
...3
}

is made syntactic sugar for

if (x == primitive) {
...1
...2
} else if (y == primitive) {
...2
} else {
...3
}

for instance.

With a nonprimitive, you get

switch (object) {
case x:
...1
break;
case null:
...2
break;
default:
...3
}

turning into
if (object == null) {
...2
} else if (object.equals(x)) {
...1
} else {
...3
}

say. (Always the test for == null occurring first, with either the
appropriate case block or the default block's code, followed by any
others.)

But I've also got a good suggestion for any operator overloading.

Firstly, binary operators between reference types are allowed if both
compile-time types have a common superclass or implement a common
interface that specifies the corresponding method (including if the
compile-time types of both sides are equal and this type specifies the
appropriate method).

Secondly, operators are then just syntactic sugar as follows:
-x -> x.negate()
x + y -> x.add(y)
x - y -> x.subtract(y)
x * y -> x.multiply(y)
x / y -> x.divide(y)
x += y -> x = x.add(y)
++x -> x = x.increment() (and add this method to BigFoo; it returns a
new instance, representing a value one higher)
x++ -> (t = x, x = x.increment(), t)
--x and x-- analogously with a decrement() method
x ~= y -> x.equals(y) (a whole new operator; if ~= allowed for
primitive types it behaves the same as == for these)
!x (maybe allow as shorthand for x == null)
(various bitwise operators should correspond to their BigInteger
methods)

A key thing is that the implied method is always invoked on the left-
hand operand, with the right-hand operand (if any) as method argument.
This means that operators would be polymorphic only on the first
argument. Using double-dispatching or other patterns when implementing
your add, subtract, multiply, etc. methods in your own class hierarchy
would be able to give the benefits of bilateral polymorphism, of
course.

It would be desirable to be able to set a thread-local MathContext for
BigDecimal calculations and scope it somehow. I'd suggest a more
general "environment" or "context" mechanism built on a (hopefully
speeded-up!) threadlocal mechanism, whereby you can use code like

do switch (threadlocal: expression) { ... stuff ... }

(which overloads, unambiguously, existing keywords) to:
* Save the current value of the thread local somewhere
* Change it to "expression".
* Stuff
* Restore the old value of the thread local

It would be syntactic sugar for:

Object t3dsfgr838 = someThreadLocal.get();
someThreadLocal.set(expression);
try {
 stuff
} finally {
 someThreadLocal.set(t3dsfgr838);
}

where the temporary's name is guaranteed not to otherwise exist in
this scope.

There should then of course be built-in thread locals for some stuff
(such as math context to use for the forms of BigDecimal methods that
don't take an explicit one, and which overloaded + and the like would
use). Switching on a particular math context for a block of
calculations is then easy and natural:

do switch (Math.mathContext: myMathContext) {
 someBigDecimal = someOther + yetAnother;
 someBigDecimal *= 4; // Should accept mixed primitive/reference
 // types IF the reference type has a valueOf(foo) method
 // matching the primitive to use for promotion!
 someMoreCalculations();
}

And of course ThreadLocal should be made a) faster to access (at least
to just read) and b) generic (so with a ThreadLocal<String>, you would
not have to cast theThreadLocal.get() to String, etc.; why was this
done promptly for WeakReference et. al. but not ThreadLocal? Arrrgh!)
Tom Hawtin - 03 Jul 2007 23:12 GMT
> Secondly, operators are then just syntactic sugar as follows:

> x * y -> x.multiply(y)

I want to multiply my Matrix by five using: 5 * m

> It would be desirable to be able to set a thread-local MathContext for
> BigDecimal calculations and scope it somehow.

Ick. Best not call any other methods in that scope (for instance by
causing a class to load)...

>                                               I'd suggest a more
> general "environment" or "context" mechanism built on a (hopefully
> speeded-up!) threadlocal mechanism, whereby you can use code like

ThreadLocal is already pretty fast. I believe it spends most of its time
in Thread.currentThread().

> do switch (threadlocal: expression) { ... stuff ... }

> It would be syntactic sugar for:
>
[quoted text clipped - 5 lines]
>   someThreadLocal.set(t3dsfgr838);
> }

Why not just use a closure? In current syntax (with restricted closure):

    someThreadLocal.with(expression, new Runnable() {
            public void run() { ... stuff ... }
    });

Or in my suggested syntax for anonymous inner classes, the same thing
only less restricted:

    someThreadLocal.with(expression, ### { ... stuff ... });

In Gafter, et al, I believe (don't quote me) the equivalent is:

    someThreadLocal.with(expression) { ... stuff ... }

> And of course ThreadLocal should be made a) faster to access (at least
> to just read) and b) generic (so with a ThreadLocal<String>, you would
> not have to cast theThreadLocal.get() to String, etc.; why was this
> done promptly for WeakReference et. al. but not ThreadLocal? Arrrgh!)

(a) It is quite fast in comparison to BigDecimal operations.

(b) ThreadLocal is generic. IIRC, the example wasn't generified in 1.5.
In 1.6 the example has a bug (not from the original author).

http://java.sun.com/javase/6/docs/api/java/lang/ThreadLocal.html

Tom Hawtin
Stefan Ram - 03 Jul 2007 23:24 GMT
>> x * y -> x.multiply(y)
>I want to multiply my Matrix by five using: 5 * m

 I never liked the asymmetry of »x.multiply( y )«.
 I'd prefer:

x * y -> new BigDecimalPair( x, y ).multiply()

 (The object creation overhead can be optimizid
 away for such cases.)

 »5 m« might be written as follows:

new IntegerMatrixPair( 5, m ).multiply()

 Or, why not use static methods?

x * y -> BigDecimalPair.multiply( x, y );

IntegerMatrixPair.multiply( 5, m )

 Here, »BigDecimalPair« should be a friend of »BigDecimal« in
 the C++-sense of »friend«, and »IntegerMatrixPair« should be a
 fried of »Matrix«. - Java, of course, does not have a »friend«
 keyword.
Twisted - 04 Jul 2007 00:00 GMT
> >> x * y -> x.multiply(y)
> >I want to multiply my Matrix by five using: 5 * m
[quoted text clipped - 3 lines]
>
> x * y -> new BigDecimalPair( x, y ).multiply()

[snip stuff with static methods, friends...]

Yuck. Complicated. Ugly.

x op y with only one reference type is handled by dispatching on the
reference-type argument, and looking for its compile-time type to have
a suitable valueOf() static method. E.g.:

5 * m -> m.multiply(Matrix.valueOf(5));

So a static, Matrix-returning valueOf method that accepts one integer
argument needs to be in the class Matrix in this case, and if
MatrixReloaded is the actual runtime type of m,
MatrixReloaded.multiply (but just Matrix.valueOf) actually gets
called.

And of course 5 - m would be m.subtract(Matrix.valueOf(5)).negate(),
versus m - 5 being m.subtract(Matrix.valueOf(5)) -- this means we need
a reciprocal() method in Matrix for 5/m to be legal of course. It
should be allowed to throw anything, to accomodate your
MatrixNotInvertibleException, which if a checked exception needs to be
handled or declared by the method with the "5/m" expression in it.

(To get the expected behavior from e.g. 5*m requires Matrix.valueOf(5)
return a matrix with fives on the diagonal entries and zeros
everywhere else. This doesn't seem especially efficient, but
Matrix.valueOf(5) could return a ScaleMatrix subclass that has the
same overhead for creation and use as an Integer.valueOf(5). Matrix
can double-dispatch multiply(), resulting in
scaleMatrixFive.multiply2(m) basically occurring. And that, in turn,
could just boil down to "return m.scalarMultiply(5)". Or Matrix can
specifically check its parameter for being a ScaleMatrix with
instanceof or an isScaleMatrix() method call or whatever. And if
Matrix doesn't do some of these efficient things, someone can write a
subclass MatrixRevolutions that does!)
Stefan Ram - 05 Jul 2007 21:56 GMT
>>> x * y -> x.multiply(y)
>>I want to multiply my Matrix by five using: 5 * m
>I never liked the asymmetry of »x.multiply( y )«.
>I'd prefer:
>x * y -> new BigDecimalPair( x, y ).multiply()

 So, by now, the reader should be able to estimate
 which of the following two example lines I prefer:

     vvvvvvvvvvvvv
     (10..20).each { |i| puts i }          // ruby
     10.LoopTo(20) ( i => i.PrintLine() ); // C#
     ^^^^^^^^^^^^^

http://blog.bittercoder.com/PermaLink,guid,05fc0109-3215-410e-8009-447c1e74cacb.aspx
Tom Hawtin - 05 Jul 2007 23:35 GMT
>>>> x * y -> x.multiply(y)
>>> I want to multiply my Matrix by five using: 5 * m
[quoted text clipped - 8 lines]
>       (10..20).each { |i| puts i }          // ruby
>       10.LoopTo(20) ( i => i.PrintLine() ); // C#

But a range is a sensible type of object. It's not just some old
2-tuple. I prefer not hard coding range constants.

I don't like the symmetry of new BigDecimalPair( x, y ).multiply(). I
much prefer new TwoBigDecimalsAndAnOpTriple(x, y, MULTIPLY).evaluate().
Or getting a bit mathematical new BigDecimalExpression(x, new
BigDecimalUnaryOperator(y, MULTIPLY)).

Tom Hawtin
Stefan Ram - 05 Jul 2007 23:55 GMT
>I don't like the symmetry of new BigDecimalPair( x, y ).multiply(). I
>much prefer new TwoBigDecimalsAndAnOpTriple(x, y, MULTIPLY).evaluate().
>Or getting a bit mathematical new BigDecimalExpression(x, new
>BigDecimalUnaryOperator(y, MULTIPLY)).

 This might mean that

out.println()

 would be written as

new PrintStreamAndAMethodName( out, PRINTLN ).evaluate()

 It is more dynamic, because the operator or method name can be
 chosen at run time, but this benefit might not always make up
 for the additional overhead.

~~

 One reason for my preferences of pair classes is as follows:

 A large program can be maintained more easily, if for every
 operation one knows where to find it. So whenever, one looks
 for an operator on a pair of big decimals, it has to be in the
 class BigDecimalPair. The location of the operator source code
 can be determined by the types of its operands.

 (Ignoring inheritance and assuming that the dispatch uses the
 types of the operand expressions, not of the operand objects.)
Guillermo Schwarz - 04 Jul 2007 00:01 GMT
If we had closures (and unnamed functions a la Smalltalk), we could
use HashMaps instead of switch statements.

On Jul 3, 7:40 am, julien.robins...@gmail.com wrote:
> Small comment...
>
[quoted text clipped - 41 lines]
> All this said with the ignorance of a non-expert programmer... :-)
> JR
Jacques-Olivier Haenni - 04 Jul 2007 06:59 GMT
Hello,

> If we had closures (and unnamed functions a la Smalltalk), we could
> use HashMaps instead of switch statements.
>  

At my opinion, that's the very interesting thing in closures.  You can
then add new functionalities such as the 'switch-on-map' mentionned in
some previous post, or an (enhanced) 'for each' loop, or some thread
management functionalities only by modifying the API, without any other
change to the JVM ! (The API is easier to modify than the JVM, whether
it be by one of us or even by Sun.)

Ok, this could be done already now in a large extent with anonymous
classes, but the amount of boilerplate code to write make such solutions
quite heavy to use.

JO.

> On Jul 3, 7:40 am, julien.robins...@gmail.com wrote:
>  
[quoted text clipped - 46 lines]
>> JR
>>    
Twisted - 04 Jul 2007 07:11 GMT
On Jul 4, 1:59 am, Jacques-Olivier Haenni <jo_no_s...@haenni.info>
wrote:
> Ok, this could be done already now in a large extent with anonymous
> classes, but the amount of boilerplate code to write make such solutions
> quite heavy to use.

In a way, heavy use of closures for basic flow control and such is
"quite heavy to use" anyway, in terms of CPU and memory use. Have you
ever noticed that Smalltalk is v...e...e...e...e...r...r...r...y
s...l...o...o...o...w...w   ?

CPUs themselves probably need a redesign to cope with the sort of code
in question. Procedural code with branching conditionals is what they
natively execute. In cases where closure-based constructs can be
compiled down to such a thing on a JIT basis you're golden, but
otherwise...
tjmadden1128@gmail.com - 03 Jul 2007 15:18 GMT
> P.S. a URL with more in depth explanations of what exactly is being
> proposed would be handy about now.

Here is an unofficial list, with links to discussions:
http://tech.puredanger.com/java7

Tim
Hendrik Maryns - 03 Jul 2007 10:31 GMT
Joshua Cranmer schreef:
> (Yes, I realize that I am about to potentially unleash strong opinions.)
>
[quoted text clipped - 9 lines]
> @ Superpackages
> @ Removing checked exceptions

The only thing that I definitely support is the last one, but probably
in the unusual way: indeed, get rid of checked exceptions, by making
*all* exceptions checked.
For the skeptic: it can be done, see how Eiffel handles it.

Oh, and who the hell needs switch statements?

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
Roedy Green - 03 Jul 2007 14:02 GMT
On Tue, 03 Jul 2007 11:31:26 +0200, Hendrik Maryns
<hendrik_maryns@despammed.com> wrote, quoted or indirectly quoted
someone who said :

>Oh, and who the hell needs switch statements?

I use them all the time, nearly always with enums.

There are three ways of doing a computation. You can write a switch to
collect the 25 enums in three groups.  This is much easier code that
calling a method in each enum. You can see the big picture. It is
easier to maintain and proofread.

See http://mindprod.com/projects/scid.html 
for my proposal to have your cake and eat it too -- view code either
way.

The other place I use them is in writing finite state automata. One
nice feature of Java is if you leave out the default, it will warn you
if you have failed to mention one of the possibilities as a case
label.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
Twisted - 03 Jul 2007 22:22 GMT
On Jul 3, 5:31 am, Hendrik Maryns <hendrik_mar...@despammed.com>
wrote:
> > @ Removing checked exceptions
>
> The only thing that I definitely support is the last one, but probably
> in the unusual way: indeed, get rid of checked exceptions, by making
> *all* exceptions checked.
> For the skeptic: it can be done, see how Eiffel handles it.

Are you out of your cotton-picking MIND?! I don't want to have to
declare every method as "throws RuntimeException" just because just
about everything might throw NPE and any of several other assorted
bounds, arithmetic, etc. exceptions. And if you want Error declared
too, just forgeddaboudit.

You'd have to massively redesign the language to make this have any
beneficial effect, instead of people just slapping "throws
RuntimeException" on everything. For starters, you'd have to have
fields, parameters, and locals that could be null or could not be, say
with

String foo = whatever;
String? bar;

meaning foo is a String, and bar may be a String or null, to make this
at all workable. A lot of code that would generate NPE will simply not
compile without explicitly handling the possibility of a null then,
but it also means they'd have to rewrite the whole standard library(!)
and everyone would have to rewrite their legacy code(!!) ... if they'd
done this from the beginning it would have been a good idea, but
changing it now would trigger chaos that'd make the last-minute
scrambling to fix Y2K bugs look like a Sunday picnic. Note that non-
nullable fields would be required to be explicitly initialized or else
assigned in every constructor, whether directly or by constructor
chaining. The example above explicitly initializes the String foo. A
local variable would have to be assigned immediately on being declared
if it could not be null, e.g. String foo = whatever; but never String
foo. That alone would break nearly all code. A more minor alternative
is:

String! foo = whatever;
String bar;

Again bar is the one that can be null, but all legacy code works. But
you wouldn't see a decrease in implicitly NPE-capable code until the
new !-declarations became widespread in currently-used codebases, and
only then might having to declare this exception be anything but a
massive PITA. On the flip side, the ? version above would be a massive
PITA whether or not NPE became a checked exception at the same time...

And of course there's still the potential for the NPE to crop up at
runtime. The String!/String or String/String? distinction would
probably only exist at compile time, like generic type parameters do
now. Even if it did exist at run time, it would have to do something
if an attempt was made to assign null to the wrong reference, and the
obvious thing is to eagerly throw the NPE that would otherwise happen
anyway but happen further from the location of the buggy code.

Oh, and speaking of generics and type erasure, the #2 exception on the
official 10 Most Annoying If They Became Checked Exceptions list
is ... you guessed it ... ClassCastException...
Hendrik Maryns - 04 Jul 2007 14:45 GMT
Twisted schreef:
> On Jul 3, 5:31 am, Hendrik Maryns <hendrik_mar...@despammed.com>
> wrote:
[quoted text clipped - 5 lines]
>
> Are you out of your cotton-picking MIND?!

No.

> I don't want to have to
> declare every method as "throws RuntimeException" just because just
> about everything might throw NPE and any of several other assorted
> bounds, arithmetic, etc. exceptions. And if you want Error declared
> too, just forgeddaboudit.

Well, once all exceptions are checked, the throws X statement would be
superfluous anyway, so no argument.

> You'd have to massively redesign the language to make this have any
> beneficial effect,

Indeed, that’s why it is never going to happen.  But I cannot follow
your argument which I snipped away, to be honest.  I do not think it is
valid.
Once again: if you want to see how it can be done, have a look at Eiffel
error handling.  It looks a bit minimalistic at first, but it is as
simple as it can get.
(http://docs.eiffel.com/eiffelstudio/general/guided_tour/language/tutorial-09.html)

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
Twisted - 04 Jul 2007 22:34 GMT
On Jul 4, 9:45 am, Hendrik Maryns <hendrik_mar...@despammed.com>
wrote:
> Indeed, that's why it is never going to happen.  But I cannot follow
> your argument which I snipped away, to be honest.  I do not think it is
> valid.

You can't snip the whole argument and handwave "I do not think it is
valid" and expect to be believed. Either respond in detail and marshal
some evidence to support your POV, or forget about it. If you have a
detailed proposal for how to make all the RuntimeExceptions checked
without driving Java programmers mad (or everyone just spalling
"throws RuntimeException" on every method), then by all means spell it
out. But pointing us to some Web site regarding some other programming
language entirely is a cop-out. We want to discuss these ideas here in
the newsgroup, not go off someplace else and read a monologue on the
subject where we can't reply with our own thoughts, and which isn't
even based on Java.

P.S. whether it is doable with RuntimeException or not, I think it's
frankly impossible with Error. Those can literally pop up anywhere.
Any "new" can throw OOME, for instance, and therefore any method call
might, since it might have a "new" in it directly or by way of further
calls. Making those checked really would just force everyone to put an
explicit "throws Error" on every method. Right now, basically, a
"throws RuntimeException, Error" is implied on every method
declaration, and I think that's just fine...
Hendrik Maryns - 05 Jul 2007 15:35 GMT
Twisted schreef:
> On Jul 4, 9:45 am, Hendrik Maryns <hendrik_mar...@despammed.com>
> wrote:
[quoted text clipped - 4 lines]
> You can't snip the whole argument and handwave "I do not think it is
> valid" and expect to be believed.

You’re right, sorry.

> Either respond in detail and marshal
> some evidence to support your POV, or forget about it.

I already indicated that I did not understand your argument.  I do not
see any reason at all to introduce non-nullable variables etc., I do not
even see how it is related to checked exceptions.
Since I do not grasp your concerns, it is impossible for me to reply to
them.
> If you have a
> detailed proposal for how to make all the RuntimeExceptions checked
> without driving Java programmers mad (or everyone just spalling
> "throws RuntimeException" on every method), then by all means spell it
> out.

Of course I do not have such a proposal.  However, I just wanted to
point out that it isn’t impossible.

> But pointing us to some Web site regarding some other programming
> language entirely is a cop-out. We want to discuss these ideas here in
> the newsgroup, not go off someplace else and read a monologue on the
> subject where we can't reply with our own thoughts, and which isn't
> even based on Java.

ACK.

> P.S. whether it is doable with RuntimeException or not, I think it's
> frankly impossible with Error. Those can literally pop up anywhere.
[quoted text clipped - 4 lines]
> "throws RuntimeException, Error" is implied on every method
> declaration, and I think that's just fine...

Indeed.  Maybe on second thought, I am all in favor of getting rid of
checked exceptions, since all exceptions should be handled _always
anyway_.  Even OOME, be it that you do not do anything and just quit
(that is also a way of handling it).  So basically, every function
should be put in a try catch block.  But then, what is it for, if it is
always there?  If you think this further, you might as well leave that
out and just attach to each method a block that describes what to do in
case of failure.  That is basically what Eiffel does.

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
Oliver Wong - 04 Jul 2007 23:43 GMT
>> On Jul 3, 5:31 am, Hendrik Maryns <hendrik_mar...@despammed.com>
>> wrote:
>>> get rid of checked exceptions, by making
>>> *all* exceptions checked.
>>> For the skeptic: it can be done, see how Eiffel handles it.
[...]

> Well, once all exceptions are checked, the throws X statement would be
> superfluous anyway, so no argument.

   To me, a checked exception is one you have to either handle or
explicitly throw, and an unchecked exception is one which you do not need
to handle nor explicitly throw. The terms are only meaningful in contrast
to each other. I can't see a difference between a language which has only
"unchecked exceptions" (and thus you never need to declare a throw), and a
language which has only "checked exceptions" (and thus you never need to
declare a throw).

   It may be more productive to focus the debate on:
   1) Should there be a duality of checked vs unchecked exceptions, or
should there only be one type of exception?
and 2) If the latter, should this "only one type" of exception have
enforced throw declaration, or forbid any type of throw declaration
whatsoever, (or perhaps allow the throw declarations, but make them
optional, as a form of documentation, and have no effect on behaviour of
the program)?

   FWIW, I think Sun got this part of the language design right and that
there is value in having two different types of exceptions.

   - Oliver
Wojtek - 05 Jul 2007 00:24 GMT
Oliver Wong wrote :
>     FWIW, I think Sun got this part of the language design right and that
> there is value in having two different types of exceptions.

Indeed there is.

If I have the following:

public class Foo
{
 public static final int BAR   = (new FooBar("foobar")).getIndex();
 public static final int BAR_2 = (new FooBar("foobar2").getIndex();
}

If the constructor for FooBar("") is defined as throwing a checked
exception, how do you handle it?

OTOH, if it throws an unchecked exception, then this is valid code, and
some other part of the JVM will catch it.

Note: This type of construct should ONLY ever fail during the coding
process, where the developer can fix it. I use it to to make sure that
the passed parameter is uniquely named.

Note2: There are other constructs to attach the new FooBar to the class
Foo, but they are not relevant to this discussion...

Signature

Wojtek :-)

Piotr Kobzda - 05 Jul 2007 08:40 GMT
> Oliver Wong wrote :
>>     FWIW, I think Sun got this part of the language design right and
[quoted text clipped - 12 lines]
> If the constructor for FooBar("") is defined as throwing a checked
> exception, how do you handle it?

Simply:

public class Foo
{
  public static final int BAR;
  public static final int BAR_2;
  static {
    try {
      BAR   = (new FooBar("foobar")).getIndex();
      BAR_2 = (new FooBar("foobar2").getIndex();
    } catch(Exception e) {
      throw new ExceptionInInitializerError(e);
    }
  }
}

> Note2: There are other constructs to attach the new FooBar to the class
> Foo, but they are not relevant to this discussion...

They are relevant (at least the above solution is).  Custom exception
handling is the only difference between the solution and your example
above (in both cases fields initializers' code is executed in a class
initializer).

piotr
Wojtek - 05 Jul 2007 16:15 GMT
Piotr Kobzda wrote :
>> Oliver Wong wrote :
>>>     FWIW, I think Sun got this part of the language design right and that
[quoted text clipped - 28 lines]
>    }
> }

But does not the final keyword preclude this?

And I also get an error that BAR has not been initialized.

Signature

Wojtek :-)

Tom Hawtin - 05 Jul 2007 16:45 GMT
> Piotr Kobzda wrote :
>> Simply:
[quoted text clipped - 14 lines]
>
> But does not the final keyword preclude this?

Does the final keyword preclude:

class Fred {
    private final int value;
    public Fred(int value) {
        this.value = value;
    }
}

?

What is really annoying is that, for reasons I am not familiar with, you
cannot write Foo.BAR = 42;.

Tom Hawtin
Piotr Kobzda - 05 Jul 2007 17:48 GMT
> What is really annoying is that, for reasons I am not familiar with, you
> cannot write Foo.BAR = 42;.

The reason seams to be there:
http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.5.6.2

bullet 2.3:

"* Otherwise, if the class variable is declared final, then Q.Id denotes
the value of the class variable. The type of the expression Q.Id is the
declared type of the class variable after capture conversion (§5.1.10).
If Q.Id appears in a context that requires a variable and not a value,
then a compile-time error occurs."

piotr
Piotr Kobzda - 05 Jul 2007 17:15 GMT
> But does not the final keyword preclude this?

As long as this follows the JLS rules for final fields (blank final in
this case) it doesn't.

See:
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#35962

> And I also get an error that BAR has not been initialized.

I don't have it.

<sscce>
public class Foo
{
  public static final int BAR;
  public static final int BAR_2;
  static {
    try {
      BAR   = (new FooBar("foobar")).getIndex();
      BAR_2 = (new FooBar("foobar2")).getIndex();
    } catch(Exception e) {
      throw new ExceptionInInitializerError(e);
    }
  }
}
class FooBar {
  FooBar(String s) throws Exception {}
  int getIndex() { return 0; }
}
</sscce>

piotr
Wojtek - 05 Jul 2007 18:23 GMT
Piotr Kobzda wrote :

>> But does not the final keyword preclude this?
>
[quoted text clipped - 7 lines]
>
> I don't have it.

Eclipse gives the error.

Signature

Wojtek :-)

Roedy Green - 03 Jul 2007 13:54 GMT
On Mon, 02 Jul 2007 21:27:16 GMT, Joshua Cranmer
<Pidgeot18@verizon.net> wrote, quoted or indirectly quoted someone who
said :

>@ Closures
Not keen. I think this will needlessly make code hard to understand by
the general programmer.

>@ Strings in switch statements
Not as big as deal as it once was now there are enums.  The feature
will encourage inefficient code.  I would like instead RANGES of ints
and enums that generate better code and code easier to maintain than
you would do manually.  This is a relatively trivial extension,
requiring no JVM change. See
http://mindprod.com/projects/caserange.html for what I a would like.

>@ Operator overloading for BigDecimal
fine. This can probably be done without a JVM change.

>@ Language-level XML support
I detest XML. So oppose this on general principles.  I want XML to
die. This will just encourage it. see
http://mindprod.com/jgloss/xml.html
for my reasons for wanting to stamp out XML. I have the same disgust
for XML I have for grossly overweight gluttons and people enjoy
deliberate waste.  Perhaps if it is done in a representation
independent way, XML can quietly be replaced without anyone noticing.

>@ Reified generics
I don't know what that means.  Reify means to regard or treat (an
abstraction) as if it had concrete or material existence. Does this
mean tossing out type erasure?  Generics are an embarrassment to the
language.  I personally would like to start from scratch and see if
they can be made 10 time times simpler and wart-free.

>@ Superpackages
Probably just paying attention to the dots in package names. For ant
bundling it would be nice to just have to specify one name to grab
everything related.

>@ Removing checked exceptions
NO. That will just lead to sloppy code. Java is not PHP.

--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com