Tried out mixins with externs, which I didn't really knew existed. Consider:
class A { int i; void sa (int n) {i = n;} }
class B { extern int i; void sb (int n) {i = n;} }
class C { inherit A; inherit B; void sa2 (int n) {A::i = n;} void sb2 (int n) {B::i = n;} void w() {werror ("C %O %O\n", A::i, B::i);} }
extern variables seem to work alright in that both sa() and sb() assign the same storage. However, what I find surprising is that B::i seems to access a different location in sb2() and w(). Reading it produces 0, regardless what A::i is set to, and trying to set it results in a runtime error. I expected B::i to be an alias for A::i in all respects in C.
Well, since B doesn't actually contain any "i" (the "i" is external to B), I think it would be appropriate for B::i to be an error. But it seems wrong that it's possible to read 0 from it, and that the error is not caught at compile time.
That's one way to look at it. I prefer to think of it as that the local i in B and B::i in C are the same variable, so they should behave the same, and i in B accesses the storage in A both for reading and writing.
Anyway, I agree that reading zero from B::i is wrong.
Another odd thing is that it's no problem to instantiate a B by itself (and it does in fact not have any storage for the variable). Then the local i in B will behave like B::i in my example, i.e. produce 0 when read and a runtime error when written.
Spontaneously I expected a runtime error already at object instantiation, but I guess this is consistent with having declared functions without definitions. Then it follows that both reading and writing such variables must be runtime errors.
Or maybe reading 0 is correct, if one takes the analogy with undefined functions one step further:
class B { extern int i; void f(); void x() {werror ("i: %O, f: %O\n", i, f);} }
int main() { B()->x(); // Writes "i: 0, f: 0" }
But I still would rather have B::i an alias for A::i (and i) in C in my first example.
pike-devel@lists.lysator.liu.se