Search |
||
Strings in switch and closuresPosted by forax on November 15, 2009 at 7:28 AM PST
As you perhaps already know, jdk7 milestone 5 (jdk7b76) is
out.
Switch on String
This one of the small proposal changes (from
Coins's project) to Java language in order to
allow to switch on String values.
$ java StringSwitch hello hello $ java StringSwitch -verbose hello hello switch string Here is the corresponding Java code:
public class StringSwitch {
public static void main(String[] args) {
boolean verbose = false;
for(String arg:args) {
switch(arg) {
case "hello":
if (verbose)
System.out.println("hello switch string");
else
System.out.println("hello");
break;
case "-verbose":
System.out.println("verbose mode activated");
verbose = true;
break;
}
}
}
}
And without jdk7 Here is another program with the same semantics but without the switch on strings. It uses a HashMap to avoid a cascade of if/else which could be very slow (*). So for each string, I associate a runnable, which is the code to run if the string match. Also note that because I define the code to run using an anonymous class, the local variable verbose has to be a captured and because this variable is modified, I use the usual workaround and declare it has an array of one element. * Ok, in this example, because there is only two strings, this is not that slow.
public class StringHash {
public static void main(String[] args) {
final boolean[] verbose = new boolean[]{false};
HashMap<String,Runnable> map =
new HashMap<String, Runnable>();
map.put("hello", new Runnable() {
@Override
public void run() {
if (verbose[0])
System.out.println("hello switch string");
else
System.out.println("hello");
}
});
map.put("-verbose", new Runnable() {
@Override
public void run() {
System.out.println("verbose mode activated");
verbose[0] = true;
}
});
for(String arg:args) {
Runnable runnable = map.get(arg);
if (runnable!=null)
runnable.run();
}
}
}
With closure In fact, the program above define two closures. By definition a closure is a function that is able to capture variables. Java 7 will not include a closure syntax but jdk7 VM already includes runtime support for closures. The current status of closure in Java can be seem as the opposite of the status of generics. Generics are a compiler artifact not understood by the VM (there is no reification). Closure are understood by the VM (using the package java.dyn) but there are not known by the Java type system. The program below shows how to use method handle to solve our running problem. findStatic creates a method handle from an existing method (*) found by providing its declaring class, its name and its signature; a MethodType. insertArgument (also named currying) is a way to bound a value to a method handle to create a closure. Like with anonymous class syntax, the bounded value is a value and not a variable. Calling a method handle is done by using the method invoke which is polymorphic; that's why you have to specify the return type; the VM will verify that the declared types and the MethodType of the method handle are identical. * In a close future, this will be done in one instruction by the VM, but I don't know if this instruction will surface in Java.
public class StringMH {
private static void hello(boolean[] verbose) {
if (verbose[0])
System.out.println("hello switch string");
else
System.out.println("hello");
}
private static void verbose(boolean[] verbose) {
System.out.println("verbose mode activated");
verbose[0] = true;
}
public static void main(String[] args) {
boolean[] verbose = new boolean[]{false};
HashMap<String,MethodHandle> map =
new HashMap<String,MethodHandle>();
Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.make(void.class, boolean[].class);
MethodHandle helloMH = lookup.findStatic(StringMH.class, "hello", methodType);
MethodHandle verboseMH = lookup.findStatic(StringMH.class, "verbose", methodType);
map.put("hello", MethodHandles.insertArgument(helloMH, 0, verbose));
map.put("-verbose", MethodHandles.insertArgument(verboseMH, 0, verbose));
for(String arg:args) {
MethodHandle mh = map.get(arg);
if (mh!=null)
mh.<void>invoke();
}
}
}
Because method handle code in the VM is not production ready you have to add some flags to be able to run this program. The VM will also output a warning saying that the JDK and the VM code are not aligned fortunately this program doesn't use that part of the code. java -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic StringMH -verbose hello
Enough fun for today, see you soon.
»
Related Topics >>
Blogs Comments
Comments are listed in date ascending order (oldest first)
Hot curry
Submitted by forax on Sun, 2009-11-15 18:28.
Hi Damon,
As far as I know, Hotspot does two kinds of optimisation on MethodHandles.insertArguments.
Rémi Closures synyax
Submitted by sveryovka on Mon, 2009-11-16 04:16.
I understand that support of closures syntax is not in the scope defined for jdk 7.
But what I find very bad is that work on closures syntax for java (see http://javac.info/ and closures-dev mailing list) was stopped long time ago and nothing happens there.
I believe that now having jvm support for closures it a right time to resume work closures syntax support for java programming language.
I understand that it is not you who makes such decisions but just wondered if you have header anything about plans for closures syntax for java programming language.
Thanks,
Serhiy
The community has shown
Submitted by jwenting on Tue, 2009-11-17 01:50.
The community has shown clearly that closures (or function pointers, which is what they really are) are not a desired addition to the language. It's only a small group of people with no feeling with what's happening in the real world who are trying to push them. Having support for them at bytecode format allows their use in other languages that are available on the JVM, forcing them down the throat of Java developers is not at all the same thing and certainly is not desirable.
Re: the community has shown
Submitted by forax on Tue, 2009-11-17 02:17.
Hi Jeroen,
I think you're wrong. Python has closure, Ruby has closure, Javascript has closure, Groovy has closure, Objective-C has closure, C# has closure, C++ will have closure (just to cite some mainstream non-functional languages) so closures seem to answer to some common problems. Even Java has closure, anonymous classes are a kind of closure but the syntax requires to declare an interface which is stupid.
I want to be able do concurrency, with co-coroutine, etc. in Java
(see http://www.ibm.com/developerworks/java/library/j-jtp03048.html)
that why I need closure. Saying that I havent the feeling to be deconnected from the Java community.
cheer, goto also
Submitted by atripp on Tue, 2009-11-17 09:36.
COBOL has goto, FORTRAN has goto, BASIC has goto, C has goto, C++ has goto, C# has goto, pascal has goto, perl has goto. So goto seems to answer some common problems.
Even Java has goto, labelled breaks are a kind of goto.
The issue is not whether or not the feature *can* be useful, it's whether its typical real-world usage will cause code to be more or less maintainable.
Re: goto also
Submitted by forax on Tue, 2009-11-17 10:11.
Andy,
You're right goto is useful :) So the question seems to be "Is the following code maintainable or not":
List<String> list = ...
Collections.forEach(list, lambda(String value) {
System.out.println(value);
});
with Collections.forEach declared like this:
void forEach(Collection<? extends E> c, fun void(E) closure) {
for(E element: c) {
closure.invoke(element);
}
}
In my opinion, it's not far from actual Java.
I don't see why you can claim it's less maintainable.
cheers, real world?
Submitted by petere on Tue, 2009-11-17 19:18.
I'm not sure why you're so categorically against lambdas in Java. They are very useful in simplifying code and reducing code size. Code is more maintainable when it's easier to read, code is easier to read if it has less boilerplate obscuring the actual functionality. Lambdas help quite a bit in this regard.
real world.
Submitted by atripp on Wed, 2009-11-18 10:47.
I'm not sure why you'd think I'm categorically against lambdas in Java. All I did was point out the fallacy of the "other languages have it so it must be good" argument.
Real World
Submitted by forax on Wed, 2009-11-18 10:53.
Sorry Andy, Rémi The community has shown
Submitted by thedet on Thu, 2009-11-19 05:48.
The community has shown clearly that closures (or function pointers, which is what they really are) are not a desired addition to the language.
It's sad to recognise after such a long time I'm now working with Java (since 1.1.4), that I am obviously not considered as part of "the community". It's only a small group of people with no feeling with what's happening in the real world who are trying to push them. It's hard to suddenly wake up and see that apparently all my professional enterprise programming of the last years was only a bad dream and not the "real world". But on the other hand: perhaps the definition of "the community" and "the real world" has been made by someone sitting in a cave and looking at the shadows on the wall... forcing them down the throat of Java developers is not at all the same thing and certainly is not desirable. Like it has happened with Generics? It is really a pity that people working in a business called "development" are so locked against modernisations that they consider them as "forcing something down their throats". Overly complicated examples
Submitted by icewalker2g on Tue, 2009-11-17 17:17.
I personally think the "Without JDK 7" example has been overly complicated for such a small problem as comparing strings, just to sell the idea of closures some how. Using a Runnable just to run a match?
Re: Overly complicated example
Submitted by forax on Tue, 2009-11-17 18:35.
I agree with you. If you want some real use cases: the scanner used by javac to match keywords doesn't use a cascade of if/else, any SAX parser handlers will not use (reality: should not use) a cascade of if/else. Now let me dream, just a bit. Suppose that Josh Bloch comes with an implementation of map literal (which one of the small language changes of Coin project) and suppose that Java supports closures, your overly complicated code can be written like that::
shared boolean verbose = false;
Map<String, fun void()> map = {
"hello": lambda() {
System.out.println("verbose mode activated");
verbose = true;
},
"-verbose": lambda() {
if (verbose)
System.out.println("hello switch string");
else
System.out.println("hello");
}
};
for(String arg:args) {
fun void() option= map.get(arg);
if (option!=null)
option.invoke();
}
Cheers, Remy, What about: boolean
Submitted by twilightworkshop on Wed, 2009-11-18 09:06.
Remy,
What about:
boolean verbose = false;
for(String arg:args) {
switch(arg.hashCode()) {
case HELLO_HASHCODE:
if (verbose)
System.out.println("hello switch string");
else
System.out.println("hello");
break;
case VERBOSE_HASHCODE:
System.out.println("verbose mode activated");
verbose = true;
break;
}
}
}
Best,
Mike
Using hashcode
Submitted by forax on Wed, 2009-11-18 09:17.
This is what jdk7's javac generates when you do a switch on String. BTW, do you see that you can't declare VERBOSE_HASHCODE like that: private static final int VERBOSE_HASHCODE = "-verbose".hashCode(); Rémi Yes, I usually compute the
Submitted by twilightworkshop on Wed, 2009-11-18 09:53.
Yes, I usually compute the value in an interactive interpreter of mine, then put the code
private static final int VERBOSE_HASHCODE = 1468161205; // "-verbose".hashCode()
Yes, I usually compute the
Submitted by thedet on Thu, 2009-11-19 05:29.
Yes, I usually compute the value in an interactive interpreter of mine, then put the code
Does anyone else but me get the feeling that this is another example for letting tools do what the language itself should do? So an "interactive interpreter" is now part of the IDE, necessary to write meaningful Java code? To me it is like adding values with a desk calculator to put the result into Excel cells ... |
||
|
Aha! Currying! Now, does