Stateful functions

A stateful function is a piece of ‘native’ code which is sequentially executed by ohua and has for its execution context some associated, opaque state.

Concretely this means that a stateful function, in Java for instance, is a method and an associated class.

An example:

public class IntegerAccumulator {
    private int counter = 0;

    @defsfn
    public int increment(int valueToAdd) {
        counter += valueToAdd;

        return counter;
    }
}

For each invokation site of the stateful function ohua creates a new instance of the associated class. And each time that particular piece of code is run the same instance of the associated class is handed to the method.

Defining stateful functions is currently supported for three languages: Java, Clojure and Scala. In theory however any language can define a stateful function, so long as it creates JVM bytecode for a class and a method.

Stateful functions in Java

Defining stateful functions in Java is very simple. Every stateful function needs an associated class.

The class must satisfy the following conditions

  1. The class must be public.
    This enables the runtime to find it.
  2. The class has a default constructor and is not abstract.
    Since the runtime cannot know what the constructor arguments should be it will attempt to instantiate it with none.
  3. Only one stateful funciton is defined on the class.
    The class may define as many methods and members as it wants, however it may only define one stateful function. This restriction may be lifted in the future. However for the present if you wish to define multiple stateful functions in one file we suggest using static inner classes.
  4. If the class is an inner class it must be static.
    Otherwise the runtime will be unable to instantiate the class.

To define the stateful function on the class itself simply annotate the desired method with @defsfn.

public class AssociatedClass {

    @defsfn
    public String concat(String a, String b) {
        return a + b;
    }
}

The method must satisfy the following conditions

  1. The method must be public.
    Otherwise the runtime will not be able to call it.
  2. The method must not be static.
    Using a static method will lead to an arity exception. If you must have a static version of your code define the static method and then define a second, non static method which calls the static one and annotate this one with defsfn.

Stateful functions defined in Java may be brought into scope for use in an algo using Bringing stateful functions into scope.

Stateful functions in Clojure

Stateful functions defined in Clojure may be brought into scope for use in an algo using standard Clojure require.

Stateless Clojure functions

You can use any normal clojure function in ohua. User defined functions as well as library functions can be directly called in the ohua EDSL.

Warning

As of yet there is no support for lambdas

As an example, this does not work:

(ohua
  (let [x (accept socket)
        lam (fn [y] ( ... x))]
    ..)

Stateful Clojure functions

Stateful functions in Clojure are simply Clojure functions, which have been annotated with the metadata :init-state. This :init-state metadata contains a Clojure expression which initializes the state for the stateful function. This can be any Clojure expression and it may produce any Clojure data structure. The exact reference returned by :init-state will be passed to every invokation of the stateful function. Since this state reference will be passed to the function when invoked every Clojure stateful function must have as its first argument the reference for the state, usually called this. Therefore if you require mutable state, we recommend using clojure atoms, mutable Java data structures or mutable clojure data structures.

There is a convenience macro called defsfn which works like defn but additionally takes as a second argument the :init-state expression.

; defined with defsfn
(defsfn aggregate (new java.util.ArrayList) [this arg1]
  (if (> (.size this) 6)
    (let [copy (new java.util.ArrayList this)]
      ; mutable actions are allowed
      (.clear this)
      copy)
    (.add this arg1)))

; defined with defn
(defn ^{:inti-state '(atom #{})} was-seen [this thing]
  (if (contains? @this thing)
    true
    (do
      (swap this conj thing)
      false)))

Stateful functions in Scala

Defnining stateful functions in Scala is basically identical to defining stateful functions in Java. See the requirements for the method and associated class in How to define stateful functions in Java. Annotate the method with @defsfn.

class Concat {
    @defsfn
    def concat(a:String, b:String) -> String = {
        a + b
    }
}

Stateful functions defined in Java may be brought into scope for use in an algo using Bringing stateful functions into scope.