Pointer Types

Machine Pointers

A machine pointed is a typed machine address. Felix has three types of machine level pointers.

Type Deref Storeat Semantics
&<T Y N Read only pointer to T
&>T N Y Write only pointer to T
&T Y Y Read or write pointer to T

Read only pointers are semantically equivalent to C++ const pointers.

Operations

Dereference

The system builtin dereference operation is named _deref and is an operator equivalent to a function

fun _deref: &<T -> T;

The library defines an overloadable function of the same type:

fun deref[T] (p:&<T): T => _deref p;

which can also be invoked by the syntax:

*p

The dereference operation fetches the value of a storage location at the address of the pointer.

Storeat

The system buildin storage operation is named _storeat and is equivalent to a procedure

proc _storeat: &>T * T;

The library defines an overloadable procedure of the same type:

proc storeat[T] (p:&>T, v:T) => _storeat(p,v);

which can also be invoked by the syntax

p <- v;

The storeat operation stores its value argument into the storage location at the address of the pointer.

Subtyping Rules

The read-write pointer type is an invariant subtype of the read-only pointer type, and an invariant subtype of the write only pointer type.

In theory read is covariant and write contravariant but this is not implemented at the present time.

This means a read-write pointer may be used wherever either a read-only or write-only pointer is required.

Constructors

All three types of pointers can be constructed by addressing a variable.

var x = 1; // type int
var ropx : &<int = &<x;
var wopx : &>int = &>x;
var rwpx : &int = &x;

In addition, a read-write pointer is returned by the system intrinice operator new which copies a value onto the heap and returns a pointer to it:

var px = new 42; // &int

Other operations returning pointers are defined in the library, typically by binding to C or C++ functions such as malloc.

Pointer Projections

Projection operators applying to arrays, tuples, records, and structs, are all overloaded to work on pointers to these types. For example, to store a value in a structure component:

struct X { int a; int b; };
var x = X (1,2);
&x . a <- 42; // sets x.a to 42

Object Concept

The use of pointer projections equips Felix with a radical model of values and objects. Instead of references, lvalues and rvalues as in C++, Felix has a powerful alternative model.

In Felix all values of product type are immutable and first class, including arrays. However if such a value is stored in an addressable variable, it has an address. If a value is constructured on the heap a pointer is returned.

Thus, the components of a value can be fetched but not modified, whilst, via pointer projections, the components of a value stored in an addressable location can be fetched and modified.

However, pointers are themselves first class values. Therefore, Felix supports mutation entirely with a value semantics.