My Language Feature Requests
Christopher Wright
dhasenan at gmail.com
Sun Dec 23 14:54:07 PST 2007
Craig Black wrote:
>> Polymorphic structs *have* to be reference types, unless you determine
>> stack layout at runtime. And not only that, you have to modify stack
>> layout after you've created a stack frame. The only saving grace is
>> that you won't have to do that for a stack frame higher than the
>> current one.
>
> Right, but that's not a problem if you disallow polymorphism for stack
> objects. This is what C++ does and it works very well. Rather than
> generating a run-time assertion, your code would simply not compile. If
> you want polymorphism then you have to instantiate then you would have
> to instantiate the struct on the heap.
Ideally you'd determine whether your polymorphic struct has inheritors
or base classes and, if so, put it on the heap, else put it on the
stack. This is why it'd be better to keep structs as they are, but have
by-value classes.
> struct A { int i, j; }
> struct B : A { long k; }
>
> A foo (A a) { return a; }
> B b;
> b = foo(b); // compile error: instance of struct B can't be implicitly
> converted to an instance of struct A
>
> Anyway, this is all moot anyway, because I've thought of an easier
> solution. Pointers can be checked at run-time to determine if they
> address the GC heap. This check could be removed when compiling in
> release mode, so there will be no performance degradation.
That's the current system, and it's basically what I've been saying all
this time. I guess I was unclear. But you can't remove the check in
release mode:
static import std.c.stdlib;
static import std.gc;
void main () {
// gc memory
auto o = new Object();
o = null;
// not gc memory
void* ptr = std.c.stdlib.malloc(128);
// gc memory (and memory leak)
ptr = null;
ptr = std.gc.malloc(512);
// At this point, no reference to o, so it's deleted.
// The first malloc'd memory still exists and can't ever be
// collected.
ptr = std.gc.malloc(8);
// Now the gc collected the previous 512-byte buffer; of course,
// the 128-byte buffer still exists.
}
> So there's no need to dissallow new and delete for classes and we don't
> need struct polymorphism.
Well, we don't need any kind of polymorphism, but quite separate from
the rest of the requests, struct polymorphism would be useful. Though I
wouldn't refer to them as structs if they're polymorphic, since you
really can't put them on the stack, and so they have to be reference
types with value semantics.
>> You're saying:
>> class Foo {
>> int i;
>> }
>>
>> Foo f = new Foo();
>> int* i_ptr = &f.i;
>>
>> That would be a compile error? f is not fixed; I don't care if the
>> bits in i_ptr change, or the bits in the reference f. Why should I?
>>
>> Just because I took the address of f.i and stored it in an unfixed
>> pointer, the garbage collector, which has full authority to change the
>> pointer I just got, can't move *f?
>>
>> Why?
>
> I'm not really sure what you are asking. If the GC moves the relocates
> f, then i_ptr no longer points the appropriate location. Isn't that
> obvious?
>
> Are you suggesting that the GC relocate i_ptr as well? No GC I know of
> relocates raw pointers, so there's probably a good technical reason why
> they don't. I'm not a GC expert though.
Because no language besides D allows you to take the address of an class
member and has native garbage collection, and D doesn't have a moving
collector. There's the Boehm collector for C++, but that's not a moving
collector. C# has unsafe blocks in which you can use pointers, but in
those blocks you don't have a garbage collector running. And...that's
it. Maybe we'll see something revolutionary with Objective-C 2.0, but
probably not, and it's not here yet.
You're already moving raw pointers, so you may as well move all of them.
Otherwise you're eliminating a decently general use case or causing
random segfaults or losing a lot of efficiency in memory layout (which
will make future collections quicker, too) for pretty much nothing.
More information about the Digitalmars-d
mailing list