Let’s leave this relatively heady mapping/contract/transformation stuff aside for now. I think we’ve got enough to chew on there for now.
To address one of Jonathan Blow’s requirements, let’s promote unique_ptr, shared_ptr and weak_ptr to first-class language constructs. (Partly because this way, the compiler should be able to step in, and do a better job than compiling down code to generate the same things).
We’ll do this by adding some new keywords that modify pointer declarations – owned, shared and weak – and in the process simplify the syntax for using these in the process.
Here’s the old version:
… and here’s the new one:
owned MyType* pPtr;
shared MyType* pPtr;
weak MyType* pPtr;
Much cleaner and more readable, in my opinion.
We also have the advantage that being compiler constructs, we can clean up the way that they’re used.
Assignment from a regular pointer to an owned pointer takes ownership of the pointer.
Assignment from a regular pointer to a shared pointer is not possible, unless the pointer is being assigned to the shared pointer l-value as it is being created by new. (This allows for intrusive reference counts to be generated before the type in memory).
Assignment from an owned or shared pointer to a regular pointer makes a copy of the pointer value, but does not affect ownership.
Assignment from an owned pointer to an owned pointer moves the ownership of the pointer to the assignee.
Assignment from a shared pointer to a shared pointer shares the ownership of the pointer, creating a copy and incrementing the refcount.
Assignment of null to an owned pointer detaches the ownership.
Assignment of null to a shared pointer decrements the refcount, and breaks the link. If the recount hits zero, the object is deleted.
… but other than that, they look and operate exactly like standard pointers. There’s no need to use make_unique or make_shared; the compiler should have enough information to do the right thing.
Sure, it’s syntactic sugar, but it does the right thing.
(Yes, I know I’ve not gone over weak here… I’m trying to just get this out).
Defining an explicit refcount location
If the refcount needs to be explicitly defined in the struct, it could be done by marking the variable that should contain it with an attribute – [refcount]. This allows for things like explicitly requiring that the refcount live on its own cacheline at the end of the struct (for highly-contended refcounts).