Monday, May 28, 2018

Shebang Coming to Java?

Although it was never a central goal of JEP 330 ["Launch Single-File Source-Code Programs"] to add support for the Unix-style shebang (#!), issues surrounding the potential ability of JEP 330 "single file source programs" to support a Unix-style shebang have generated significant discussion on the OpenJDK jdk-dev mailing list. This "vigorous discussion" has led to Mark Reinhold adding a week to the review period (now ends on May 31) for JEP 330 to allow for further discussion regarding targeting JEP 330 for JDK 11.

Although there are still some disagreements about whether shebang support should be added at all, it does seem that consensus is shifting to a proposal to explicitly differentiate between regular platform-independent Java source code files (those that end with extension .java) and the new JEP 330 "executable" platform-specific "single-file source-code programs". The explicit distinction is noteworthy because it would allow for shebang to be expressed in the latter (JEP 330 executable platform-specific single-file source-code programs) and not be used in the former (traditional Java platform-independent source code we're all accustomed to).

A Jonathan Giles message in this discussion spells out "various reasons to not want to change JLS or javac", points out that "shebang scripts are an executable format defined on some, but not all, platforms," points out that "creating a shebang script is typically more than just adding an initial first line to a file," and articulates the concept of differentiating explicitly between traditional Java source code and JEP 330 executable Java scripts:

While renaming the file to a command-friendly name is optional, it is also expected to be common practice. For example, a source file named `HelloWorld.java` might be installed as `helloworld`. And, while the JEP describes use cases for executing a small single-file program with `java HelloWorld.java` or executing it as a platform-specific shebang script with just `helloworld`, it does not seem like there is a common use case to execute `HelloWorld.java`. So, if the shebang script is typically renamed to a command-friendly name, it will not be possible to compile it directly, with "javac helloworld", because that is not a valid command line for javac. This reduces any potential convenience of having javac ignore shebang lines.

Since Java source files are different artifacts to platform-specific executable scripts, it makes sense to treat them differently, and since we do not want to change the Java language to support shebang lines, the suggestion is to amend the JEP and implementation so that shebang lines are never stripped from Java source files, i.e. files ending in `.java`. This avoids the problem of having the ecosystem of tools handling Java source files having to deal with arbitrary artifacts like shebang lines. The change would still permit the direct execution of Java source files, such as `java HelloWorld.java`, and the execution of shebang scripts, such as `helloworld`.

The following table summarizes characteristics and advantages associated with each style of "Java" file.

Item Traditional Java Source Files JEP 330 Executable Single-File Source-Code Programs
Descriptions
/Names
"Java source files (which end with a .java extension)" "executable scripts (which do not use [.java] extension.)"
"Java source files" "shebang scripts"
"Java source file" "script that contains Java code" or "platform-specific executable script"
"Java source files, as identified by a filename ending in '.java'"  
Shebang Not Supported Supported
Platform Independent Dependent
Explicit Compilation Yes No

Jonathan Gibbons summarizes the intent of JEP 330: "The general theme here is not to evolve Java into a scripting language, but to make tools like the Java launcher more friendly to supporting the use of Java source code in an executable text file, in order to reduce the ceremony of running simple programs."

The discussion has also covered alternative approaches such as binfmt_misc (see here also), Unix-style "here documents" (here documents defined), "support for '-' STDIN source in java launcher", and Linux being changed to support "la-la-bang: //!.

Another interesting side note from this discussion is Brian Goetz's "retrace" of how JEP 330 got to its current state. He talks about the "countless hours listening to people's concerns about Java" that led to this realization, "A general theme that people have expressed concern over is 'activation energy'; that doing simple things in Java requires too much fixed work." Goetz points out that JShell and JEP 330 are two of many possible ways of addressing this and that these two approaches were selected from among the many after making "subjective choices about which had the best impact" with consideration of "cost (in multiple dimensions) and benefit (or our subjective estimates of the benefits) when making these choices."

So, "regular Java" source code files will not be getting shebang support, but that is not a big deal as they don't really need them. It is looking likely, however, that JEP 330-based platform-dependent executable single-file scripts written in Java will support an optional shebang on the first line. We may know by Thursday of this week whether JEP 330 will be targeted for JDK 11.

1 comment:

@DustinMarx said...

The post "New Java 11 Feature: Launch Single-File Source-Code Programs" provides a nice, detailed overview for this JDK 11 feature.