JShell API, design problems?

JShell API, design problems?

This weekend I continued working my project making a Java REPL adventure game that teaches the basics of programming (in Java). One main goal of starting this project was to get a better understanding of the JShell API, not just the tool. I’ve used the JDK 9 JShell command line tool before, and it worked great. But there is also a big API behind it you can programatically use.

Let me show you how this works:

        JShell shell = JShell.create();
        List<SnippetEvent> events = shell.eval("int i = 10;");

What have we done here? Well first we’ve created an instance of the JShell. This is just like starting the command line tool. Now we can call the eval() function to evaluate Java code. As a result you receive so called SnippetEvents, these are classes containing the information about what happened. Let’s see what the code above returns:

        for(SnippetEvent event : events) {
            System.out.println(event);
        }

        //Output: SnippetEvent(snippet=Snippet:VariableKey(i)#1-int i = 10;,previousStatus=NONEXISTENT,status=VALID,isSignatureChange=true,causeSnippetnullvalue=10)

There is quite some information in there, the event contains the actual ‘snippet’, the piece of code that was executed. Also there is a previous state, status and some other information. This is where the JShell API starts to feel weird to me. To get the Snippet from the SnippetEvent we can call the following method:

        SnippetEvent event = events.get(0);

        // To get the information, we call snippet (not getSnippet()):
        Snippet snippet = event.snippet();

        // Next we cast our snippet to the correct subclass:
        VarSnippet vSnippet = (VarSnippet) snippet;

        // Now we can retrieve information, for example the type we've created:
        System.out.println(vSnippet.typeName());

        //Output: int

        // We can also get the 'value' of the SnippetEvent:
        System.out.println(event.value());

        //Output: 10

There are a couple of points I don’t like about the current JShell API design here:

  • Why are the methods to get information called .snippet() and .typeName(), why not getSnippet() and getTypeName()?
  • Why is the result of vSnippet.typeName() a String?
  • Why is the result of event.value() a String? Didn’t we have an ‘int’?

First the question about the method names. In all of the JDK code they seem to be using the bean-specification, where you have getMethods() for getting and setMethod(…) for setting. I’m not sure why this isn’t the case for the JShell API? Is this a new way Oracle is designing their API’s? Do other new JDK API’s have the same syntax?

Next is the question regarding the usage of Strings. Why is the value() a String when we’ve clearly made something an int? Even worse, let’s create something that is not a primitive:

        List<SnippetEvent> events = shell.eval("jdk.jshell.JShell.create();");
        System.out.println(events.get(0).value());

        //Output: jdk.jshell.JShell@4cc0edeb

It is even worse, the only result we get from event.value() is a String and it is clearly just the .toString() of the actual backing object. For this API I would love to see it returning the actual object instead. I understand the JShell tool uses String’s and communicates the toString(), but shouldn’t the API be more general? Or am I missing something here?

Anyway, this is exactly why more people should try these API’s and share the feedback! Mail your feedback and suggestions to the mailing list.

What do you think? Please leave a comment below, or… even better, share your thoughts on the mailing list