About two ours to get this:

///////////////////////////////////////////////////////////////
// An OO experiment

interface AA {
  setx: int -> void;
  sety: int -> void;
  getx:1 -> int;
  gety:1 -> int;
  sum: 1 -> int;
}


// omethod temporarily to avoid conflict with http_request
// which happens to use a field named "method"
object makeX (var x:int, var y:int) implements AA = {
  omethod proc setx(a:int) { x = a; } 
  omethod proc sety(a:int) { x = a; } 
  fun getxx => x;
  omethod fun getx() => x;
  omethod fun gety () => y;
  omethod fun sum () => x + y;
}


var anX = makeX (23, 42);
println$ anX.getx();
///////////////////////////////////////////////////////


We use "object" instead of "class" because class is already used
for Haskell style typeclasses. Also this suggests that Felix objects are
very much more flexible than Java ones.  Could change to just "obj"
in keeping with shorter names in Felix.

We use "omethod" instead of "method" because accidentally, Mike has a field
"method" in a struct in http_request. Could change this to "meth" although that
sounds like a cheap drunk or crack addict.

How it works: 

interface is a synonym for typedef of a record. It's that simple.

object is slightly tricker. It's just a function which returns a record
of all the functions and procedures (ONLY) inside it marked "omethod",
with the same names. Duplication of names isn't allowed. Obviously
the functions cannot be polymorphic, however the record and object
can be.****

POWER
=====

Felix objects as implemented by object syntax are much more
powerful than Java ones. For a start, every such function is a closure
over the object representation, which is the context of the method
definitions: the function body AND its context. Like any other function.

Although records are immutable you can make them any way you like.
Remember, "object" is just sugar for a function that makes a record.
You can always write any kind of factory function you like.

Although it looks like Java .. the power is much closer to Python.
[For inheritance it will turn out the objects are more prototype
based I suspect .. we'll see]

I will not in passing a *dynamic* version of this using JudySL array
which maps a string name to an object could be quite interesting :)
[Getting the types right is the tricky bit: dynamic typing. But quite
possible using our RTTI I guess, not sure: we could also use
C++ dynamic_cast provided all the objects were derived
from some base "object" type]

TODO
====

Obviously we want "extends" in interfaces. This will be a 
fairly minor patch.

The rule will be: from left to right, then in the body of the extension,
collect fields into a set. Later fields replace earlier ones if they
have the same name. We could also make an error if there
were a conflict in the bases, unless resolved in the extension,
or consider also some consistency in the types of the fields
with the same name.

The patch isn't entirely trivial, because of polymorphism:

interface A[T] { .. }
interface B[U,V]  extends A[U * V] { ... 

The specialisation has to be resolved at binding time, as well as the
lookup. Of course you must note again, the binding stuff knows nothing
about objects or interfaces. So the actual technology will apply to
records in general.

I will also note: exactly the same idea could be applied to structs.
After all they're just a set of fields like a record, with a name thrown in.
[Actually .. Felix record type internally has provision for a name
to enhance the structural typing to include an "extra" identifier]

Similarly unions could be extended for the same reason,
and that includes enums.


*** Existential types ***
We need to understand "universal quantification and existential
quantification", for all and exists, in respect of types. In a function:

fun f[T] (x:T) = { var a : T = x; return a; }

FROM THE OUTSIDE the function is universally quantified by type
variable T. 

FROM THE INSIDE the function is existentially quantified.
This means that inside the function, T is NOT a type variable.
It's an unknown type constant. It can't vary. It's exactly as if there
were a typedef to something we didn't know. So the variable 'a'
in the function is not polymorphic, it's monomorphic. It could
be "int" or "long" we don't know, its "some particular type".

This means for a record type:

typedef X[T] = (f:T->T);

that X is polymorphic. However f is not. If we had:

        (f: T. T->T)

then the field f would be polymorphic. Ocaml can do this in a record.
Felix can't. It's saying f is a polymorphic function.

--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to