I am still grappling with Felix core semantics.

Here's a rough outline. 

Felix has values and objects. Values are immutable.
Values are first class. Objects may be mutable. 

Literals other than strings, are values, tuples, records, structs, and other
similar constructor combine values into values. Function closures are
also values. Procedure (and generator) closures are objects.

Objects can be created on the heap by various means. Objects can't be
accessed directly, by rather accessed and modified via pointers,
which are themselves values.

A value may be stored in a variable. When this happens, you can
take the address of the variable and have thereby converted the value
into an object by making it addressable. You can then modify components
of the value, even though values are immutable, since such a modification
is equivalent to constructing a new value with a changed component
and storing it back in the variable. [We should add functional updates
to Felix]

Ok, so that's the object model. Now for the execution model.

Felix has three evaluation strategies: do it now (eager), do it later (lazy),
and let the compiler decide. Assignment or initialisation of a variable
is eager:

        var x = y + z; // uses values of y, z current when control
                // flows through the statement

Functional values:

        fun x = y + z;

are lazy. x is evaluated where it is used, separately for each use,
and so depends on the value of y and z at that time. In effect lazy
evaluation is substitution.

Value definition:

        val x = y + z;

can be eager or lazy. It's up to the compiler. If y and z are invariant,
it doesn't matter when x is evaluated: this is sometimes called
referential transparency.

A val constructed from only literals and other vals is certain to be
transparent if control only flows through those value definitions
exactly once. However there's a nasty glitch in the semantics:

        for i in 1 upto 10 do
                val x = i;
        done

Here, even though x is a val, it takes on different values, like
a variable. This is a bit nasty! Note also, a value might not
be defined when used:

        if false do 
                val x = 1;
        done
        print x; // woops

Although this seems messy don't forget:

        print x;
        val x = 1;

has the same effect without a loop or conditions. But perhaps it
is worse that:

        var a = 1;
        val x = a;
        a++;
        print x;

could print either 1 or 2. This isn't intuitive. Presently the execution
model is conflated with the object model. Although x is not addressable
and is immutable, it's value isn't deterministic: it can depend on the
values of variables at the time it is evaluated, which is not determinate.

[The compiler does NOT deliberately do this at the moment,
on the contrary, it tries valiantly to ensure that a val is like a var
but just not addressable. That's for a plain declaration, but it isn't
as keen on doing that when the val is a parameter]

The same issue applies to functions: pure functions depend only
on parameters, but impure ones can depend on variables
(even though the function may not have side effects, it can still
depend on side-effects).

Lazy evaluation of expressions is forced by lifting them to closures:

        { x + y }

The time at which a variable's value is used can also be controlled
by using a pointer to it, and dereferencing it: this is not yet assured
but the compiler doesn't try to guess what value is stored in a variable
from a pointer to it.

Also note that lazy evaluation of function parameters may occur
when the function is inlined, but rarely occurs when it isn't.
Never-the-less it may happen, especially with a child function
whose parent is inlined (this may cause the child to be
specialised during the reparenting process).

I'm thinking about banning dependence of val on vars,
or on dereferences of pointers to ensure transparency.
In that parametric vals:

        val y = 1;
        val f (x:int) => x + y;

would be pure functions. This would also mean it's safe
to assign val symbols at any time: eagerly or lazily.
The only difference would be if the evaluation was
invalid (bottom in Haskell). E.g. division by zero.

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




------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to