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 source
d 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.