Documentation for gololang.Control

This module contains utilities to control execution flow.

Contexts

Contexts are very similar to Python's with statement and can be seen as a more generic version of Java's try with resource

A context is any object exposing two special methods. The first one, __$$_enter, is a parameterless method that must be called when entering the context. The second one, __$$_exit, is a method that must be called when exiting the context. A context can be created using the provided Context structure, a DynamicObject, or by augmenting existing Java objects (e.g. CloseableContext)

A context is meant to be used with the within macro, that wraps the execution of its block with these enter and exit methods. This allows to abstract try...catch...finally patterns. Indeed, the given block is wrapped inside a try...catch...finally to ensure that the __$$_exit method of the context is called. The result of the __$$_enter method of the context can be bound to the given name to be used inside the block.

For instance, given:

&within(name = expression) {
  block
}
  1. The expression is evaluated. It is expected to return a context.

  2. The context __$$_enter method is invoked without arguments. Its result (the target) is bound to name if present, and is ignored otherwise.

  3. The block is executed (in a try clause).

  4. Depending on the exception thrown by block:

    • If block raised an exception, the __$$_exit method is called with the target and this exception. If the method returns an exception, it is thrown. Must the exception raised by the block be rethrown, the __$$_exit must return it. If the __$$_exit returns null, no exception will be raised. Any exception raised by the __$$_exit method is suppressed.
    • If the block does not raise an exception, the __$$_exit method is called with the target and null and its returned value is ignored. Any exception raised by the __$$_exit method is rethrown.

Since the result of the __$$_enter method is given to the __$$_exit method, the context is not required to keep it as an attribute, should __$$_exit act on it. The context can therefore be stateless. It may however keep the target as an internal attribute, or a closed variable when using Context for instance.

Since the __$$_exit method is given the exception raised by the block and can prevent its rethrow, the exception can be dealt with directly inside this method. Moreover, since the exception returned by __$$_exit is raised, the exception can be wrapped in a higher level exception.

For instance, one can create a transactional context as:

function transaction = |params...| -> context(
  -> createConnection(params),
  |connection, err| {
    case {
      when err is null {
        connection: commit()
      }
      when err oftype MyException.class {
        connection: rollback()
        dealWithIt(err)
      }
      otherwise {
        connection: rollback()
        return WrapperException("Transaction failed", err)
      }
    }
  }
)


...
&within(connection = transaction(connectionParams)) {
  doSomethingWith(connection)
}

More than one context can be used, which is the same as nesting contexts, as:

&within(x = context, generateContext()) {
  work(x)
}

is expanded into

&within(x = context) {
  &within(generateContext()) {
    work(x)
  }
}

Structs

Context

This structure encapsulate two functions that will be used as context and enter and exit functions.

See also the applied augmentation to provide the corresponding context methods.

This structure must not be instanciated directly, use context instead.

Members

Named Augmentations

CloseableContext

Augmentation to create a context from objects with a close method.

Classes with a close() method can be augmented with this augmentation to behave as a context. The enter value is the object itself, and the exit method call its close method and returns the exception unchanged. This allows a behavior similar to the Java try with resource.

See also closing to use a wrapping function instead.

AutoCloseable are augmented using this augmentation.

__$$_enter(this)

__$$_exit(this, target, error)

LockContext

Augmentation to create a context from objects with lock() and unlock() methods.

Classes with lock() and unlock() methods can be augmented with this augmentation to behave as a context. The enter value is the object itself, after it was locked, and the exit method unlocks it and returns the exception unchanged.

See also locking

__$$_enter(this)

__$$_exit(this, target, error)

Augmentations

gololang.Control.types.Context

Makes the Context structure a context by providing __$$_enter and __$$_exit methods that delegate on the corresponding closures.

In both cases, if the field value is not a closure, it is used as the method's return value.

__$$_enter(this)

Delegates on the enter field.

__$$_exit(this, target, error)

Delegates on the exit field.

java.lang.AutoCloseable

Java AutoCloseable objects are augmented to be a closing context.

For instance, to read the lines of a file, one can use:

&within(f=openFile("somefile.txt")) {
  foreach line in f {
    println(line)
  }
}

See also closing.

Named augmentations applied

java.util.concurrent.locks.Lock

Java Locks objects are augmented to be a locking context.

For instance:

let lock = ReentrantLock()

&within(lock) {
  doSomeWork()
}

See also locking

Named augmentations applied

Macros

within(args...)

Execute a block within a context.

This macro must be called with at least a context and a block to execute. The contexts may be given a name that will be bound to the result of __$$_enter. Several context may be given, which is equivalent to nested contexts.

For instance:

&within(x = context1, generateContext(), y = otheContext()) {
  work(x, y)
}

is expanded into

&within(x = context) {
  &within(generateContext()) {
    &within(y = otherContext()) {
      work(x, y)
    }
  }
}

The __$$_exit method of each context will be called accordingly, even if the block fails with an exception.

Functions

closing(resource)

Creates a context for resources that must be closed.

For instance:

&within(resource=closing(createCloseable())) {
  doSomethingWith(resource)
}

See also CloseableContext to augment existing classes instead.

context(enter, exit)

exceptionFilter(mapper)

Generic context to deal with exceptions.

The created context returns null on entry. The exit function ignores the target, and apply the given mapper function to the exception.

For instance, to just log a message and ignore the exception, one can use:

let errorLog = exceptionFilter(|e| { Messages.error(e: localizedMessage()) })

&within(errorLog) {
  somethingThatMayRaise()
}

locking()

Convenient function to create a locking context from a java.util.concurrent.locks.ReentrantLock.

locking(lock)

Creates a context for locking objects.

For instance:

&within(locking(createLock()) {
  doSomething()
}

See also LockContext to augment existing classes instead.

nullContext()

Creates a null context returning null.

This is a singleton.

See also nullContext

nullContext(val)

Creates a null context.

This null context does nothing on exit, and return the given value on entry. It can be used as a fallback value when the context to use is changed dynamically.

It's a Null Object Pattern instance.

This function should be banged.

stderr(err)

Creates a context redirecting standard error.

stdout(out)

Creates a context redirecting standard output.

suppress(exceptions...)

Creates a context that ignores exceptions.

unlocking(lock)

Creates a context for unlocking objects.

This context can be used to temporally release a previously acquired lock.

For instance:

let l = createLock()
&within(l) {
  doSometing()
  &within(unlocking(l)) {
    doTaskWithLockReleased()
  }
  workWithLockHeld()
}

wrapped(cls)

Creates a context that wraps exceptions

If an exception is raised inside the context, it will be wrapped in the given exception (as its cause).

For instance, given:

&within(wrapped(MyException.class)) {
  doSomething()
}

If doSomething throws an exception e, a MyException instance will be raised instead, whose cause will be set to e.