Re: this() not executing code on structs

2009-10-23 Thread Denis Koroskin
On Sat, 24 Oct 2009 03:28:02 +0400, Denis Koroskin <2kor...@gmail.com>  
wrote:



On Fri, 23 Oct 2009 19:40:33 +0400, Andrei Alexandrescu
 wrote:


Denis Koroskin wrote:
On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu  
 wrote:



Don wrote:

Bartosz Milewski wrote:

Andrei Alexandrescu Wrote:


this() { myCount = count++; }   // ERROR


It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so  
should constructors with all parameters defaulted.

 Ouch.
It's because it's interpreting foo() as a struct literal.
If a struct has any constructors, struct literals should be disabled.


http://d.puremagic.com/issues/show_bug.cgi?id=3438

The more I think of it, the more imperious it becomes that we allow  
default constructors that execute code. The main question is what to  
do about .init.


Andrei
 I'd suggest ditching it and enforce explicit member initialization  
(unless a variable is nullable). This will also remove a lot of bloat  
from executables.


I don't understand. The problem right now is that even of all fields  
are explicitly intialized, e.g.


struct A {
 Widget x = null;
 double d = 0;
 int i = -1;
}

there is still no ability to execute code upon initialization, e.g.  
force A to contain a non-null Widget.



Andrei


Yes, I was talking about a different scheme, where default ctors are
allowed. They aren't allowed now but we are talking about things we can
change/improve, right?

I mean there is no _real_ need for T.init, just malloc()'ate some memory  
and call the __ctor on it. Struct members default values would be  
converted into runtime initialization expressions like this:


struct A
{
 this(Args)(Args args) // may be an empty set of arguments
 {
 // the following lines are inserted automatically
 x = null;
 d = 0;
 i = -1;

 // user-defined code follows
 i = 42;
 }

 Widget x = null;
 double d = 0;
 int i = -1;
}

Optimization pass would eliminate double initialization (in the case  
about i would be initialized straight to 42)


This scheme works fine for C++, and it would fit languages that don't  
support MI even better.


I believe D's approach with init is a bit easier to understand (rules are  
less complicated), but it is also not very efficient: a few stores/pushes  
are faster than memcpy'ing few bytes in most cases (minor but still). And  
an additional bloat it introduces is also not very welcome, of course.


While I'm not a idealizing C++ object initialization scheme, I do think it  
is sound (even though it is complicated). Some variation of it may be well  
suitable for D.


I made the following post a while ago  
(http://www.digitalmars.com/d/archives/digitalmars/D/D_programming_practices_object_construction_order_85468.html),  
it may interest you as I believe it is relevant to this discussion.  
Unfortunately no one has made any comments about it (is it silly, or just  
nobody cares?).


Re: this() not executing code on structs

2009-10-23 Thread grauzone

Steven Schveighoffer wrote:

On Thu, 22 Oct 2009 12:50:21 -0400, grauzone  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.





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".





-Steve


Re: this() not executing code on structs

2009-10-23 Thread Denis Koroskin

On Fri, 23 Oct 2009 19:40:33 +0400, Andrei Alexandrescu
 wrote:


Denis Koroskin wrote:
On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu  
 wrote:



Don wrote:

Bartosz Milewski wrote:

Andrei Alexandrescu Wrote:


this() { myCount = count++; }   // ERROR


It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so  
should constructors with all parameters defaulted.

 Ouch.
It's because it's interpreting foo() as a struct literal.
If a struct has any constructors, struct literals should be disabled.


http://d.puremagic.com/issues/show_bug.cgi?id=3438

The more I think of it, the more imperious it becomes that we allow  
default constructors that execute code. The main question is what to  
do about .init.


Andrei
 I'd suggest ditching it and enforce explicit member initialization  
(unless a variable is nullable). This will also remove a lot of bloat  
from executables.


I don't understand. The problem right now is that even of all fields are  
explicitly intialized, e.g.


struct A {
 Widget x = null;
 double d = 0;
 int i = -1;
}

there is still no ability to execute code upon initialization, e.g.  
force A to contain a non-null Widget.



Andrei


Yes, I was talking about a different scheme, where default ctors are
allowed. They aren't allowed now but we are talking about things we can
change/improve, right?

I mean there is no _real_ need for T.init, just malloc()'ate some memory  
and call the __ctor on it. Struct members default values would be  
converted into runtime initialization expressions like this:


struct A
{
this(Args)(Args args) // may be an empty set of arguments
{
// the following lines are inserted automatically
x = null;
d = 0;
i = -1;

// user-defined code follows
i = 42;
}

Widget x = null;
double d = 0;
int i = -1;
}

Optimization pass would eliminate double initialization (in the case about  
i would be initialized straight to 42)


Re: this() not executing code on structs

2009-10-23 Thread Andrei Alexandrescu

Denis Koroskin wrote:
On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu 
 wrote:



Don wrote:

Bartosz Milewski wrote:

Andrei Alexandrescu Wrote:


this() { myCount = count++; }   // ERROR


It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so 
should constructors with all parameters defaulted.

 Ouch.
It's because it's interpreting foo() as a struct literal.
If a struct has any constructors, struct literals should be disabled.


http://d.puremagic.com/issues/show_bug.cgi?id=3438

The more I think of it, the more imperious it becomes that we allow 
default constructors that execute code. The main question is what to 
do about .init.


Andrei


I'd suggest ditching it and enforce explicit member initialization 
(unless a variable is nullable). This will also remove a lot of bloat 
from executables.


I don't understand. The problem right now is that even of all fields are 
explicitly intialized, e.g.


struct A {
Widget x = null;
double d = 0;
int i = -1;
}

there is still no ability to execute code upon initialization, e.g. 
force A to contain a non-null Widget.



Andrei


Re: this() not executing code on structs

2009-10-23 Thread Denis Koroskin
On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu  
 wrote:



Don wrote:

Bartosz Milewski wrote:

Andrei Alexandrescu Wrote:


this() { myCount = count++; }   // ERROR


It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so  
should constructors with all parameters defaulted.

 Ouch.
It's because it's interpreting foo() as a struct literal.
If a struct has any constructors, struct literals should be disabled.


http://d.puremagic.com/issues/show_bug.cgi?id=3438

The more I think of it, the more imperious it becomes that we allow  
default constructors that execute code. The main question is what to do  
about .init.


Andrei


I'd suggest ditching it and enforce explicit member initialization (unless  
a variable is nullable). This will also remove a lot of bloat from  
executables.


Re: this() not executing code on structs

2009-10-23 Thread Andrei Alexandrescu

Don wrote:

Bartosz Milewski wrote:

Andrei Alexandrescu Wrote:


this() { myCount = count++; }   // ERROR


It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so 
should constructors with all parameters defaulted.


Ouch.
It's because it's interpreting foo() as a struct literal.
If a struct has any constructors, struct literals should be disabled.


http://d.puremagic.com/issues/show_bug.cgi?id=3438

The more I think of it, the more imperious it becomes that we allow 
default constructors that execute code. The main question is what to do 
about .init.


Andrei


Re: this() not executing code on structs

2009-10-23 Thread Don

Bartosz Milewski wrote:

Andrei Alexandrescu Wrote:


this() { myCount = count++; }   // ERROR


It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so should 
constructors with all parameters defaulted.


Ouch.
It's because it's interpreting foo() as a struct literal.
If a struct has any constructors, struct literals should be disabled.


Re: this() not executing code on structs

2009-10-23 Thread Steven Schveighoffer

On Thu, 22 Oct 2009 12:50:21 -0400, grauzone  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.



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.




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).




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.


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.



-Steve


Re: this() not executing code on structs

2009-10-22 Thread Andrei Alexandrescu

grauzone wrote:

Andrei Alexandrescu wrote:

grauzone 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 { ... }")

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.


I wish it was as easy as it sounds. In fact you don't need to pass 
scope classes as ref parameters - it's enough to pass them "by value" 
because they are implicitly references.


You can't even safely call a method on a scope class object because 
that method may assign "this" to something escaping the scope of the 
method.


Save for using some flavor of interprocedural escape analysis and/or 
making "scope" a function attribute, I'm not seeing how scope can be 
made safe and reasonably useful.


OK, but the user of that class is still forced to use it safely. It's 
the implementor's responsibility to make sure he doesn't to unsafe 
things. It's the same with structs, at least in normal D (not SafeD).


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"?


The point is that you can disable address taking altogether and still 
write a great deal of good code in D. If address taking is verboten 
(e.g. in SafeD), ref parameters can never be escaped (they will be 
scoped) and therefore they become safe, too. So within SafeD, structs 
become safe, but scope class objects still couldn't be made safe 
without heroic effort.


I wonder about that. How will the following example will be made safe? 
Right now, ref parameters _can_ escape with the help of ref returns.


import std.stdio;

ref int foo(ref int z, int something) {
return z;
}

ref int foo2() {
int u = 123;
return foo(u, 0);
}

void main() {
writefln("%s", foo(foo2(), {char[20] tmp;  return 0; }()));
}

It's probably not minimal, but it demonstrates how you can return 
references to outdated stack locations without explicitly taking 
pointers. That delegate literal overwrites the stack, so that writefln 
outputs garbage.


How to solve this? Disallow ref arguments or ref returns in SafeD, 
because they are hidden "address taking"?


Or is this all besides the point?


It's right to the point. I keep on forgetting about that corner case, 
Steve pointed it to me a long time ago. In the call foo(u, 0) the 
compiler must conservatively assume that the scope of the returned value 
is the same as the scope of u, and therefore disallow compilation of foo2.



Andrei


Re: this() not executing code on structs

2009-10-22 Thread grauzone

Andrei Alexandrescu wrote:

grauzone 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 { ... }")

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.


I wish it was as easy as it sounds. In fact you don't need to pass scope 
classes as ref parameters - it's enough to pass them "by value" because 
they are implicitly references.


You can't even safely call a method on a scope class object because that 
method may assign "this" to something escaping the scope of the method.


Save for using some flavor of interprocedural escape analysis and/or 
making "scope" a function attribute, I'm not seeing how scope can be 
made safe and reasonably useful.


OK, but the user of that class is still forced to use it safely. It's 
the implementor's responsibility to make sure he doesn't to unsafe 
things. It's the same with structs, at least in normal D (not SafeD).


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"?


The point is that you can disable address taking altogether and still 
write a great deal of good code in D. If address taking is verboten 
(e.g. in SafeD), ref parameters can never be escaped (they will be 
scoped) and therefore they become safe, too. So within SafeD, structs 
become safe, but scope class objects still couldn't be made safe without 
heroic effort.


I wonder about that. How will the following example will be made safe? 
Right now, ref parameters _can_ escape with the help of ref returns.


import std.stdio;

ref int foo(ref int z, int something) {
return z;
}

ref int foo2() {
int u = 123;
return foo(u, 0);
}

void main() {
writefln("%s", foo(foo2(), {char[20] tmp;  return 0; }()));
}

It's probably not minimal, but it demonstrates how you can return 
references to outdated stack locations without explicitly taking 
pointers. That delegate literal overwrites the stack, so that writefln 
outputs garbage.


How to solve this? Disallow ref arguments or ref returns in SafeD, 
because they are hidden "address taking"?


Or is this all besides the point?

(Hello world doesn't compile with -safe (Phobos issue), so I couldn't 
test it with -safe on dmd v2.032.)




Andrei


Re: this() not executing code on structs

2009-10-22 Thread Andrei Alexandrescu

grauzone 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 { ... }")

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.


I wish it was as easy as it sounds. In fact you don't need to pass scope 
classes as ref parameters - it's enough to pass them "by value" because 
they are implicitly references.


You can't even safely call a method on a scope class object because that 
method may assign "this" to something escaping the scope of the method.


Save for using some flavor of interprocedural escape analysis and/or 
making "scope" a function attribute, I'm not seeing how scope can be 
made safe and reasonably useful.


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"?


The point is that you can disable address taking altogether and still 
write a great deal of good code in D. If address taking is verboten 
(e.g. in SafeD), ref parameters can never be escaped (they will be 
scoped) and therefore they become safe, too. So within SafeD, structs 
become safe, but scope class objects still couldn't be made safe without 
heroic effort.



Andrei


Re: this() not executing code on structs

2009-10-22 Thread Denis Koroskin
On Thu, 22 Oct 2009 21:01:15 +0400, Andrei Alexandrescu  
 wrote:



grauzone 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 { ...  
}")
 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.


I wish it was as easy as it sounds. In fact you don't need to pass scope  
classes as ref parameters - it's enough to pass them "by value" because  
they are implicitly references.


You can't even safely call a method on a scope class object because that  
method may assign "this" to something escaping the scope of the method.


Save for using some flavor of interprocedural escape analysis and/or  
making "scope" a function attribute, I'm not seeing how scope can be  
made safe and reasonably useful.


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"?


The point is that you can disable address taking altogether and still  
write a great deal of good code in D. If address taking is verboten  
(e.g. in SafeD), ref parameters can never be escaped (they will be  
scoped) and therefore they become safe, too. So within SafeD, structs  
become safe, but scope class objects still couldn't be made safe without  
heroic effort.



Andrei


Scope classes could be disallowed in SafeD, but you can't disallow  
Scope!(Object).


Re: this() not executing code on structs

2009-10-22 Thread grauzone

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 { ... }")

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"?



Classes can't be value types because they are polymorphic, meaning their size
isn't known at compile time.  C++ tries to make them value types but really, 
there
is no *good* way to make a polymorphic type with size not known at compile time 
a
value type.


Why do you want to add class functionality to structs to enable "RAII"
like features, when you could just use scope classes?


To me, this makes perfect sense.  Classes are polymorphic, structs are value
types.  Except in the "here be dragons" world of C++, the two are mutually
exclusive, which is the reason for the dichotomy in the first place.  Therefore,
structs should do everything they can w/o being polymorphic and classes should 
do
everything they can w/o being value types.  You then decide which one you want
based on whether you need value semantics or polymorphism more.

The only place in D where this logic breaks down is monitor objects on classes.
Even here, while structs technically *could* be given monitors, this is
inefficient because they are value types, whereas the efficiency loss from 
storing
a few extra bytes in a reference type is minimal in most cases.


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...



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.


Re: this() not executing code on structs

2009-10-22 Thread grauzone

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.


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"?



Classes can't be value types because they are polymorphic, meaning their size
isn't known at compile time.  C++ tries to make them value types but really, 
there
is no *good* way to make a polymorphic type with size not known at compile time 
a
value type.


Why do you want to add class functionality to structs to enable "RAII"
like features, when you could just use scope classes?


To me, this makes perfect sense.  Classes are polymorphic, structs are value
types.  Except in the "here be dragons" world of C++, the two are mutually
exclusive, which is the reason for the dichotomy in the first place.  Therefore,
structs should do everything they can w/o being polymorphic and classes should 
do
everything they can w/o being value types.  You then decide which one you want
based on whether you need value semantics or polymorphism more.

The only place in D where this logic breaks down is monitor objects on classes.
Even here, while structs technically *could* be given monitors, this is
inefficient because they are value types, whereas the efficiency loss from 
storing
a few extra bytes in a reference type is minimal in most cases.


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...



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.


Re: this() not executing code on structs

2009-10-21 Thread dsimcha
== 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.

Classes can't be value types because they are polymorphic, meaning their size
isn't known at compile time.  C++ tries to make them value types but really, 
there
is no *good* way to make a polymorphic type with size not known at compile time 
a
value type.

> Why do you want to add class functionality to structs to enable "RAII"
> like features, when you could just use scope classes?

To me, this makes perfect sense.  Classes are polymorphic, structs are value
types.  Except in the "here be dragons" world of C++, the two are mutually
exclusive, which is the reason for the dichotomy in the first place.  Therefore,
structs should do everything they can w/o being polymorphic and classes should 
do
everything they can w/o being value types.  You then decide which one you want
based on whether you need value semantics or polymorphism more.

The only place in D where this logic breaks down is monitor objects on classes.
Even here, while structs technically *could* be given monitors, this is
inefficient because they are value types, whereas the efficiency loss from 
storing
a few extra bytes in a reference type is minimal in most cases.

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.


Re: this() not executing code on structs

2009-10-21 Thread Steven Schveighoffer

On Wed, 21 Oct 2009 17:54:08 -0400, grauzone  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.


A class is a reference type.  If you pass the reference to the stack to a  
function that then stores it for later use, it is unsafe.  If you return  
it from the function, it's unsafe.  If you do the same with a struct (not  
a struct pointer), this is not the case.  Note that you *could* have the  
same problem with struct pointers or references, but typically, you expect  
to treat struct references like they are referencing stack data, it's not  
typical for classes.


-Steve


Re: this() not executing code on structs

2009-10-21 Thread grauzone

Andrei Alexandrescu wrote:
Today, structs can't write their own this(). There aren't very solid 
reasons for that except that it makes language implementation more 
difficult.


I wonder how much of a problem that could be in practice. I realized 
today that the "Counted" example - a classic C++ primer example 
featuring a struct that counts its own instances - cannot be implemented 
in D.


In C++ the counted example looks like this:

struct Counted {
   static unsigned count;
   unsigned myCount;
   Counted() { myCount = count++; }
   Counted(const Counted& rhs) { myCount = count++; }
   Counted& operator=(const Counted& rhs) {
  // no writing to myCount
  return *this;
   }
   ~Counted() {
  --count;
   }
}

In D there's no chance to write Counted because you can always create 
Counted objects without executing any code.


struct Counted {
   static uint count;
   uint myCount;
   this() { myCount = count++; }   // ERROR
   this(this) { myCount = count++; }
   ref Counted opAssign(Counted rhs) {
  // no writing to myCount
  return this;
   }
   ~this() {
  --count;
   }
}

This being a toy example, I wonder whether there are much more serious 
examples that would be impossible to implement within D.


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.


Why do you want to add class functionality to structs to enable "RAII" 
like features, when you could just use scope classes?


To refresh everyone's memory: a scope class is declared like "scope 
class Foo { ... }", and references to it can "only appear as a function 
local variable".


I for one don't really like the idea of having to distinguish between 
PODs and "other stuff" (like you had in C++) just again.


At the very least, the default constructor should always be available 
for structs. (If not, have fun figuring out what S[10] should do.)



Andrei


Re: this() not executing code on structs

2009-10-21 Thread Rainer Deyke
Andrei Alexandrescu wrote:
> Today, structs can't write their own this(). There aren't very solid
> reasons for that except that it makes language implementation more
> difficult.
> 
> I wonder how much of a problem that could be in practice. I realized
> today that the "Counted" example - a classic C++ primer example
> featuring a struct that counts its own instances - cannot be implemented
> in D.
> 
> In C++ the counted example looks like this:
> 
> struct Counted {
>static unsigned count;
>unsigned myCount;
>Counted() { myCount = count++; }
>Counted(const Counted& rhs) { myCount = count++; }
>Counted& operator=(const Counted& rhs) {
>   // no writing to myCount
>   return *this;
>}
>~Counted() {
>   --count;
>}
> }
> 
> In D there's no chance to write Counted because you can always create
> Counted objects without executing any code.
> 
> struct Counted {
>static uint count;
>uint myCount;
>this() { myCount = count++; }   // ERROR
>this(this) { myCount = count++; }
>ref Counted opAssign(Counted rhs) {
>   // no writing to myCount
>   return this;
>}
>~this() {
>   --count;
>}
> }
> 
> This being a toy example, I wonder whether there are much more serious
> examples that would be impossible to implement within D.

Any struct that uses dynamic memory allocation internally.

Any struct that registers its instances in some dort of global registry.

'ValueType!T', which turns reference type 'T' into a value type.

A 'ScopedLock' variant that uses a single global mutex.

RAII wrappers over global initialization/deinitialization functions.

A 'UniqueId' struct that initializes to a value that is guaranteed to be
distinct from the vale of any other 'UniqueId' used by the program.


-- 
Rainer Deyke - rain...@eldwood.com


Re: this() not executing code on structs

2009-10-21 Thread Leandro Lucarella
Bartosz Milewski, el 21 de octubre a las 16:33 me escribiste:
> Andrei Alexandrescu Wrote:
> 
> > this() { myCount = count++; }   // ERROR
> 
> It's worse than that. Try this:
> 
> struct foo {
>this(int dummy = 0) { writeln("Default constructor");}
> }
> 
> foo x = foo();
> 
> Nothing gets printed. If default constructors are disallowed, so should
> constructors with all parameters defaulted.

Fill bug reports in bugzilla, please!

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
Los jóvenes no son solo brazos que nos cargan... También se los puede
mandar a la guerra, que es su obligación.
-- Ricardo Vaporeso


Re: this() not executing code on structs

2009-10-21 Thread Bartosz Milewski
This means that no non-trivial invariant may be defined for a struct. In most 
cases it doesn't matter, but it might be a problem with the smart pointer 
family. 

For instance, refcounted may not assume that the shared refcount pointer has 
been allocated. Without this invariant all refcounted operations must have 
additional code that tests for null and does the right thing (which is not 
always obvious).


Re: this() not executing code on structs

2009-10-21 Thread Bartosz Milewski
Andrei Alexandrescu Wrote:

> this() { myCount = count++; }   // ERROR

It's worse than that. Try this:

struct foo {
   this(int dummy = 0) { writeln("Default constructor");}
}

foo x = foo();

Nothing gets printed. If default constructors are disallowed, so should 
constructors with all parameters defaulted.


Re: this() not executing code on structs

2009-10-21 Thread Denis Koroskin
On Wed, 21 Oct 2009 20:15:16 +0400, Andrei Alexandrescu  
 wrote:


Today, structs can't write their own this(). There aren't very solid  
reasons for that except that it makes language implementation more  
difficult.


I wonder how much of a problem that could be in practice. I realized  
today that the "Counted" example - a classic C++ primer example  
featuring a struct that counts its own instances - cannot be implemented  
in D.


In C++ the counted example looks like this:

struct Counted {
static unsigned count;
unsigned myCount;
Counted() { myCount = count++; }
Counted(const Counted& rhs) { myCount = count++; }
Counted& operator=(const Counted& rhs) {
   // no writing to myCount
   return *this;
}
~Counted() {
   --count;
}
}

In D there's no chance to write Counted because you can always create  
Counted objects without executing any code.


struct Counted {
static uint count;
uint myCount;
this() { myCount = count++; }   // ERROR
this(this) { myCount = count++; }
ref Counted opAssign(Counted rhs) {
   // no writing to myCount
   return this;
}
~this() {
   --count;
}
}

This being a toy example, I wonder whether there are much more serious  
examples that would be impossible to implement within D.



Andrei


I agree it's a very annoying limitation, but I believe there is a  
rationale behind it.


Imagine a class that aggregates a struct:

struct Foo { ... }

class Bar
{
   Foo foo;
   this() {}
   // ...
}

The class object construction is now consists of two steps:

1) memcpy the Bar.classinfo.init
2) call __ctor()

Unlike C++, there is no stage at which class members are being  
initialized, and it simplifies things quite a lot.


Think about the following: what happens if structs will be allowed default  
ctors? How to avoid double initialization?


You may end up with design very similar to C++ in this case (including an  
initialization list).


Some problems could be solved with an enforced explicit initialization of  
each member. That's the only way I see now that would avoid double  
initialization of a struct in presence of default and non-default ctors:


struct Scoped(T) // I like this name a lot more than InPlace, and  
especially InSitu

{
this(Args...)(Args args)
{
T obj = cast(T)data.ptr;
obj.__ctor(args);
}

ubyte[T.classinfo.init.length] data = T.classinfo.init; // I believe  
this should work at compile-time, since classinfo is immutable

}

class Foo
{
this() {}
this(int i) {}
}

class Bar
{
Scoped!(Foo) foo;
this()
{
 // foo is already constructed by now (default ctor is called)  
which is cool

 // but what if I need to initialize it with some other ctor?
 foo = Scoped!(Foo)(42); // double initialization
}

int doesntNeedToBeInitializedExplicitlyInACtor = 17;
}

Enforcing explicit initialization of each member (unless its value is set  
at the declaration, as in the example above) is gracefully solving this  
issue.


Also think about exception safety: what if an exception is thrown in a  
class ctor - should the dtors be invoked on initialized members or not? If  
yes, in what order? D doesn't enforce initialization order, so it's a bit  
tricky to determine what members are already initialized and need to be  
destroyed (with a dtor call) efficiently. C++ handles issues like this  
very well IMO. I believe D should also have a sound solution to this  
problem.


Re: this() not executing code on structs

2009-10-21 Thread dsimcha
== Quote from zoli (ga...@freemail.hu)'s article
> > > If the new "operator" for the class is redesigned to have multiply
allocation types
> > > (allocate on heap, allocate on stack, etc.?), there is no main drawback 
> > > of using
> > classes instead of structs for small objects( like vec2, vec3) as well.
> >
> > Yes there is.  How about the cost of storing vtbl and monitor?  Actually, 
> > just
> I keep forgetting those (4-8) extra bytes per instance :)
> And what about the final classes (with no ancestors)?

Even final classes w/ no explicit ancestors are implicitly subclasses of Object,
which defines virtual functions.  Therefore, *all* class instances must have a
vtbl pointer.


Re: this() not executing code on structs

2009-10-21 Thread zoli
> > If the new "operator" for the class is redesigned to have multiply 
> > allocation types
> > (allocate on heap, allocate on stack, etc.?), there is no main drawback of 
> > using
> classes instead of structs for small objects( like vec2, vec3) as well.
> 
> Yes there is.  How about the cost of storing vtbl and monitor?  Actually, just

I keep forgetting those (4-8) extra bytes per instance :)
And what about the final classes (with no ancestors)? Is there a vtbl for them 
since they cannot be derived and they have no virtual parent to inherit members 
from ? Or the Object with opHash and the other operators are virtual by nature 
in all classes ? (sorry, I don't know D that much)

Well, actually it seems as struct is a much better and clear solution. In that 
case I vote for this().



Re: this() not executing code on structs

2009-10-21 Thread dsimcha
== Quote from zoli (z...@freemail.hu)'s article
> Andrei Alexandrescu Wrote:
> > Today, structs can't write their own this(). There aren't very solid
> > reasons for that except that it makes language implementation more
> > difficult.
> >
> If the new "operator" for the class is redesigned to have multiply allocation 
> types
> (allocate on heap, allocate on stack, etc.?), there is no main drawback of 
> using
classes instead of structs for small objects( like vec2, vec3) as well.

Yes there is.  How about the cost of storing vtbl and monitor?  Actually, just
last night I was in a corner case where this mattered (as well as needing fine
control over allocation), so I ended up rolling my own polymorphism with 
structs.
 This is not a complaint about the design of D classes.  They do exactly what 
they
should do:  Handle the first 99% of use cases well and make people in obscure
corner cases roll their own from lower level primitives rather than succumbing 
to
the inner platform effect.  However, I think it would be ridiculous not to allow
simple syntactic sugar like non-polymorphic member functions on structs.

> I don't think if there's any reason to use struct with member functions from
that point, use class instead. And hence struct can be the good old plain data
structures again, to give some semantics to a block of memory.

Ok, simple example that's not a corner case:  How about storing one inline in an
array?


Re: this() not executing code on structs

2009-10-21 Thread zoli
Andrei Alexandrescu Wrote:

> Today, structs can't write their own this(). There aren't very solid 
> reasons for that except that it makes language implementation more 
> difficult.
> 

If the new "operator" for the class is redesigned to have multiply allocation 
types 
(allocate on heap, allocate on stack, etc.?), there is no main drawback of 
using classes instead of structs for small objects( like vec2, vec3) as well.
For function parameters, use the reference for in/out and, use a copy of the 
original for value parameters ( personally I hate codes where they change the 
input parameters when they are value types - for larger codes it's hard to 
track what's going on in the function, and whether it's the original or the 
modified value...)

I don't think if there's any reason to use struct with member functions from 
that point, use class instead. And hence struct can be the good old plain data 
structures again, to give some semantics to a block of memory.

But if the scoped allocation is gone, the struct will require much more 
construction powers, and will be used more (ex vec2, vec3, etc.)



this() not executing code on structs

2009-10-21 Thread Andrei Alexandrescu
Today, structs can't write their own this(). There aren't very solid 
reasons for that except that it makes language implementation more 
difficult.


I wonder how much of a problem that could be in practice. I realized 
today that the "Counted" example - a classic C++ primer example 
featuring a struct that counts its own instances - cannot be implemented 
in D.


In C++ the counted example looks like this:

struct Counted {
   static unsigned count;
   unsigned myCount;
   Counted() { myCount = count++; }
   Counted(const Counted& rhs) { myCount = count++; }
   Counted& operator=(const Counted& rhs) {
  // no writing to myCount
  return *this;
   }
   ~Counted() {
  --count;
   }
}

In D there's no chance to write Counted because you can always create 
Counted objects without executing any code.


struct Counted {
   static uint count;
   uint myCount;
   this() { myCount = count++; }   // ERROR
   this(this) { myCount = count++; }
   ref Counted opAssign(Counted rhs) {
  // no writing to myCount
  return this;
   }
   ~this() {
  --count;
   }
}

This being a toy example, I wonder whether there are much more serious 
examples that would be impossible to implement within D.



Andrei