Friday, July 15, 2011

Euphoria dot-notation

I was reading this OpenEuphoria forum thread and I wondered,
what if we could use the Euphoria type mechanism to create aggregates with  dot-notation - using functions and procedures for getters and setters:


type foo (object o)
  return atom(o)
end type

function foo.id (atom this)
  return peek4u(this)
end function

procedure foo.id (atom this, atom value)
  poke4(this, value)
end procedure

foo ptr = allocate(4)
ptr.id = 3  -- implicitly calls foo.id(ptr, 3)
? ptr.id -- prints 3 -- implicitly calls foo.id(ptr)


This seems to be simple yet flexible and fits the spirit of Euphoria. It's also dang ugly and not as concise as C struct declarations. The same name for the procedure and functions could be confusing, but the interpreter will know to call the function or procedure based on context. Also, the type of the object is static - it doesn't get passed to functions or inside sequences.


What about nested aggregates? And pointers?

-- point { int x, int y }

type point (object this)  return atom(this)  end type
function point.x (atom this)  return peek4s(this)  end function
procedure point.x (atom this, atom x)  poke4(this, x)  end procedure
function point.y (atom this)  return peek4s(this+4)  end function
procedure point.y (atom this, atom y)  poke4(this+4, y)  end procedure
procedure point.init (atom this, sequence xy)  poke4(this, xy)  end procedure

-- line { point p1, point p2 }

type line (object this)  return atom(this)  end type
function line.p1 (atom this)  return this  end function
procedure line.p1 (atom this, point p)
  if p != this then
    memcpy(this, p, 8)
  end if
end function
function line.p2 (atom this)  return this+8  end function
procedure line.p2  (atom this, point p)
  if p != this+8 then
    memcpy(this+8, p, 8)
  end if
end procedure
procedure line.init (line this, sequence a, sequence b)
  this.p1.init(a)
  this.p2.init(b)
end procedure

line l1 = allocate(16)
l1.init({10, 15}, {20,25})
? {{l1.p1.x, l1.p1.y}, {l1.p2.x, l1.p2.y}} -- prints {{10, 15}, {20, 25}}

The only knowledge we have the type of line.p1 is the second argument in the setter procedure.  I hope that's enough.

I've also introduced method procedures in the above example, and I think it would be fine for functions too.

What about pointers?

-- line2 { pointer-to-point p1, pointer-to-point p2 }

type line2 (object o)  return 1  end type
function line2.p1 (atom this)  return peek4u(this)  end function
procedure line2.p1 (atom this, point p)  poke4(this, p)  end procedure
function line2.p2 (atom this)  return peek4u(this+4)  end function
procedure line2.p2 (atom this, point p)  poke4(this+4, p)  end procedure

line2 l2 = allocate(8)

l2.p1 = l1.p2  -- l2.p1 points to l1.p2
l2.p2 = l1.p1  -- l2.p2 points to l1.p1
? {{l2.p1.x, l2.p1.y}, {l2.p2.x, l2.p2.y}} -- prints {{20, 25}, {10, 15}}

Keeping track of the size of the aggregate gets to be a pain. A sizeof function might be nice.

Would this work for sequences too?

type bar (object o)
  return sequence(o)
end type

function bar.first (sequence this)
  return this[1]
end function

-- this must have special calling conventions where this is passed by reference
procedure bar.first (sequence this, object o)
  this[1] = o
end procedure

function bar.last (sequence this)
  return this[length(this)]
end function

-- this must have special calling conventions where this is passed by reference
procedure bar.last (sequence this, object o)
  this[length(this)] = o
end procedure

bar seq = {1, 2, 3}
seq.first = 5
? seq -- prints {5, 2, 3}
seq.last = 10
? seq -- prints {5, 2, 10}

This requires special casing the first argument of the setter procedures to be passed by reference.




Instead of an init procedure, what if we could use C99-like dot-notation in initialization:

foo ptr = { .id = 3 }

Wait, that doesn't make sense: the ptr hasn't been allocated before initialization.  What if we were to add constructors and destructors?

function foo._init ()
  return allocate(4)
end function

procedure foo._fini (object this)
  free(this)
end procedure

foo ptr = { .id = 3 }

The ._init function only gets called when ptr is created without an initializer.  The ._fini procedure gets called automatically when ptr refcount goes to zero (when it gets assigned a new value). Hopefully the existing refcount free mechanism can be modified to call the _fini function.

Wednesday, June 15, 2011

User content

Suppose there was a web site that allowed users to create games by simply drawing levels as you would draw using a paint program. Suppose this site allowed you to share created levels and search for levels created by others. I suspect the site would quickly become the penis-game site in no time. When I showed a prototype of such a site to my wife, I kid you not, the first thing she did was draw a penis made up of 1-up mushrooms.

Moderation or a rating system to prevent inappropriate images would be advisable.