May 10, 2018

One of the main objectives of the Sling language has always been to try and make life simpler and to reduce the need for typing, and to reduce the overall amount of source code needed to do something. And one of the most annoying repetitive things that I personally as a programmer have spent a lot of time and keystrokes on, is the try-catch statement. You know, it's the classic, you want to read a file (nothing complicated, no big deal)..


data = Files.readAllBytes(path);

And as all Java programmers already know, if you try that, a great disappointment will follow…

error: unreported exception IOException; must be caught or declared to be thrown

So from what was just a simple line of code, you'll now have to take a deep breath and start typing. You'll work your way towards this monster..

try {
    data = Files.readAllBytes(path);
}
catch(Exception e) {
    e.printStackTrace();
}

(And this monster is already greatly simplified by using "Exception" instead of "IOException" and then adding yet more lines of code in a different place in the file to import the IOException..)

So from what was a simple one-liner, the programming language here forced us to turn it into a 6-liner with three times the amount of typing. And of course this is not a one-time incident. Over the lifespan of a programmer, one will do this countless times, over and over each day. Obviously from time to time you get tired and "lazy" and don't want to type that printStackTrace because "that wouldn't happen anyway", and over time important errors go missing, and terrible things happen to our bank accounts and insurances (not kidding).

Of course that was not Sling. That was Java. But we do have the same construct, the classic try-catch statement, also in Sling:

try {
    doSomething()
}
catch(e as exception) {
}

(As of slingc r305, the language now has a new built-in data type "exception", which maps to "System.Exception" for C#, "java.lang.Throwable" on Java and a regular object on JavaScript.)

As we started to think of ways to improve this, one of the first things we did was to make that exception parameter declaration optional. So the previous snippet can be also expressed like this:

try {
    doSomething()
}
catch {
}

(If no parameter is given to catch, the "e as exception" is automatically assumed)

Although better, that's still not so very convenient, and the error still goes missing. And doing the "print stack trace" in a cross-language fashion is not at all a one-liner (on Java you'll do "e.printStackTrace()", on C# "Console.WriteLine(e.ToString())", on JavaScript maybe "console.log(e)"), so there's a lot of typing left there. Of course you can do a utility function for it, which would be helpful.. But for the common case of just catching the exception and spitting it out, we came up with something new:

The trycatch keyword

It works like this:

trycatch {
    doSomething()
}

And of course like always in Sling, a one-liner block can be shortened:

trycatch:
    doSomething()

And as a particular case of the trycatch keyword, a one-liner block can also be turned into a single statement:

trycatch doSomething()

These would all now translate to this kind of Java code:

try {
    doSomething();
}
catch(Exception e) {
    e.printStackTrace();
}

Or this kind of C# code:

try {
    doSomething();
}
catch(System.Exception e) {
    System.Console.WriteLine(e.ToString());
}

Or this kind of JavaScript code:

try {
    doSomething();
}
catch(e) {
    console.log(e);
}

That's a lot of typing removed.

But wait, there's more!

The trycatch keyword can also be used as an expression. The trycatch expression evaluates to true if the block executed without exceptions, or false if exceptions were encountered. So you can do stuff like this:

if not trycatch doSomething() {
    PRINT "Error took place"
    return false
}

But of course the assert statement is meant to make that one shorter:

assert trycatch doSomething():
    PRINT "Error took place"

This ends up being a really rich statement packed into a small space. It is equivalent to the following C# code:

if (!((System.Func<bool>)(() =>
{
    try
    {
        doSomething();
    }
    catch (System.Exception e)
    {
        System.Console.WriteLine (e.ToString());
        return (false);
    }
    return (true);
}))())
{
    System.Console.WriteLine ("Error took place");
    return (false);
}

Or the following in Java:

if(!(new Object() {
    public boolean execute() {
        try {
            doSomething();
        }
        catch(java.lang.Throwable e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}.execute())) {
    System.out.println("Error took place");
    return(false);
}

Or something very similar in JavaScript.

The trycatch keyword, along with the exception data type, is now available in slingc r305 and newer. Just use the Eqela command line interface to build and update your build.qx file with:

use eqela:sling:r305

Happy hacking.


Share this article: