Hi, I am still grappling with this problem:

Felix has a rule for concrete data types, in particular products.
We have quite a few product type: tuples, records, structs, arrays.

Products are characterised by projection functions.
Each product type has a different way of naming them.
We like for a record type:

        typedef r_t = (p1:int, p2:int);
        val r : r_t = (p1=1, p2=2);

to express projections like:

        r.p1

in the OO tradition. Felix says p1 is an ordinary function thingo,
and 

        x . f

means exactly the same as

        f x

so we can also write:

        p1 r

Consequently you can write this too:

        1 (1,2) == 2

because (1,2).1 == 2. Of course 1 isn't a projection but an integer,
but Felix translates the application of an integer to a tuple to the
application of the corresponding projection.

So far so good. Now we also have this notation:

        p <- v;

which means, store the value v into the location p.
We require the type of p and v to be &T and T respectively for some T.

So now if you have

        var x : int;

you can assigned to x like:

        x = 1;

but this is just sugar: Felix translates it to:

        &x <- 1;

It is important to note here that & is NOT an operator. Rather

        &x

is the real name of the variable, that it, it is the machine address
of the associated storage. &x is a name. The syntax

        x

is actually short hand for 

        *(&x)

Note we could have made "x" the name of the address, but to make Felix
look like C we don't. Nevertheless there is something very important going
on here:

        WE HAVE GOTTEN RID OF THE CONCEPT OF LVALUES

[Except in C bindings where we still need them but lets gloss over that :]

Now, in C you can write:

        s.x = 1;

where s is of a struct type with a field x. In Felix this would translate to

        &(s.x) <- 1;

which is nonsense!! Remember, & is not an operator. It is just part of
the name of a variable. So this would be OK:

        (&s).x <-1

But how do we make that work? Isn't the "x" here a projection?
And don't projections apply to product types? But &s is not of a product
type, it's a POINTER to a product.

So the solution? Make projections apply to pointers to products as well!

In particular, if

        p: P -> V

then

        P: &P -> &V

as well, in other words, if you apply a projection to a pointer to a product
you get a pointer to the corresponding field.

This in turn makes it possible to store a value into a PART of a product.

In particular, this makes a GOLDEN RULE (at least for products):

        VALUES ARE IMMUTABLE

If you want to store into a value, stick it into a variable!

        VARIABLES HOLD MUTABLE OBJECTS

The key thing is ALL product values can be made mutable by simply
sticking them into a variable, then using the required chain of projections
on the variable's address:

        var x = (1,2);
        1 &x <- 42;

Yep. That works! It has to. The projection 1 applied to the tuple object x
returns a pointer to the second component which can then be stored into.

The symmetry is very nice!

THE PROBLEM
============

This all works just great! For concrete data types. That is,
one where the compiler knows about the projections.

But for an ABSTRACT data type, it doesn't work automatically.

Suppose you have an array abstraction A,  and some value a
and a method:

        a.get 1;

to get the second component. So find we can write:

        fun apply (p:int, a:A) => a.get p;

and NOW we can indeed write

        a.1

because that means 1 a, and "apply" methods are a way to teach
the compiler how to apply non-functions to values. We can even 
do this: provide a method:

        (&a).get 1; // returns a POINTER

and then an apply function can be used again to allow this:

        (&a).1 <- 42;

But there's a problem! That's not how a varray works.

A varray is literally a pointer underneath. So it is intrinsically
mutable. Like many mutable data structures, you don't need to
store it in a variable to store into its parts.

A varray acts like a value AND like an object.

There's also a major safety problem. With a concrete data type

        var x = 1,2;
        var p = &x.1;

we have a pointer interior to the tuple, which can hang about.
In this case that's just fine, it cannot dangle, and it can only point
into a specific variable.

But that's not true for mutable data types. In particular for a varray,
a pointer into one cannot dangle, but it certainly can point past
the end of the used part of the array (just point to the last element,
then pop it off the end with pop_back).

It's much worse if the data structure is hiding a C++ one!

It is essential to use a pointer to store a value.

get/set methods DO NOT WORK.
This is an OO stupidity. Assignment isn't the only mutator.
Increment is another one. And if you have say, an array then

        set (a, index, value)

looks fine until you consider that the value could be another product
which a component that is another product...  you then get a complete
mess of sets and gets because you have to do a modification to
a temporary and store it back (because a get returns a value ..).

What works is get/ref: get a value, get a reference. But the reference
must be transient (linearly typed, so it must only be used once, and
immediately). Note that get/set DOES enforce this (by hiding the store
address).

So there's the conundrum. In particular in my recent code I had to write:

        set (a,index,v)

even for a varray. The old notation

        a&.index <- v

doesn't work because the &, function is never invoked because now
the PARSER translates

        x*.y ==> (*x).y // which equals *(x.y)
        x&.y ==> (&x).y

to enforce the interpretation above. The problem is i want both

        a . 1 // second component of varray a
        a . 1 <- 42; // assign 42 to first component

to work, the first because that's how ordinary arrays work and the
second because a is really a pointer already so we do NOT want
to have to take the address of "a" to store into it.

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




------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the 
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to