You are currently browsing the archives for the prototype tag.

Prototypes, Objects, Functions, etc.

As I said previously, I really like prototype based languages. In those languages, an object if a hashtable with a link to a prent object (for empty slots).

An object can also be seen as a function explicitly defined which associates an object to an object. Moreover, this object has two more features: the value of a slot can be changed, and there is some kind of inheritence (the parent object).

Functions can be seen as extensions of objects.

Before going further, I'd like to clarify something: I will consider that there are no differences between objects and functions. Everything is an object, even functions. In order to do so, the definition of an object has to be extended: an object's slot are not constants, but patterns:

def o = {
    "foo" -> "bar"
  | "bar" -> "baz"
  | 42    -> "Doug'"
  | n     -> n+1
}

This object has two methods "foo" and "bar", a slot 42 whose value is "Doug" and a slot n which returns n+1 (with the convetion "plop"+1 = "plop1"). Moreover the method is called using the following syntax:

o "foo"; // = "bar"
o.foo; // = "bar"
o 42; // = "Doug'"
o 41; // = 42

Thus when we write foo bar baz, we apply the object foo bar to the argumente baz. It's some kind of curryfication. Here is another cool example:

def fibo = {
    0|1 -> 1
  | n   -> this n = this (n-1) + this (n-2)
};
fibo 10;
fibo 20;

Fibo is well know, but here there is an implicit and automatic memoization, which is really awesome.

I have a few other ideas, but I'll keep them for another day ;)

Prototype based PHP

Another proof of concept, using PHP this time :

<?php
class Proto {
  private $elems;
  private $proto;

  function __construct($proto = null) {
    $this->elems = array ();
    $this->proto = $proto;
  }

  function __set($name, $value) {
    $this->elems[$name] = $value;
  }

  function __get($name) {
    if ($this->elems[$name])
      return $this->elems[$name];
    else
      if ($this->proto)
        return $this->proto->$name;
      else
        return null;
  }

  function __call($name, $args) {
    if ($this->elems[$name] && is_callable($this->elems[$name]))
    {
      array_unshift($args, $this);
      return call_user_func_array($this->elems[$name], $args);
    }
    else
      return null;
  }

}
?>

The idead is completely different from the OCaml implementation. This time we use the magical methods to do whatever we want. Here is yesterday's example :

<?php
function write ($s) { echo $s; }
function method ($args,$body) { return create_function('$self,'.$args, $body); }

header('Content-Type:text/plain');

$p = new Proto;
$p->foo = 'p.foo';
$p->baz = 'p.baz';

$o = new Proto($p);
$o->foo = 'o.foo';
$o->bar = method('$f', '$f($self->baz);');

echo $p->foo, "\n";
echo $p->baz, "\n";
echo $o->foo, "\n";
$o->bar('write');
?>

There are several differences here too. First, echo is a statement, not a function, so it can't be passed to a function. This is why I use this workaround with the write function. Next, because of PHP's scoping, there is no direct access to the global variable $foo without calling global $foo;), I decided to $self as the first argument of all methodes and to bind it to the current element (this is actually how JavaScript works);

There are not much differences though…

Protoml + Camlp4

A little update to this morning's article, I wrote a little camlp4 extension which makes it easier to user the prototype module (and it doesn't overwrite the records).

let _ =
  let p = {} in
  p.foo <- "p.foo";
  p.baz <- "p.baz";

  let o = {}|p| in
  o.foo <- "o.foo";
  o.bar <- (fun f -> f (o.baz));

  print_endline (p.foo);
  print_endline (p.baz);
  print_endline (o.foo);
  ((o.bar) : 'a->'b) print_endline;

Downloaded : 88 times
File : protoml.tar.gz
Size: 957 o

Prototype based OCaml

Talking about prototypes, here is a little module which allows prototype based programming in OCaml. I'll warn you right now : it's horrible, but funny.

type obj =
    Empty
  | Obj of (string, string) Hashtbl.t * obj

let create ?(proto=Empty) () = Obj (Hashtbl.create 111, proto)

let set o k v =
  match o with
    Empty -> raise Not_found
  | Obj (o, p) -> Hashtbl.replace o k (Obj.magic v)

let rec get o k =
  match o with
    Empty -> raise Not_found
  | Obj (o, p) ->
      try
        Obj.magic (Hashtbl.find o k)
      with Not_found -> get p k

There is nothing difficult to understand (it was actually difficult to do). An object is just a hashtable and a parent object. Typing is bypassed using Obj.magic

Let's have a little fun:

open Proto

let _ =
  let p = create () in
  set p "foo" "p.foo";
  set p "baz" "p.baz";

  let o = create ~proto:p () in
  set o "foo" "o.foo";
  set o "bar" (fun f -> f (get o "baz"));

  print_endline (get p "foo");
  print_endline (get p "baz");
  print_endline (get o "foo");
  ((get o "bar") : 'a->'b) print_endline;

The result:

$ ./prototest
p.foo
p.baz
o.foo
p.baz

Note : This is only a proof of concept, never use this in OCaml, it is not at all compliant with OCaml philosophy. It's funny, however :D