For the current moment the Heron specificiation has swelled to four different kinds of pointer/reference types:
type* weak_pointer; // can be reassigned, can't be deleted
type^ strong_pointer; // can be reassigned, can be deleted
type$ temporary; // can't be reassigned, can't be deleted
I didn't want Heron to have garbage collection as a default (at least not in the variant of Heron which I am using) but I wanted to make memory managment easier. The primary way I plan on doing this, is to differentiate between pointers which own the resource (strong pointers) and pointers which simply reference a resource (weak pointers). The strong pointers force programmers to be very explicit about what they are doing, for instance you don't copy strong_pointers, you either transfer them (like auto_ptr) or you share them (like share_ptr). For instance:
my_type^ x = new my_type();
y = x; // illegal instruction, ownership is either transfered or shared
y = transfer(x); // x is set to NULL in the process
x = share(y); // now both point to the object
x = NULL; // x releases hold on object
y = NULL; // runtime error, y has sole-ownership but forgot to delete it
The goal here is to simply require the programmer to be explicit about what they are doing with their pointers. This should clear up a lot of the memory management gotchas that occur in C/C++ code.
Of course the drawback of this explicit pointer stuff is that the language is now harder to learn. My question is, is the increased safety worth the increased syntactic complexity?
> Of course the drawback of this explicit pointer stuff is > that the language is now harder to learn. My question is, > is the increased safety worth the increased syntactic > complexity?
Why? Because you don't get the drawbacks of GC, AND you don't get the drawbacks of raw pointers. The complexity is not increased for the C++ programmer, and in fact it's basically what the current best practice is. OTOH, the Java's GC tries to hide that complexity, and ends up causing much more harm than good.
Of course, Java is hardly the only GC language. OTOH, I believe it's one of a very small number of languages that prohibit programmers from directly accessing the underlying GC system and taking care of the issues that can't be handled automatically.
I can't see why this is needed in non-GC language. In fact, most of the time object holds its own resources and it's natural that other objects don't delete its resources (it may be more or less enforced by proper interface). Your approach doesn't catch statically case when owner deleted resource, but it's still in use (this problem can't be statically solved anyway). The other issue is when object has no owner, which is also not solved by your approach. Dynamic catching of such situations is possible in C++ as well - just create some heavy smart pointer to handle it. If you're intended to leave runtime support of such things it wouldn't lighter then that C++ smart pointer approach.
I'm writing my own language too and this comes back to allowing the caller (or the callee) to define by ref, by pointer or by value. You have the added bonus of strong pointers which I haven't thought of because I handle things differently on that front alone.
I'm working on an idea to seperate variables and what they represent or point to. Even direct variables have one level of indirection with its address. Pointers and references have 2 levels. I haven't worked this out yet, but I'm trying to have all variables work the same way in syntax, except that you can use different assignment for what level you want to copy.
Something to think about is to reverse the level of indirection. Right now in C/C++, you use the * for every level of extra indirection, but there's no way to tell for sure when you're at the actual data other than compiler errors and looking at the syntax for the type. Do you need 1 star, 2 stars or X stars to finally get at the data? If you reversed this and made sure that if you used only the variable name, then it would copy the actual data (by value) no matter how many indirections. If you used one level of indirection, it would copy a reference to it (even if such a reference did not exist as it's simply creating an address). Etc... Higher levels that do not exist would of course create temporaries for the extra indirections.
This is contrary to how the hardware works, but might be simpler on the syntax. This is a rather good topic. I think I'll write it up on my blog as well.