ExpandCollapseNext Index

+ 1.1 Objects

Felix provides a highly dynamic but statically typed object protocol. You can make an object like this:

  var aperson = object (name:string, var age: int) = {
    method fun get_name () => name; 
    method fun get_age () => age; 
    method proc set_age (x:int) { age = x; }
  };
  
  var john = aperson ("john", 42);
  
  println$ john.get_name () + ","+ john.get_age ()+".";
  john.set_age (43);
  println$ john.get_name () + ","+ john.get_age ()+".";

Clearly, john is an object, so what is person? The answer is that person is an object factory which can be called upon to make objects such as john. This plays a similar role to a class in Python or a constructor in C++, however in Felix, object constructors are alive.

An object factory is in fact nothing more than an ordinary function with some specialised syntax, which returns a record of closures of the functions and procedures marked as methods.

You will of course note that, as will all functions, the local variables, including parameters, are not accessible outside the function: thus Felix leverages functional (lambda) abstraction to hide the private representation of an object.

+ 1.1.1 Named Objects

In the above code we deliberately used an inline or literal object notation to emphasise that objects are first class and can be used anywhere: a lambda notation tha produces an anonymous object constructor as a closure.

As for functions, more conventional syntax is also available:

  object person (name:string, var age:int) = {
    method fun get_name () => name; 
    method fun get_age () => age; 
    method proc set_age (x:int) { age = x; }
  }

This is not equivalent because now person is a named object constructor function, not a variable. In particular, like all functions, named object constructor function can be overloaded.

It is good to avoid confusion, and remember that whilst person is a constructor, it is the same as in Java or C++ that

     person ("fred", 22)

is an object.

+ 1.2 Extending Objects

It is easy to make an extended object. Lets suppose we want to give john an occupation then we first do this:

  var occupation  = object (title:string) = {
    method fun get_job()=>title; 
  };

Now we can make an occupation:

  var programmer = occupation ("programmer");

Now, we can make a new composite object:

  var working_john = extend john with programmer end;
  println$ working_john.get_name () + " job is " + working_john.get_job();

+ 1.2.1 Object Aspects

When we extend an object we create a new aspect of the object consisting of the union of the sets of methods. This is a new method record, however the representation is not copied. To see this consider this example: first, we give job a second job.

  var moonlighting_john = extend john with occupation "barista" end;
  println$ moonlighting_john.get_name () + " job is " + moonlighting_john.get_job();

Now observe:

  moonlighting_john.set_age (44);
  println$ john.get_name () + ","+ john.get_age ()+".";

will tell that john is 44: john, working_john and moonlighting_john all have the same age.

In many languages you derive new classes from old ones by inheritance. In Felix you can derive new objects from old ones on a per-object basis. You merge attributes dynamically of any objects to form a new object. Each derived object can be thought of as a view or aspect of a complex entity.

Both object factories and the objects they create are first class values.