on preventing null:
along the way of discussing pointer idioms, I wrote that nullable pointers should be expressed as a disjoint union between nothing (null) and a pointer value. this means that a pointer, to the type system, is something which does point to a live, non-null, non-special object. if a pointer "can be null", it's not expressed as a pointer; it's expressed as a union. union {null, pointer} so to speak. this is standard in several languages, it works fine; you just need language support for disjoint unions, not C's "inclusive unions". it's really the same thing elanthis is describing, only formalized using a normal language feature. when you have a value of that type, you need to switch on its value
in order to dereference it, such as:
switch (maybenull) {
case pointer p: p->dosomething();
case null: donull();
}
notice that there's only a pointer value p in scope in the switch arm corresponding to the pointer part of the union. the principal benefit to this approach is that the dereference operator is statically inapplicable to the null value. it doesn't even get a name. you know by looking at types alone when you need to write this form and when you have a live pointer. for cases where there may be a null, you're using a union of this type, and you're forced to handle it. for cases where there may not be a null, you just use a pointer. really, this is not at all novel. it already exists in many languages.
on preventing cycles:
the "transfer of ownership" idiom I described is insufficient, as elanthis pointed out. I think a more correct way to do this is to require that an owning pointer (or disjoint owning/null union) can only receive its value when it is initialized. it is then inexpressible to "assign" to that variable, merely to evict its value (transferring to another variable which is being initialized) or destroy it.
I think that restriction does the trick; you would need to initialize A before B and B before A to make a cycle. I believe there is some relationship between this approach and the "linear naming" research that chalst is doing. perhaps I'm underestimating his work though.
in any case, I mostly disagree with elanthis' position that cyclical ownership is some sort of special, unsolvable problem. it's just a delicate problem. I think it's generally understood that structural language restrictions are a tradeoff between "helping to organize your thoughts" and "binding your hands from doing useful work"; such things must be developed carefully and with attention to costs, but not treated as sacred cows.