ark-lang / ark

A compiled systems programming language written in Go using the LLVM framework
https://ark-lang.github.io/
MIT License
682 stars 47 forks source link

Big Pointer/Reference Proposal #665

Closed MovingtoMars closed 8 years ago

MovingtoMars commented 8 years ago

These are some changes to simplify syntax and semantics.

Types

@int - raw pointer to int
^int - ARC pointer to int
&int - reference to int

By default, these types are immutable. Mutable variations:

@mut int - mutable raw pointer to int
^mut int - mutable ARC pointer to int
&mut int - mutable reference to int

Raw pointers and referecnes can be created by using the same symbol used in the type as the address-of operator. There is no address-of operator for ARC pointers.

thing := 10;

@thing // raw pointer to thing
&thing // reference to thing

@mut thing // mutable raw pointer to thing
&mut thing // mutalbe reference to thing

Note that you cannot take a raw pointer to a stack variable. You can bypass this restruction like so: raw_ptr := @int(uintptr(&thing));

Dereferencing

There is one deference operator to rule them all: *.

thing := 10;

*(@thing) // same as thing
*(&thing) // same as thing

Casting

Raw pointers and references can be casted to uintptr and back.

To get a raw pointer from an ARC pointer, use the library function mem::arc_get_raw_pointer<T>(ptr: ^T) -> @T.

To get an ARC pointer from a raw pointer, use the library function mem::arc_from_raw_pointer<T>(ptr: @T, refs int) -> ^T.

Raw pointers and ARC pointers can be implicitly casted to references. This is useful for functions which should be able to take all three types.

func do(a: &int) {
    *a = 5;
}

func main() -> int {
    // pass an ARC pointer to do()
    // it's essentially the same for raw pointers
    arc_ptr: ^int = mem:alloc<int>();
    do(arc_ptr);

    // pass a stack var reference to do()
    i: int = 5;
    do(&i);

    return 0;
}

Also, all 3 mutable type variations can be implicitly casted to their immutable variations.

MovingtoMars commented 8 years ago

Hopefully, with this setup, the compiler will be able optimise out many ref count checks. Also, it could even replace some ARC pointers with raw pointers when it is proven to be safe.

felixangell commented 8 years ago

LGTM, perhaps in the casting from_raw_ptr and to_raw_ptr, we could put this inside arc.ark so in effect you do arc::from_raw_ptr or something like that. Not particularly sure on the @ symbol for raw pointers, any particular reason why you chose this over something like an asterisks *?

MovingtoMars commented 8 years ago

It's to make it consistent with the other two, where the type symbol is the same as the address-of operator. Keeping * separate from all three keeps it clean.

felixangell commented 8 years ago

@MovingtoMars Ah yeah the dereferencing stuff, hm yeah I guess I like most of this though if we could pick a symbol for raw pointers could it be like ', so x: 'int = .... I'm not too bothered, but if the opportunity is there...

MovingtoMars commented 8 years ago

Ideally, you shouldn't be using raw pointer too often, so it shouldn't matter.

SamTebbs33 commented 8 years ago

This seems a bit overcomplicated, couldn't all references be reference counted, rather than having a totally distinct type for that?

felixangell commented 8 years ago

@SamTebbs33 The idea is it's a systems language, you don't want to reference count everything because:

Though I do agree that introducing 3 new types is a little overcomplicated for my liking.

felixangell commented 8 years ago

@MovingtoMars Yah but the @ symbol seems a little arbitrary, and if we're going for arbitrary I'd rather it be foo: 'T = ... :wink:

kiljacken commented 8 years ago

I'll start out with saying that in general, I think this is a really complicated approach, and ideally I'd want just raw pointers and then do (A)RC completely in the stdlib, mainly via the implementation of RAII-like system using interfaces (e.g a Drop interface containing a method that would be invoked once the value leaves scope).

Now with that out of the way, my comments on this approach:

felixangell commented 8 years ago

@kiljacken I mostly agree, I would prefer arc in the stdlib rather than introducing loads of weird pointer syntax.

MovingtoMars commented 8 years ago

Ok. It'll probably be a lot less complicated by putting it in the stdlib.