My first idea to solve this problem was to introduce "inout return types". It would provide an extra (hidden) reference to the actual type, as it is done for inout parameters. But I decided not to do that, as it would be a quirky solution. And then someone pointed out that the current pointer system is weird and makes source code unreadable because of the implicit (de)referencing done by the compiler. So I thought of changing the type system to be more like C++, with explicit referencing/dereferencing for most things. Unfortunately it seemed to me that the changes would lead me to something that was almost identical to C++ but a bit more complicated. I decided that this wasn't an option either.
I looked back to the actual problem and my first idea of 'inout return types'. What I have come up with is a bit similar to that solution, only less quirky. The main idea is introducing a second pointer level, thus allowing a pointer-to-pointer-to-class type to be declared in some places. This introduces an ambiguity, namely: to what pointer level does the pointer assignment etc. apply to? Well, the second (i.e. top-level) pointer is only used as a reference to the single pointer; you need to be able to change the single pointer as in the array-of-pointer-to-int example. That means all pointer operations would need to work on the single pointer, the one that points to the 'int' in the example. The double pointer would serve like a reference in C++, only initialized once and always dereferenced when used in an expression. The usage of such a double pointer is not universal; it would not be allowed for parameter types, because input parameters don't need a second level of indirection and because inout parameters already provide an implicit second pointer for a pointer parameter. A double pointer can be useful for return types, for variable types, and maybe for fields as well.
Some examples now:
var i : int = 22As you see in the example pp can not be changed anymore; it is a reference to p and all pointer assignments done on pp will be therefore applied to p.
var p: *int = i # points to i
var pp: **int = p # points to p
var b : bool
b = (p = 22) # yes, p equals 22
b = (pp = 22) # yes, pp equals 22
b = (pp $= p) # yes, pp equals p
p = 47 # change i to 47
pp = 84 # change i to 84
p $= new int(55) # p no longer points to i
pp $= new int(31) # p changed again, points to 31
This new functionality allows us to write a class that serves as a pointer-to-int:
class IntPtrArrayI'm not sure when I will implement this feature, but unless I get some serious objections against this the feature will be added to the language.
public:
var fP : [10] * int # array has a fixed size of 10 ints
const procedure size() : nat
return 10
end
operator[](index:nat) : **int
# return a reference to the int pointer
return fP[index]
end
const operator[](index:nat) : *int
# no double pointer return needed (array is const)
return fP[index]
end
end