Prexonite Script

a .NET hosted scripting language with a focus on meta-programming and embedded DSLs

View the Project on GitHub SealedSun/prx

Finally trying hard to catch exceptions

Posted on 2007-04-17

Prexonite now comes with exception handling in the form of try-catch-finally blocks. Their implementation is a bit different from the ones in C#.

Add System::IO to Imports;

function main
{
    try
    {
        var sw = new StreamWriter("foo.txt");
        sw.WriteLine("It worked!");
    }
    catch(var exc)
    {
        println(exc);
    }
    finally
    {
        dispose(sw);
    }
}

An no, you cannot omit the braces this time. It looks just like C# exception handling except that you have to differentiate between different types of exceptions for yourself. The syntax for throwing exceptions is equally intuitive (from a C# programmers standpoint at least). Just throw whatever you want. If it's not an exception, it's ToString-ed form will be used as the message.


declare function sum;
function average(xs)
{
  if(xs is null or xs.Count == 0)
    throw "average requires a list with at least one element.";
  return sum(xs) / xs.Count;
}

As I said in the beginning, my implementation differs from the C# one. For technical reasons, the finally block is executed before any catch blocks. At least currently. This might change with future versions.

Always remember that C#'s implementation of exception handling is much more robust than the one in Prexonite because the CLR has more sophisticated means of protecting and ensuring the execution of the finally block than Prexonite has. If one evil command or object member throws away the complete stack, the VM has no chance to get it's hands on the required finally code.

The current implementation does not prevent you from jumping out of the try block and therefor skipping the finally block. It is up to you. In addition to the try-catch-finally and the throw constructs, the foreach statement has been modified to ensure the disposal of the IEnumerator.

Also I implemented the using pattern from C#. This one, on the other hand, works like expected. For performance reasons, the dispose command has been added to the standard collection. It calls IDisposable.Dispose on all arguments that explicitly support the interface. You don't even have to check for null.

Add System::IO to Imports;

function main
{
    using(var sw = new StreamWriter("foo.txt")
        sw.WriteLine("It worked!");
}