Steven Schveighoffer wrote:
On Thu, 22 Oct 2009 12:50:21 -0400, grauzone <n...@example.net> wrote:
dsimcha wrote:
== Quote from grauzone (n...@example.net)'s article
Andrei Alexandrescu wrote:
I'd really like to know why "scope x = new X();" is "unsafe", while
encouraging doing exactly the same with structs seems to be a perfectly
fine idea. Allocating structs on the stack is obviously not any safer
than with classes. I don't remember the exact reasons why you wanted to
turn "scope" into a library feature, but I think I remember something
about discouraging it for safety reasons; please forgive me is this is
wrong.
Because classes in D are always passed by pointer. (Technically
references, but
really they're just pointers under the hood.) Returning a scope
(stack-allocated)
class from a function is equivalent to escaping a pointer to a stack
variable.
Returning a struct is done by value, just like returning an int.
(I'm talking about scope classes as declared in "scope class T { ... }")
Your original question was about the statement "scope x = new X()",
which can be done on any type of class, even non-scope ones.
I mentioned that "scope class T" thing in my original post too.
But you can't return scope classes from a function. You can't pass
them as ref parameters either. They're designed to be safe.
On the other hand, you can pass struct pointers all the way you want
around, and it's damn unsafe.
I don't get this "structs are safe because they are value types"
argument anyway, because the this pointer for structs is a
pointer/reference anyway. If it's trivial to break that "safety", can
you really call it "safety"?
Passing struct pointers is not always the norm. Passing class
references *is* the norm (and actually the only way), even for scope
classes, so there is much more chance for escape.
You can end up passing hidden pointers quickly, because a struct's this
is a reference, and there are ref parameters and even ref returns. But
Andrei is convinced that he can make passing refs safe, and as soon as
they're safe, you're probably right.
Scope is really a dangerous hack to allocate a *reference type* on
the stack.
It's dangerous and kludgey, but in a performance-oriented language
it's a
necessary evil.
You could say the same about structs.
You have to go out of your way to pass a struct by reference. You
*can't* possibly pass a class by value, so they are more dangerous.
In order to make scope safer, it has to be a type modifier in addition
to a storage class, so the compiler can make reasonable decisions (like
disallowing implicit casting to a non-scope version).
That would have been possible. That type modifiers is already there and
is partially implemented. But Andrei seems to have decided to go another
way (using structs instead of classes), and this will become a useless
feature. So I hope it will be removed to make the language less bloater.
<OT>
Why do all objects have monitor pointers anyway? The idea, that every
object can act as lock, is a really bad one. But this is off-topic...
All objects have a *placeholder* for a lock, which isn't allocated until
the object is locked for the first time. It's a very pervasive idea in
other successful languages like Java and C#. Having used it extensively
in C#, I find it very easy to use and well designed.
I found it never useful. Even more, implicitly using an object as a lock
makes the locking scheme more unclear ("which object is a lock and which
isn't? I can't tell anymore!"), and I see lots of code that does the
"Object lock = new Object();" thing to get rid of this confusion.
Being able to use an object as lock looks like a nice, naive idea from
the early days of multithreading, but it's obsolete now.
Even if the allocation of the mutex is done lazily on demand, why add
overhead to *all* light weight objects for such a useless thing?
However, in C#, there is support for conditions on objects as well,
which isn't "builtin" for D. IMO, mutexes without conditions is
severely limiting. The library condition variables aren't as nice as
C#'s builtin conditions.
I always wondered how D could claim to make "big steps" into
multithreading, without having any mechanism to signal other threads; it
only had locks. The library condition variables from D runtime just
fixed this hole from "outside".
</OT>
-Steve