I am an architect at Kayak.com working mainly with Java. I focus on performance problems at work and occasionally on computer graphics as a hobby when I find the time. Derek has posted 5 posts at DZone. View Full User Profile

Java as a Scripting Language?

09.03.2008
| 10029 views |
  • submit to reddit

I came across a language comparison (which I wish I could still find) where the author presented a code sample in many different languages. The example he chose was computing the MD5 digest of a string. He showed a verbose Java version, some python etc. Finally php:

md5("Hello World");

This example, the author asserted, showed that PHP coders can do as much with one line as a Java coder can do in 20. Of course any problem is easy in any language if there’s an available library call that’s just right.

When I have to write a program to work with lines of text I’ll usually turn to Ruby or possibly Groovy (sorry Perl – not going there anymore). Scripting languages like these are usually geared toward text processing and their built in libraries make these jobs easy. I wouldn’t jump into Java because it’s such a pain to do this kind of thing.

Ruby

File.open("myfile.txt").each { |line|
puts line if line =~ /blue/
}

some standard Java to do the same thing

import java.io.*;

public class ProcessWords {
public static void main(String [] args) throws IOException {
BufferedReader input = new BufferedReader(
new FileReader("myfile.txt"));
String line;
while ((line = input.readLine()) != null)
if (line.indexOf("blue") != -1)
System.out.println(line);
input.close();
}
}

The Java code is obviously more verbose and uglier, matching many people’s opinion of Java in general. But is this because of the language or the API? Java’s APIs are all very general and give you complete control over everything you do. Ruby’s APIs make it easy to perform this common task.

You could easily create a TextFile class in Java with a linesMatching method that returned Iterable<String> allowing you to iterate over lines that matched a regular expression. Now the task is easy:

public class ProcessWords {
public static void main(String [] args) throws IOException {
for (String line : new TextFile("myfile.txt").linesMatching("blue")) {
System.out.println(line);
}
}
}

The designers of Ant decided programmers like writing in XML. But I don’t. I’d rather write in Java than XML. Would ant build scripts be better expressed in Java?

My hypothetical translation into Java.

public class Ant implements ProjectDefinition {
void targets(Project project) {
project
.add(new Target("clean") {
void execute(Tasks tasks) {
tasks.delete("build");
}
})

.add(new Target("compile") {
void execute(Tasks tasks) {
tasks.mkdir("build/classes");
tasks.javac("src").destdir("build/classes");
}
});
}
}

Both definitions are roughly the same size. The hypothetical Java version definitely has some cruft but is reasonably compact. Like Rake though, the Java version would allow you to use the power of a real language in your build script – conditionals loops, dynamic targets, variables. A Java version would give you instant IDE support, debugging, profiling on top of that.

Both the line iteration and ant project definition examples show internal domain specific languages. The first domain is text processing. Scripting languages compete in this space, but I would argue it has a lot more to do with the libraries they provide than the language syntax. The second domain is build configurations. With the right APIs Java would do a very good job here too.

Of course Java does have several strikes against it when you actually consider its use for scripting:

  1. you have to compile all the files which turns some people off. You could easily write a ClassLoader to compile the code on the fly.
  2. Java starts up slowly, which kills the performance of very quick scripts, if that matters.
  3. Java has no meta programming. This is probably the biggest issue, although reflection and code generation can help here. (You could generate the ant task APIs for my build script example).

I think more user friendly APIs could be written for Java for areas like text processing, XML parsing and creation, threading (even easier than java.util.concurrent), and file operations. Joda Time is a great example of a library that is cleary superior to Java’s in this respect.

When I write an API (in any language) I try to think of what would make the user happiest when coding against it, not what necessarily matches the implementation. Chained method calls for example don’t help at all in the implementation of a class, but returning this from each method can help the callers in some cases and is easy enough to justify. In some cases providing a little internal DSL instead of a collection of getters/setters and unrelated methods makes the code a lot more readable and helps keep the focus on the caller instead of the implementation.

From http://dmy999.com/

Published at DZone with permission of its author, Derek Young.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

ff aaa replied on Wed, 2008/09/03 - 5:36am

nice, and i agree java can do pretty good with well designed helpers. i had a similar approach with SimpleFileReader class. Also a similar blog enrty.

 

 

 

Ray Krueger replied on Wed, 2008/09/03 - 6:10am

This is exactly why I like Groovy! All the power of the JVM and the classes and libraries that are already built for Java; supporting a language that's easy on the eyes and totally familiar to any Java geek.

Your Ant example above is totally possible, but I'd definitely rather use Gant or Buildr personally.

Ricky Clarkson replied on Wed, 2008/09/03 - 6:33am

"This is exactly why I like Groovy! All the power of the JVM and the classes and libraries that are already built for Java; supporting a language that's easy on the eyes"

And behaves completely differently.  I know I keep saying this, but int i="hello"; is valid Groovy code, but the Groovy homepage claims Groovy supports static typing.  No.  Static things are checked without running the code.  That's what static means.

Dan Howard replied on Wed, 2008/09/03 - 12:46pm

Also look at BeanShell. This is truly JAVAScript.

phil swenson replied on Wed, 2008/09/03 - 2:21pm

I personally am a fan of using JRuby's Rake and using the AntWrap gem.

I also have used Gant and it's very similar, and Gant itself is pretty nice.... I do find a lot of groovy-isms very irritating.  For example it's not truly scripted, if you pull in java files to your build to leverage you have to have them compiled.  Given that it's a build script, this is problematic.  Groovy also gives the most heinous stack dumps I've ever seen.  Every exception has about 100-200 lines of groovy cruft that has nothing to do with the error.  Neither of these issues are easy to solved due to the nature of Groovy.  Don't get me wrong, I like Groovy pretty well but just prefer Ruby.

I find Ruby a more pure solution.

Here's a snippet of a ruby rake file:

@ant = Antwrap::AntProject.new(:ant_home=>'/usr/share/ant')
@ant.mkdir(:dir =>  "classes")
@ant.path(:id => "common.class.path"){
  @ant.fileset(:dir => "#{common_lib_dir}"){
    @ant.include(:name => "**/*.jar")
  }
}

desc "clean the classes directory"
task :clean do
  @ant.delete(:dir => "classes")
end

desc "generate war file"
task :war =>[:compile] do
  @ant.war(:update => false, :destfile=>"ei.war", :webxml=>"../web/WEB-INF/web.xml"){
    @ant.fileset(:dir => web_dir)
  }
end

task :default => [:compile]

desc "compile java classes"
task :compile do
  puts "compiling java classes to [classes]..."
  @ant.javac(:srcdir => "../src", :destdir => "classes", :deprecation=>true, :debug=>true, :fork=>true){
    @ant.classpath(:refid => "common.class.path")
    @ant.compilerarg(:value =>"-Xlint")
  }
end
 

Collin Fagan replied on Wed, 2008/09/03 - 2:58pm

If you are going to tlak about Java as a scripting language don't forget Beanshell (http://www.beanshell.org/).  The syntax is 99% java with just a few small changes to make scripting tasks easier. 

Alex Prayle replied on Wed, 2008/09/03 - 7:29pm

A task commonly required by one developer may never be required by another.

You just need to either find or build a more special purpose Java library to do whatever tasks you commonly do as concisely as you require:

So for example, if text file processing is your thing, the above example could be implemented even more concisely in Java as:

extractLines("myfile.txt", new ContainsCriteria("blue"), System.out);

or even

extractLinesContaining("myfile.txt", "blue");

A more general purpose API will generally require more code to use it.

 

 

 

 

 

 

 

 

 

phil swenson replied on Wed, 2008/09/03 - 9:09pm in response to: Alex Prayle

"A task commonly required by one developer may never be required by another.

You just need to either find or build a more special purpose Java library to do whatever tasks you commonly do as concisely as you require"

Yeah, you can do what everyone does and write a bunch of utility classes like they did for the Apache Commons.  But I don't think Sun deserves a defense here.  They always pick the most complex use cases and ignore the common ones.  I don't mind handling the complex cases, but why do you have to deal with streams for opening a file?  It's silly.  Most other languages make it easy.  There is a reason almost every project has classes like "XMLUtil, FileUtil, StringUtil, EmailUtil, etc."  It's because Sun makes things much more complicated than they need to.

Ray Krueger replied on Wed, 2008/09/03 - 9:43pm in response to: Ricky Clarkson

 

I know I keep saying this, but int i="hello"; is valid Groovy code

 

You probably shouldn't keep sayin it then, because you're wrong :)

int i="hello"

This is not valid groovy code. You've declared i to be of type int, and therefore cannot assign a string to it. Just like Java :)

If you want to drop the type declaration and make it valid to swap types you can "def" it without a type.

def i = "hello"
i = 10
println i

That's valid groovy code, because I've explicitly stated that I don't care what i is, really all I care about is that it has a toString() for the println call.

Ricky Clarkson replied on Thu, 2008/09/04 - 12:31am

int i="hello"; is valid Groovy code.  The compiler happily generates .class files.  Yes, it throws an exception at runtime, but it should not get past the compiler if Groovy supports static typing.

Artur Biesiadowski replied on Fri, 2008/09/05 - 8:14am in response to: Ricky Clarkson

[quote=rickyclarkson]int i="hello"; is valid Groovy code. The compiler happily generates .class files. Yes, it throws an exception at runtime, but it should not get past the compiler if Groovy supports static typing.[/quote]

I think that there is confusion about static versus strong typing. Plus even in java you can do

int a = (Integer)(Object)"test"; 

which can be perfectly detected by compiler to be impossible and will fail only on runtime. Number of casts you have to do to fool the compiler is not a real difference between staticically/stronly types languages and their counterparts.

Mike P(Okidoky) replied on Fri, 2008/09/05 - 12:16pm in response to: Ricky Clarkson

And not only that, even if Groovy *knows* that a type is set, it still makes a function call for each operation, totally crippling performance.

The Groovy boys should *really* fix this !  Without it, they can *not* expect to be taken seriously.

Thomas Mueller replied on Sun, 2008/09/07 - 2:15pm in response to: ff aaa

[quote]Would ant build scripts be better expressed in Java?[/quote] I have started the project PJMake, a Pure Java Make tool. I use this build tool in my H2 Database Engine. The target described in the article would look like this:

public class Build extends BuildBase {
void clean() {
delete("build");
}
compile() {
mkdir("build/classes");
javac(new String[] {"-d", "build/classes", "-sourcepath", "src" }, getFiles("src"));
}
}

Ricky Clarkson replied on Mon, 2008/09/08 - 3:56am

"I think that there is confusion about static versus strong typing"

Strong typing means whatever you want it to on the day.  Static typing at least has a reasonably well-accepted definition.

"Plus even in java you can do int a = (Integer)(Object)"test";"

Every static type system disallows some valid programs, and allows some invalid programs (until you get to dependent typing, perhaps).  Their quality doesn't make them more static or less static, just more useful or less useful.  Haskell, for example, has no cast operator (though you can write one through 'unsafe' code), disallowing a huge set of invalid programs, but requiring the refactoring of some valid ones.

Henry Story replied on Mon, 2008/09/08 - 6:17am

Tim Boudreau had recently also suggesting replacing Ant with Java using a similar argument as the one given above. But I think what is missing here is something a lot more important. Replacing ant with java, with Groovy, with python etc. is all much of a muchness.  You end up loosing something, which sadly Ant does not make very clearly visible. Networked data, or hyperdata.

 What would be a lot more interesting would be to replace ant with RDF, as I argue on a post of the same name. This is because most applications now rely on libraries distributed around the web. Doing that in Java too is possible, but it really is not designed for it. (Some very good RDF stores and libraries are written in Java on the other hand)

Dominique De Vito replied on Mon, 2008/09/08 - 8:04am

I rather prefer to script with Java than ANT, if possible. Because, following that way I can increase my own Java library that could be used also for my other Java projects.

 

It could be interesting for the Java community to promote and support a Java-syntax-like language for scripting, may be a DSL, at least, a language that could be easily compiled into Java. I see the following advantages:

- no more cumbersome XML (in fact the creator of ANT says he is not now happy to have introduced XML into ANT),

- full advantages for calling Java APIs (easier than ANT)

- easier to learn for Java programmers

- it could be an experimental platform for introducing, for example, programming sugar that could be next introduced into the Java language itself

- it could be also a good testbed for Java API in order to know if they are complete enough or if they provide short ways in order to program concisely.

 

phil swenson replied on Mon, 2008/09/08 - 9:13am in response to: Dominique De Vito

Dominique, what you describe is Groovy/Gant. 

I personally prefer Ruby/Rake as I described above, but Gant is a very nice way to go too.  I don't think there is any reason to re-invent the wheel here.

 There are other more complex projects out there like Graven and Buildr as well, but I personally found them to be overkill.

 "- no more cumbersome XML (in fact the creator of ANT says he is not now happy to have introduced XML into ANT)"

Yep, James Duncan Davidson, creator of ANT and Tomcat is now a huge ruby advocate.

 

And you pure java guys are nuts IMO.  I guess it's better than XML, but Java really sucks at this stuff.  No closures, lousy file API, very verbose for a build file.

Thomas Mueller replied on Mon, 2008/09/08 - 2:50pm in response to: Dominique De Vito

Dominique, what you describe is PJMake, a Pure Java Make tool. I wanted to call it JAnt but that name is already used :-)

Jose Maria Arranz replied on Thu, 2014/01/23 - 3:42am

Six years later your idea is real:

https://github.com/jmarranz/relproxy

Take a look to code, don't ignore the hashbang (#!/usr/bin/env jproxysh):

#!/usr/bin/env jproxysh

String msg = args.length > 0 ? args[0] : "";
System.out.println(msg);

System.out.println("example_java_shell 1 ");

example.javashellex.JProxyShellExample.exec();

or this one:

#!/usr/bin/env jproxysh

import example.javashellex.JProxyShellExample;

public class example_java_shell_2
{
    public static void main(String[] args)
    {
        String msg = args.length > 0 ? args[0] : "";
        System.out.println(msg);

        System.out.println("example_java_shell_2 1 ");

        JProxyShellExample.exec();
    }
}

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.