Re: [Vala] try/catch concepts



On 15 November 2011 00:33, Jim Peters <jim uazu net> wrote:
pancake wrote:
I've been thinking a bit on this post.. and I agree with it that
exception handling via try/catch hides the proper control flow of
the program and can result in problematic situations.

I happened to be thinking about this topic for other reasons, so I'm
going to paste a rather long thing I wrote.

The short version: There are two major types of errors that might
occur, and it's very difficult for a language to support both
usefully. Low level errors are adequately (if sometimes awkwardly)
handled by exceptions, high level errors are not. It might be possible
to craft a generic system for handling high level errors, but it will
always depend on the application framework for support, so in my view
a simple syntax is tweak is unlikely to help.

The long version:

A program is a serialisable set of instructions, to run it you need:

    * An executor to execute those instructions serially. (An executor
can spawn other executors, each of which follows this rule.)
    * A serialiser to linearise the program, i.e. choose a single
instruction the executor will run next.
    * A context to provide each instruction a handle to resources.

At low-level the executor is implicit (a hardware thread runs the
instructions with no logic in between); the serialiser is implicit
(structure of program + current thread stack); context is implicit
(physical memory).

At a higher level, all components can be explicit, e.g:

interface TaskContext() {
 + setData(...)
 + setError(...)
}

interface Task {
 + run(TaskContext)
}

interface Executor {
 + schedule(Task)
}

Each task can contain multiple low-level instructions, and so also
fits the definition of a program, and is normally run with the
low-level executor/serialiser/context. An Executor is software, and
can intelligently examine state between tasks. Serialisation is an
implementation detail of Executor - it might be a state machine, or
manage multiple state machines, etc.

Any number of Executors might exist, for example there may be one to
process each user action, or each client connection. At this level,
the hardware is completely abstracted, so can be, for example,
distributed across threads or across hosts.

Any unexpected errors must occur in the low-level part, since at the
high level they become application states, e.g. file-not-found is
low-level error, but file-not-available is acceptable state at high
level, for which there should be programmed response.

Any application that wishes to use high level logic therefore has two
different sorts of error handling requirement. Traditional exception
handling is only appropriate for the low-level part, since it is tied
to the (implicit) call stack, which is not a part of (or more likely,
only an implementation detail of) the high-level executor. At
high-level, task execution causes state change in the explicit task
context, and the executor can arrange for other logic to run based on
this. Rules are needed to respond to both success and error states -
any state for which there is no handler is a termination state of the
high-level program.

This gets complicated when you want to use the low-level constructs
(methods etc) for high level logic. Writing Task classes for
everything is painful, using delegates can simplify, but it still
exposes the low level details. Also it would be best to write using
explicit context objects, but it’s a lot easier to use memory
directly.

An application framework would ideally provide a way to define that
some code is an application level task, and therefore have implicit
access to a specific context, and different error handling options,
where exceptions could be automatically wrapped and turned into state.
This would be hard to design as a language feature, since it is built
on top of the software executor, which could have a much more
complicated interface than the language designers imagine.

A further possibility would be to use a variant language, such that an
application would basically include scripts that invoked its own
functionality. The scripts would be the high level part, using
different error handling syntax (and possibly be wrapped in
transactions etc. as the domain requires.)

The closest that a single language would be able to get to this is to
allow marking some methods/classes as application/script level, and
wrapping all instructions in these with a single predefined error
handling scheme, e.g. VB style ignore errors/abort. This is possibly
the worst option.

-- 
Phil Housley



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]