On Saturday, 3 May 2014 at 12:28:03 UTC, monnoroch wrote:
Back to the dtors: i understand, that all the stuff you propose
could make GC faster, simpler, and cooler,
Note that this is _not_ the motivation behind the discussed
changes. It's primarily about correctness and consistency. What
we currently have if something that doesn't work at all in some
cases (dynamic arrays, new with structs), and where it does work
(class destructors) users have to conform to various rules as to
what is allowed in a GC-called destructor (e.g. don't access
references to other objects, don't throw (?), don't use
thread-local globals, any probably many more subtle rules), that
mostly cannot be enforced statically or even at runtime,
potentially causing silent corruption if you fail to comply with
them. This is IMO more than enough motivation to do something
about it.
but it sounds insane to anyone, who uses the language, not
develops it, that if you create struct object, dror will be
called, but if you place the copy in a container, it wont. It's
just unanderstandable from user's point of view.
Not in a container, but making it GC managed. And IMO, it's
unreasonable to expect deterministic behaviour from a tracing
(non-precise) GC, which is inherently non-deterministic. The real
problem is that you can currently do these things accidentally,
without noticing it.
1) C.
That is the simplest way: fully-manual resource management.
It's obvious, we can't do that in D, because it's supposed to
be simpler for coding, than C.
Again, the main motivation for GC is safety and enabling more
idioms that would otherwise be impossible, _not_ lazyness on the
part of the programmer.
3) C++.
This one is semi-automatic (talking about user code, not some
allocator libraries): you choose the scheme (refcounting,
unique reference) and then it'll do the rest.
4) Rust.
I'm not a pro here, but as i understand, it uses C++ way, and
adds gc-collected pointers, but not sure, so help me here.
You could describe it like that, yes. But it's a lot more
involved. In a way, Rust's owned types are the opposite of a GC:
A GC destroys objects lazily and keeps them alive as long as they
are referenced. Owned objects are destroyed eagerly at the end of
their scope, but the type system ensures that there are no
references to them at this point.
What i propose, is to include new concept in D: scoped objects.
Any object (no matter is it a class or struct instance) can be
either scoped or not.
Dtors for scoped objects are called when out of scope, dtors
for non-scoped objects are not called at all.
It is actually as simple as rewrite code
A a = A();
as
A a = A();
scope(exit)
a.~A();
There is std.typecons.scoped for that, and the deprecated scope
classes. Also see deadalnix's `isolated` proposal:
http://forum.dlang.org/thread/yiwcgyfzfbkzcavuq...@forum.dlang.org
But I'm afraid your suggestion is unsafe: There also needs to be
a way to guarantee that no references to the scoped object exist
when it is destroyed.
I also don't think it's a good idea to have a hard-coded list of
types that are scoped. This either needs to be specified by the
user of the type (at instantion) and then become part of the type
(like const), or it needs to be specified by the implementer of
the type, as a requirement that it can only be instantiated as a
scoped type, or as garbage-collected or reference-counted or ...