The Basics

Encore uses active classes which are classes with asynchronous method call semantics in order to achieve parallelism-by-default. This section gives a concise overview of encore’s classes. The Section “Encore Syntax” and others will describe the language in much greater detail.

Hello, World!

The obligatory hello-world program, hello.enc, looks like this:

active class Main
  def main() : unit
    println("Hello, World!")
  end
end

To compile and run the program just run encorec --run hello.enc.

$ encorec --run hello.enc
Hello, World!

It is important to know that every legal encore program needs to have an active class called Main, with a method called main. The runtime will allocate one object of class Main and begin execution in its main method.

Compiler Options

Running encorec foo.enc will typecheck the source and produce the executable foo. The following options are supported:

--import [dirs]        | -I [dirs]  colon separated list of directories in which to look for modules.
--out-file [file]      | -o [file]  Specify output file.
--custom-flags [flags] | -F [flags] Supply custom flags for the C compiler. (Use quotation marks to supply more than one flag)
--generate-c           | -c         Outputs intermediate C fields in separate source tree.
--debug                | -g         Inserts debugging symbols in executable. Use with -c for improved debugging experience.
--type-check           | -tc        Only type check program, do not produce an executable.
--pretty-print         | -pp        Pretty print the AST immediately after parsing.
--literate             |            Literate programming mode. Code blocks are delimited by '#+begin_src' and '#+end_src'.
--verbose              | -v         Print debug information during compiler stages.
--optimize N           | -O N       Optimise produced executable. N=0,1,2 or 3.
--profile              | -pg        Embed profiling information in the executable.
--run                  |            Compile and run the program, but do not produce executable file.
--no-gc                |            DEBUG: disable GC and use C-malloc for allocation.
--help                 |            Display this information.

For instance, keep the intermediate C-files, invoke the following: encorec -c foo.enc.

Active/Passive Classes

Encore supports active and passive classes. Allocating an object from those classes gives active or passive objects, respectively. To make a class active, the active keyword is necessary. To make a class passive, use modifier class P, where modifier is linear, local, read, or subord. Calling a method on an active object will have that method execute concurrently (also in parallel, if enough cores are available). The return type of an active method is a future (see section “Futures”) and not the return type in the method declaration. In contrast to active classes, methods of passive classes execute synchronously, in the calling thread. Passive objects are similar to what you’d expect in a Java-like language (but without any synchronisation overhead).

Note that all fields in an active class are private but all fields are public in a passive class. A class may have a method called init which is used as the constructor. It is called when appending arguments to object construction (new Foo(42)) and cannot be called on its own.

Example: Active Class

The follow example considers an active class Foo. A Foo instance has an ID string, and calling the printID method will print that string 5 times to stdout. The main method creates two Foo instances, and has them print their IDs:

active class Main
  def main() : unit
    val obj1 = new Foo
    val obj2 = new Foo
    obj1.setID("obj1")
    obj2.setID("obj2")
    obj1.printID()
    obj2.printID()
  end
end

local class Foo
  var id : String

  def setID(new_id : String) : unit
    this.id = new_id
  end

  def printID() : unit
    var i = 0
    while i < 5 do
      i = i + 1
      println(this.id)
    end
  end
end

Executing this program gives nondeterministic output:

$ encorec -run ex_active.enc
obj1
obj1
obj1
obj1
obj1
obj2
obj2
obj2
obj2
obj2

The behavior of this program can be made deterministic using get applied to each call to printID. This call waits for the method invocation to finish before proceeding. See the section “Futures” for more information.

Example: Passive Class

Passive classes are used the way regular classes in Java are used, namely, to build data structures. Unlike Java, they are unsynchronised, which means that an Encore programmer needs to work harder to ensure passive classes are used safely. The mechanism for achieving safety on passive classes is the Kappa capability system, which consists of a small number of annotations to describe how objects of passive classes are shared. The following class, duplicated from the previous example, includes the annotation local to state that instances of this class cannot be passed between actors.

local class Foo
  var id : String

  def setID(new_id : String) : unit
    this.id = new_id
  end

  def printID() : unit
    var i = 0
    while i < 5 do
      i = i + 1
      println(this.id)
    end
  end
end

Other capabilities include read for read-only objects, linear for objects that have only a single reference to them, and subord for objects that are cannot be referred to outside of another passive object.

results matching ""

    No results matching ""