December 12, 2008
Zoran Isailovski wrote:
> I'm an experienced C#, Java and Python programmer, and have employed closures (and C# delegates) upon numerous occasions. While experimenting with D closures and delegates, I was stroke by a phenomenon I cannot explain. Here's the code:
> 
> module closures01;
> 
> import std.stdio;
> 
> alias int delegate(int arg) Handler;
> 
> Handler incBy(int n)
> {
> 	return delegate(int arg){ return arg + n; };
> }
> 
> Handler mulBy(int n)
> {
> 	return delegate(int arg){ return arg * n; };
> }
> 
> void test1()
> {
> 	writefln("\ntest1:\n----------------------------------------");
> 	int x = 10, y;
> 	y = mulBy(3)(x); writefln("%d * 3 -> %d", x, y);
> 	y = mulBy(4)(x); writefln("%d * 4 -> %d", x, y);
> 	y = incBy(2)(x); writefln("%d + 2 -> %d", x, y);
> }
> 
> void test2()
> {
> 	writefln("\ntest2:\n----------------------------------------");
> 	int x = 10, y;
> 	Handler times3 = mulBy(3);
> 	Handler times4 = mulBy(4);
> 	Handler plus2 = incBy(2);
> 	y = times3(x); writefln("%d * 3 -> %d", x, y);
> 	y = times4(x); writefln("%d * 4 -> %d", x, y);
> 	y = plus2(x); writefln("%d + 2 -> %d", x, y);
> }
> 
> public void run()
> {
> 	test1();
> 	test2();
> }
> 
> /* **************************************** *
>  * Compiled with: Digital Mars D Compiler v1.030
>  *
>  * (Unexplainable) program output:
> 
> test1:
> ----------------------------------------
> 10 * 3 -> 30
> 10 * 4 -> 40
> 10 + 2 -> 12
> 
> test2:
> ----------------------------------------
> 10 * 3 -> 20
> 10 * 4 -> 42846880
> 10 + 2 -> 4284698
> 
> * **************************************** */
> 
> What goes wrong???

	In both cases, when your delegate gets called, the corresponding
stack frame is invalid. However, in test1, the stack data is still
intact when the delegate is called, whereas in test2 it has been
overwritten by the calls to mulBy(4), incBy(2) and writefln.

		Jerome
- --
mailto:jeberger@free.fr
http://jeberger.free.fr
Jabber: jeberger@jabber.fr
December 12, 2008
Reply to Zoran,

> Thx, Denis, but I'm still confused. The stack thing was also my first
> thought. But when I tried to actually explain the dynamics that way, I
> came to the conclusion that then, test1() shouldn't have worked
> either.
> 


what might be happening is that test1 is not using up enough stack space to overwrite the arguments.


December 12, 2008
Reply to Zoran,

> I don't think it is restrictive if the compiler prevented a situation
> that would otherwise lead to a run-time error anyway, or worse, weird
> and confusing run-time behavior. In my case, if the compiler couldn't
> SAFELY handle a reference to the argument n outside the enclosing
> function, then, IMO, RETURNING it (but not otherwise using it) should
> be flagged a compilation error. Admittedly, detecting this is a bit
> more involved for the compiler, but not at all restrictive for the
> user.
> 

D2.0 handles it all correctly. D1.0 follows the "hear is a gun, there is your foot" mentality with regards to this. In general D is *not* a safe language and that is by intent.


December 12, 2008
Fri, 12 Dec 2008 15:24:39 -0500, Zoran Isailovski wrote:

> Denis Koroskin Wrote:
> 
>>>> On Fri, 12 Dec 2008 19:32:03 +0300, Zoran Isailovski <dmd.zoc@spamgourmet.com> wrote:
>>>>
>>>> > I'm an experienced C#, Java and Python programmer, and have employed closures (and C# delegates) upon numerous occasions. While
>>>> experimenting
>>>> > with D closures and delegates, I was stroke by a phenomenon I cannot explain. Here's the code:
>> As a rule of thumb, you shoudn't don't return local delegate from a function in D1, but you may safely pass them down the call stack.
> 
> I don't think it is restrictive if the compiler prevented a situation that would otherwise lead to a run-time error anyway, or worse, weird and confusing run-time behavior. In my case, if the compiler couldn't SAFELY handle a reference to the argument n outside the enclosing function, then, IMO, RETURNING it (but not otherwise using it) should be flagged a compilation error. Admittedly, detecting this is a bit more involved for the compiler, but not at all restrictive for the user.

There are situations where proving that n escapes the function is hard and requires extensive flow analysis.  It may be impossible to prove when one module of a large program is compiled separately.  And it may be impossible to prove for library code where user code is unknown by definition.  Therefore the decision is left to the programmer.  This is indeed unsafe, and D2 tries to solve this by introducing full, heap-allocated closures.  This in turn brings performance problems in situations where stack closures would be sufficient.  Now significant effort is made towards allowing stack closures in D2 where it would be safe.

That said, the full closure feature won't make its way into D1.  D1 closures will stay as they are.
December 13, 2008
BCS Wrote:

> Reply to Zoran,
> 
> > I don't think it is restrictive if the compiler prevented a situation that would otherwise lead to a run-time error anyway, or worse, weird and confusing run-time behavior. In my case, if the compiler couldn't SAFELY handle a reference to the argument n outside the enclosing function, then, IMO, RETURNING it (but not otherwise using it) should be flagged a compilation error. Admittedly, detecting this is a bit more involved for the compiler, but not at all restrictive for the user.
> > 
> 
> D2.0 handles it all correctly. D1.0 follows the "hear is a gun, there is your foot" mentality with regards to this. In general D is *not* a safe language and that is by intent.
> 
> 
Oh... I've got the wrong impression from the papers about D. (But then, why would someone design an *unsafe* language *by intention*??? For that, we've got C and C++, don't we?)

Anyway, I've been looking for a modern and *safe* language, but without the overkill of a Java VM or .NET runtime. My hope was with D, but you seem to be convincing me otherwise...

Does the "D is unsafe by intention" relate to D2.0, too?
December 13, 2008
Zoran Isailovski <dmd.zoc@spamgourmet.com> wrote:

> Oh... I've got the wrong impression from the papers about D. (But then, why would someone design an *unsafe* language *by intention*??? For that, we've got C and C++, don't we?)

Because we want D  to be the new C/C++? :p

D is unsafe in that it lets you shoot yourself in the foot with a limited
amount of hassle. It has pointer arithmetics, manual memory management if
you want that, etc. It is however not unsafe in the same way as C/C++
(here's a boot with a gun attached to it, to use it safely, remove the
gun)

Also, there is SafeD, which is not yet implemented, but it's coming.
(http://www.digitalmars.com/d/2.0/safed.html)

> Anyway, I've been looking for a modern and *safe* language, but without the overkill of a Java VM or .NET runtime. My hope was with D, but you seem to be convincing me otherwise...

It may or may not be. As mentioned above, it's still possible to ferk up
with D, but it's a lot harder than with C or C++.

> Does the "D is unsafe by intention" relate to D2.0, too?

D2 still has pointers and optional manual memory management, so yes.
D2 has fixed a lot of the unsafe things from D1, so no.

Clear enough? :p

-- 
Simen
December 13, 2008
Sergey Gromov Wrote:

> Fri, 12 Dec 2008 15:24:39 -0500, Zoran Isailovski wrote:
> 
> > Denis Koroskin Wrote:
> > 
> >>>> On Fri, 12 Dec 2008 19:32:03 +0300, Zoran Isailovski <dmd.zoc@spamgourmet.com> wrote:
> >>>>
> >>>> > I'm an experienced C#, Java and Python programmer, and have employed closures (and C# delegates) upon numerous occasions. While
> >>>> experimenting
> >>>> > with D closures and delegates, I was stroke by a phenomenon I cannot explain. Here's the code:
> >> As a rule of thumb, you shoudn't don't return local delegate from a function in D1, but you may safely pass them down the call stack.
> > 
> > I don't think it is restrictive if the compiler prevented a situation that would otherwise lead to a run-time error anyway, or worse, weird and confusing run-time behavior. In my case, if the compiler couldn't SAFELY handle a reference to the argument n outside the enclosing function, then, IMO, RETURNING it (but not otherwise using it) should be flagged a compilation error. Admittedly, detecting this is a bit more involved for the compiler, but not at all restrictive for the user.
> 
> There are situations where proving that n escapes the function is hard and requires extensive flow analysis.  It may be impossible to prove when one module of a large program is compiled separately.  And it may be impossible to prove for library code where user code is unknown by definition. Therefore the decision is left to the programmer.  This is indeed unsafe, and D2 tries to solve this by introducing full, heap-allocated closures.  This in turn brings performance problems in situations where stack closures would be sufficient.  Now significant effort is made towards allowing stack closures in D2 where it would be safe.

Sergey,  thanks for taking the time to respond.

I think you are talking about allowing all usages that may be potentially safe. I was talking about disallowing all usages  that may be potentially unsafe. (This was indeed one of the main differences in "philosophy" between languages in the C family, and languages in the ALGOL family. I truly hope D will be coming closer to the latter.)

Anyway, following the latter pattern, you don't need global analysis. You can determine if n is on the stack (it is - it's an argument), you can determine if it's referenced from within the closure (it is), and you can determine if the closure is being returned (it is). The compiler should IMO then generate an error (or warning) about the return statement, perhaps stating something like "cannot return a delegate that refers to variables in local scope", or something like that.

> That said, the full closure feature won't make its way into D1.  D1 closures will stay as they are.

I see. And I'd love to switch to D2, but I just can't get DFL working with it (on Win32).
December 13, 2008
Zoran Isailovski wrote:
> Oh... I've got the wrong impression from the papers about D. (But then, why would someone design an *unsafe* language *by intention*??? For that, we've got C and C++, don't we?)
> 
> Anyway, I've been looking for a modern and *safe* language, but without the overkill of a Java VM or .NET runtime. My hope was with D, but you seem to be convincing me otherwise...
> 
> Does the "D is unsafe by intention" relate to D2.0, too?

D tries to make it easy to do the safe thing. It's a systems language, so it has to allow you to do unsafe things without too much trouble -- but usually with some not-too-pretty syntax to indicate that you're doing something unsafe.

In this case, D1 fails. D2 works, though at the cost of additional, often unnecessary, heap allocation. Since D is a systems language, this is not good and is due to change soon. At least, I think Walter said he plans to implement scope delegates in D2.
December 13, 2008
On Sat, Dec 13, 2008 at 9:09 AM, Christopher Wright <dhasenan@gmail.com> wrote:
> D tries to make it easy to do the safe thing. It's a systems language, so it has to allow you to do unsafe things without too much trouble -- but usually with some not-too-pretty syntax to indicate that you're doing something unsafe.
>
> In this case, D1 fails. D2 works, though at the cost of additional, often unnecessary, heap allocation. Since D is a systems language, this is not good and is due to change soon. At least, I think Walter said he plans to implement scope delegates in D2.

He already has, as of the last update.
December 13, 2008
Simen Kjaeraas Wrote:

> Zoran Isailovski <dmd.zoc@spamgourmet.com> wrote:
> 
> > Oh... I've got the wrong impression from the papers about D. (But then, why would someone design an *unsafe* language *by intention*??? For that, we've got C and C++, don't we?)
> 
> Because we want D  to be the new C/C++? :p
> 
> D is unsafe in that it lets you shoot yourself in the foot with a limited amount of hassle. It has pointer arithmetics, manual memory management if you want that, etc. It is however not unsafe in the same way as C/C++ (here's a boot with a gun attached to it, to use it safely, remove the gun)
> 
> Also, there is SafeD, which is not yet implemented, but it's coming. (http://www.digitalmars.com/d/2.0/safed.html)
> 
> > Anyway, I've been looking for a modern and *safe* language, but without the overkill of a Java VM or .NET runtime. My hope was with D, but you seem to be convincing me otherwise...
> 
> It may or may not be. As mentioned above, it's still possible to ferk up with D, but it's a lot harder than with C or C++.
> 
> > Does the "D is unsafe by intention" relate to D2.0, too?
> 
> D2 still has pointers and optional manual memory management, so yes. D2 has fixed a lot of the unsafe things from D1, so no.
> 
> Clear enough? :p
> 
> -- 
> Simen

Yepp! Thanks! :))