Notes on INF5510 Exercise Set 1
v18.1 (2018-02-01)
Oleks Shturmov

The following notes present my reflections on INF5510 Exercise Set 1, following the exercise session on January 25, 2018. These notes would not constitute a complete reference solution.

1. Hello, World!

If your shell can't find the commands ec or emx:

$ ec
ec: command not found
$ emx
emx: command not found

Then you either haven't set your EMERALDROOT environment variable, or forgot to extend your PATH environment variable.

To do so, it should suffice to add the following to the file ~/.profile (create it if it does not exist):

export EMERALDROOT="/some/absolute/path"
export PATH="$EMERALDROOT/bin:$PATH"

To apply these settings in your current shell instance, issue the following command:

$ source ~/.profile

The ~/.profile file is sourced system-wide on login, so to make the above settings “global”, all you have to do now is log out, and log in again, or simply restart your computer.

2. Types

Emerald distinguishes between the keywords operation and function, hinting that an operation may, while a function may not alter the state of the object. Unfortunately, Emerald does not actually stop functions from altering the state of an object.

Emerald method signatures specify not only the return type, but also the name of the variable to be returned. For instance, add here returns the value of the boolean variable res on exit:

operation add [ name : String ] -> [ res : Boolean ]

This means that Emerald methods need no explicit “return” statements. They should just make sure to set the return variables to sensible values. Unfortunately, Emerald will not issue a warning if you clearly do not set the return values to anything sensible.

Hence, the add method can be implemented simply as follows:

const set : SimpleCollection <- object set
  export operation add [ name : String ] -> [ res : Boolean ]
    % What is the default value of res?
  end add

The export keyword makes the add operation visible outside the object.

contains and remove can be implemented similarly.

It is allowed for set to define more methods than specified. These methods can be called on set, even though its declared type is SimpleCollection. The stated “type” of a variable is therefore a mere statement that the variable conforms to that type:

const set : SimpleCollection <- object set
  % Other methods here ...
  export function size -> [ res : Integer ]
    res <- 0
  end size
end set

const main <- object main
  initially
    stdout.putstring[set.contains["x"].asString || "\n"]
    stdout.putstring[set.size.asString || "\n"]
  end initially
end main
$ ec types.m
Compiling types.m
$ emx types.x
true
0

Note also that the compiler (ec) will stop you if you try to call a method that never-the-less is not defined for set:

const main <- object main
  initially
    stdout.putstring[set.contains["x"].asString || "\n"]
    stdout.putstring[set.cap.asString || "\n"]
  end initially
end main
$ ec types.m
Compiling types.m
"types.m", line 25: Operation cap[0] is not defined

Emerald is statically typed.

3. Classes

The class construct implicitly declares a type object, and a create method, returning an object of that type.

Hence, the implementation goes something like this:

const Person <- object PersonCreator
  const PersonType <- typeobject PersonType
      function getname -> [ res : String ]
  end PersonType
  export function create [ name : String ] -> [ res : PersonType ]
    % Actually set res to something sensible.
  end create
end PersonCreator

4. Inheritance

We proceed as above for the Person class.

As for the Teacher class, the object defining it must declare its own methods, in addition to the ones in the Person class. Although this object may maintain an instance of the Person class, it is more efficient to embed the implementation of the Person class inside the Teacher class to avoid indirection at run-time:

const Teacher <- immutable object Teacher
  const TeacherType <- typeobject TeacherType
    operation getname -> [ res : String ]
    operation getposition -> [ res : String ]
  end TeacherType
  export operation create [ name : String, position: String ] -> [ res : TeacherType ]
    % Actually set res to something sensible.
  end create
end Teacher

5. Covariance/Contravariance

The way to validate conformity using Emerald is to decorate the oleks and eric constants with some expected types.

5.1. Student does not conform to Teacher

We discover this by trying to type oleks as Teacher:

const oleks : Teacher <- Student.create["Oleks"]

When trying to compile this, we get an error:

$ ec variance.m
Compiling variance.m
    Immutable mismatch
    Type anytype doesn't conform to type stringtype
  param 1 to operation ask doesn't conform
  Type astudenttype doesn't conform to type ateachertype
"variance.m", line 22: The initializer type doesn't conform to that declared for the constant

5.2. Teacher does conform to Student

We discover this by trying to type eric as Student:

const eric : Student <- Teacher.create["Eric"]

Which yields no compiler errors.

6. Generating Primes

Not solved during the exercise session.

7. Data Structures

Not solved during the exercise session.

8. Keywords

After completing these exercises, you should be familiar with the following keywords. If not, read up on them in the language report.

  • Object
  • Operation
  • Function
  • Object Constructor
  • Conformity
  • Class
  • Inheritance

9. Tips

You can use the $ as syntactic sugar for .get.

For instance, you can write eric$name in place of eric.getname above.