www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - two suggestions: inner class new itself; error out NaN in debug mode

reply z gg.com writes:
1) inner class cannot new itself:

class A {
B newB() {return new B();}
class B {
B dup() {
B r;
r = newB();  // workaround
r = new B(); // error out: inner.d(7): no 'this' for nested class B
return r;
}
}
}

I understand the reason, and I know the workaround; but can we make it legal, by
just copying the 'this' pointer (should be called 'outer' really) from the
invoking object?  So writing innerClass.dup will be much easier.


2) generate runtime error-out in debug mode when a float value NaN is evaluated.

The propagation property of NaN as init value of float is great: whenever NaN is
used as an operand, the result is NaN.  The only problem is the programmer still
need to trace back the computation path to determine the locate of the bug.

I wonder if the compiler can help on this: in debug mode, whenever a NaN is
evaluated, generate a runtime error straight away.  So the programmer can
immediate identify the bug location.
Sep 13 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <dg74l5$1q57$1 digitaldaemon.com>, z gg.com says...
1) inner class cannot new itself:

class A {
B newB() {return new B();}
class B {
B dup() {
B r;
r = newB();  // workaround
r = new B(); // error out: inner.d(7): no 'this' for nested class B
return r;
}
}
}

I understand the reason, and I know the workaround; but can we make it legal, by
just copying the 'this' pointer (should be called 'outer' really) from the
invoking object?  So writing innerClass.dup will be much easier.

I don't understand. Why is a 'this' pointer to B required in order to construct a new instance of B? Or perhaps you left a 'this' out of the example? # class A { # class B { # B dup() { return new B(this); } # } # } In this case, that the code doesn't work seems entirely reasonable.
2) generate runtime error-out in debug mode when a float value NaN is evaluated.

Interesting idea. Is there any way to accomplish this in hardware? It would stink having the compiler insert evaluations after every floating-point operation. Sean
Sep 13 2005
parent reply z gg.com writes:
I understand the reason, and I know the workaround; but can we make it legal, by
just copying the 'this' pointer (should be called 'outer' really) from the
invoking object?  So writing innerClass.dup will be much easier.

I don't understand. Why is a 'this' pointer to B required in order to construct a new instance of B?

It's non-static inner-class, which contains a hidden 'this' pointer (should be called 'outer' really) to the enclosing object. Right now D's nested class have the same semantics as in Java, check "What's New for D 0.126", and also http://digitalmars.com/d/class.html#nested
Interesting idea.  Is there any way to accomplish this in hardware?  It would
stink having the compiler insert evaluations after every floating-point
operation.

It would be great if this can be caught by setting up some hardware traps. Even if this cannot be done by hardware, I think it will still help the programmer a lot by software simulation. Maybe another flag (e.g. "-NaN") can be introduced to let the programmer explicitly enable this behaviour. It may runs slow, but you will identify the bug straight away.
Sep 13 2005
next sibling parent Sean Kelly <sean f4.ca> writes:
In article <dg7d1c$23mi$1 digitaldaemon.com>, z gg.com says...
I understand the reason, and I know the workaround; but can we make it legal, by
just copying the 'this' pointer (should be called 'outer' really) from the
invoking object?  So writing innerClass.dup will be much easier.

I don't understand. Why is a 'this' pointer to B required in order to construct a new instance of B?

It's non-static inner-class, which contains a hidden 'this' pointer (should be called 'outer' really) to the enclosing object.

Understood. But shouldn't this only be an issue when access to B's internal data is necessary? Constructing a new instance of B is more akin to calling a function than to accessing data. Sean
Sep 13 2005
prev sibling parent reply James Dunne <james.jdunne gmail.com> writes:
z gg.com wrote:
I understand the reason, and I know the workaround; but can we make it legal, by
just copying the 'this' pointer (should be called 'outer' really) from the
invoking object?  So writing innerClass.dup will be much easier.

I don't understand. Why is a 'this' pointer to B required in order to construct a new instance of B?

It's non-static inner-class, which contains a hidden 'this' pointer (should be called 'outer' really) to the enclosing object. Right now D's nested class have the same semantics as in Java, check "What's New for D 0.126", and also http://digitalmars.com/d/class.html#nested
Interesting idea.  Is there any way to accomplish this in hardware?  It would
stink having the compiler insert evaluations after every floating-point
operation.

It would be great if this can be caught by setting up some hardware traps. Even if this cannot be done by hardware, I think it will still help the programmer a lot by software simulation. Maybe another flag (e.g. "-NaN") can be introduced to let the programmer explicitly enable this behaviour. It may runs slow, but you will identify the bug straight away.

The hardware does trap such cases. It's called a signalling (or noisy) NaN. Most NaNs, however, are quiet NaNs. D's float.nan is a quiet NaN, which does not signal when evaluated. I'm not an expert on the IEEE floating point spec by any means. I'm also not quite sure how the signal from the FPU gets to the CPU to the application... I believe on Linux it is achieved with a SIGFPE signal sent to the app, which must trap it and handle it accordingly. I'm not sure how easy or difficult it would be to achieve the same effect using exceptions.
Sep 13 2005
parent reply Sean Kelly <sean f4.ca> writes:
In article <dg80p3$2m8s$1 digitaldaemon.com>, James Dunne says...
The hardware does trap such cases.  It's called a signalling (or noisy) 
NaN.  Most NaNs, however, are quiet NaNs.  D's float.nan is a quiet NaN, 
which does not signal when evaluated.  I'm not an expert on the IEEE 
floating point spec by any means.

I'm also not quite sure how the signal from the FPU gets to the CPU to 
the application... I believe on Linux it is achieved with a SIGFPE 
signal sent to the app, which must trap it and handle it accordingly. 
I'm not sure how easy or difficult it would be to achieve the same 
effect using exceptions.

SIGFPE is a standard C signal so it should work on Windows as well. Now that I think about it, std.c.fenv has functions to specify floating-point behavior, though I've never actually used them. There's a copy of a D header here: http://svn.dsource.org/projects/ares/trunk/src/ares/std/c/fenv.d Sean
Sep 13 2005
parent Don Clugston <dac nospam.com.au> writes:
Sean Kelly wrote:
 In article <dg80p3$2m8s$1 digitaldaemon.com>, James Dunne says...
 
The hardware does trap such cases.  It's called a signalling (or noisy) 
NaN.  Most NaNs, however, are quiet NaNs.  D's float.nan is a quiet NaN, 
which does not signal when evaluated.  I'm not an expert on the IEEE 
floating point spec by any means.

I'm also not quite sure how the signal from the FPU gets to the CPU to 
the application... I believe on Linux it is achieved with a SIGFPE 
signal sent to the app, which must trap it and handle it accordingly. 
I'm not sure how easy or difficult it would be to achieve the same 
effect using exceptions.

SIGFPE is a standard C signal so it should work on Windows as well. Now that I think about it, std.c.fenv has functions to specify floating-point behavior, though I've never actually used them. There's a copy of a D header here: http://svn.dsource.org/projects/ares/trunk/src/ares/std/c/fenv.d Sean

Even quiet NANs will trigger an exception when they are used in <,==,< comparisons, and they also trigger exceptions if they arise during a calculation. If D were to provide an option to make uninitialized variables be SNANs, you'd have immediate, 100% detection, but even with QNANs you'll catch them easily. Would work just as well in release mode as in debug mode. Heck, in debug mode you could use the bits inside the SNAN to be an index into a table of all variables in the program, so the error message could be: floating point variable classY.func2().somevar was used before being initialised.
Sep 14 2005
prev sibling parent reply =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= <thomas-dloop kuehne.cn> writes:
idea:
"() ? (A) : (B) = rvalue;" is legal, if A and B are legal lvalues.

sample code:
	int a = 3;
	int b = 7;
	
	((a > b) ? (a) : (b)) = a*b + (b << 1) - (a >> 1) * (a & b);

reason:
Limit code duplication and use of temporary variables in order to reduce
the bug-proneness of complex evaluations.


As far as I am aware there are no side effects for existing code.
Sep 13 2005
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 14 Sep 2005 01:07:00 +0200, Thomas Khne wrote:

 idea:
 "() ? (A) : (B) = rvalue;" is legal, if A and B are legal lvalues.
 
 sample code:
 	int a = 3;
 	int b = 7;
 	
 	((a > b) ? (a) : (b)) = a*b + (b << 1) - (a >> 1) * (a & b);
 
 reason:
 Limit code duplication and use of temporary variables in order to reduce
 the bug-proneness of complex evaluations.
 
 As far as I am aware there are no side effects for existing code.

I haven't got any idea about what you are trying to do. It is not obvious to me at all. Can you rewrite your example using the long method so I can see the logic flow etc.... -- Derek (skype: derek.j.parnell) Melbourne, Australia 14/09/2005 10:03:04 AM
Sep 13 2005
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Derek Parnell" <derek psych.ward> wrote in message 
news:12zsfnc0t7lua.1wbg7upo8ws6s$.dlg 40tude.net...
 I haven't got any idea about what you are trying to do. It is not obvious
 to me at all. Can you rewrite your example using the long method so I can
 see the logic flow etc....

This: (a < b) ? (a) : (b) = 15; Would be the same as: if(a < b) a = 15; else b = 15; So it's using the ?: to select the destination of the assignment instead of the source.
Sep 13 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 13 Sep 2005 20:08:02 -0400, Jarrett Billingsley wrote:

 "Derek Parnell" <derek psych.ward> wrote in message 
 news:12zsfnc0t7lua.1wbg7upo8ws6s$.dlg 40tude.net...
 I haven't got any idea about what you are trying to do. It is not obvious
 to me at all. Can you rewrite your example using the long method so I can
 see the logic flow etc....

This: (a < b) ? (a) : (b) = 15; Would be the same as: if(a < b) a = 15; else b = 15; So it's using the ?: to select the destination of the assignment instead of the source.

Okay, so the general form would be ... (BooleanExpression) ? (Identifier1) : (Identifier2) = Expression; which would be equivalent to ... { // Start a scoping block. Typeof(Expression) Temp = Expression; if (BooleanExpression == true) Identifier1 = Temp; else Identifier2 = Temp; } -- Derek (skype: derek.j.parnell) Melbourne, Australia 14/09/2005 10:11:09 AM
Sep 13 2005
next sibling parent reply Thomas Kühne <thomas-dloop kuehne.cn> writes:
In article <1otsutm9b7edw$.p5znknydurvg.dlg 40tude.net>, Derek Parnell says...
On Tue, 13 Sep 2005 20:08:02 -0400, Jarrett Billingsley wrote:

 "Derek Parnell" <derek psych.ward> wrote in message 
 news:12zsfnc0t7lua.1wbg7upo8ws6s$.dlg 40tude.net...
 I haven't got any idea about what you are trying to do. It is not obvious
 to me at all. Can you rewrite your example using the long method so I can
 see the logic flow etc....

This: (a < b) ? (a) : (b) = 15; Would be the same as: if(a < b) a = 15; else b = 15; So it's using the ?: to select the destination of the assignment instead of the source.

Okay, so the general form would be ... (BooleanExpression) ? (Identifier1) : (Identifier2) = Expression; which would be equivalent to ... { // Start a scoping block. Typeof(Expression) Temp = Expression; if (BooleanExpression == true) Identifier1 = Temp; else Identifier2 = Temp; }

Yes. Now consider to write 5 successive scopes and compare it with the ?: notation. Thomas
Sep 14 2005
parent Derek Parnell <derek psych.ward> writes:
On Wed, 14 Sep 2005 14:29:57 +0000 (UTC), Thomas Kühne wrote:

 In article <1otsutm9b7edw$.p5znknydurvg.dlg 40tude.net>, Derek Parnell says...
On Tue, 13 Sep 2005 20:08:02 -0400, Jarrett Billingsley wrote:

 "Derek Parnell" <derek psych.ward> wrote in message 
 news:12zsfnc0t7lua.1wbg7upo8ws6s$.dlg 40tude.net...
 I haven't got any idea about what you are trying to do. It is not obvious
 to me at all. Can you rewrite your example using the long method so I can
 see the logic flow etc....

This: (a < b) ? (a) : (b) = 15; Would be the same as: if(a < b) a = 15; else b = 15; So it's using the ?: to select the destination of the assignment instead of the source.

Okay, so the general form would be ... (BooleanExpression) ? (Identifier1) : (Identifier2) = Expression; which would be equivalent to ... { // Start a scoping block. Typeof(Expression) Temp = Expression; if (BooleanExpression == true) Identifier1 = Temp; else Identifier2 = Temp; }

Yes. Now consider to write 5 successive scopes and compare it with the ?: notation.

I was not making *any* judgment on the idea. I was only trying to gain understanding. -- Derek Parnell Melbourne, Australia 15/09/2005 2:02:47 AM
Sep 14 2005
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Derek Parnell wrote:

[...]
 Okay, so the general form would be ...

      Typeof(Expression) Temp = Expression;

No. Because, D has at least that discontinuity with overloaded functions. -manfred
Sep 14 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 14 Sep 2005 14:57:14 +0000 (UTC), Manfred Nowak wrote:

 Derek Parnell wrote:
 
 [...]
 Okay, so the general form would be ...

      Typeof(Expression) Temp = Expression;

No. Because, D has at least that discontinuity with overloaded functions.

What the hell does that mean? I did say "equivalent" right? All I meant was that it would AS IF one created a temporary variable that had the same type as the expression and assigned the expression to that temporary. What has that got to do with overloaded functions? -- Derek Parnell Melbourne, Australia 15/09/2005 2:04:43 AM
Sep 14 2005
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Derek Parnell wrote:

[...]
 Okay, so the general form would be ...

      Typeof(Expression) Temp = Expression;



 I did say "equivalent" right? All I meant was that it would AS
 IF one created a temporary variable that had the same type as
 the expression and assigned the expression to that temporary.

Then I do not understand what you might mean with "as if".
 What has that got to do with overloaded functions? 

If the RHS is the adress of an overloaded function `&f' then currently `typeof( &f)' has the type of the first definition of `f', which might be neither the type of the `?'-branch nor the type of the `:'-branch of the `?:'-operator. Therefore the general form is to take `typeof( LHS)' instead of `typeof( RHS)'. -manfred
Sep 14 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 15 Sep 2005 05:32:29 +0000 (UTC), Manfred Nowak wrote:

 Derek Parnell wrote:
 
 [...]
 Okay, so the general form would be ...

      Typeof(Expression) Temp = Expression;



 I did say "equivalent" right? All I meant was that it would AS
 IF one created a temporary variable that had the same type as
 the expression and assigned the expression to that temporary.

Then I do not understand what you might mean with "as if".
 What has that got to do with overloaded functions? 

If the RHS is the adress of an overloaded function `&f' then currently `typeof( &f)' has the type of the first definition of `f', which might be neither the type of the `?'-branch nor the type of the `:'-branch of the `?:'-operator. Therefore the general form is to take `typeof( LHS)' instead of `typeof( RHS)'.

Okay I get the confusion now. When I said "Typeof(Expression)" I did not actually mean that we would use the D typeof() function. It was just my attempt at using shorthand to say 'whatever the type of the Expression is, we would use the exact same type for the temporary variable'. Here it is in code, which should remove some confusion... <code> real foo(char a, short b) { return 10.0L; } real foo(int a, long b) { return 20.0L; } void main() { typedef real function(int, long) r_foo_i_l; r_foo_i_l d; r_foo_i_l e; int a = 1; int b = 3; // Implementing ((a<b) ? (d) : (e) = &foo); { r_foo_i_l temp = &foo; if (a<b) d = temp; else e = temp; } assert( d !is null ); assert( d(1, 2L) == 20.0L ); } </code> -- Derek (skype: derek.j.parnell) Melbourne, Australia 15/09/2005 3:39:40 PM
Sep 14 2005
parent Manfred Nowak <svv1999 hotmail.com> writes:
Derek Parnell wrote:

[...]
 When I said "Typeof(Expression)" I
 did not actually mean that we would use the D typeof() function.

I understand now. Thank you. -manfred
Sep 15 2005
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Thomas Khne wrote:
 idea:
 "() ? (A) : (B) = rvalue;" is legal, if A and B are legal lvalues.
 
 sample code:
 	int a = 3;
 	int b = 7;
 	
 	((a > b) ? (a) : (b)) = a*b + (b << 1) - (a >> 1) * (a & b);
 
 reason:
 Limit code duplication and use of temporary variables in order to reduce
 the bug-proneness of complex evaluations.

You can do *((a > b) ? (&a) : (&b)) = a*b + (b << 1) - (a >> 1) * (a & b); Stewart. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d- s:- C++ a->--- UB P+ L E W++ N+++ o K- w++ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y ------END GEEK CODE BLOCK------ My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Sep 14 2005
parent reply Georg Wrede <georg.wrede nospam.org> writes:
 reason:
 Limit code duplication and use of temporary variables in order to reduce
 the bug-proneness of complex evaluations.

You can do *((a > b) ? (&a) : (&b)) = a*b + (b << 1) - (a >> 1) * (a & b);

To Stewart: Cool! To OP: This is all very nice. But honestly, I don't see how this could possibly alleviate "bug-proneness". Number one rule of avoiding bugs is: write clear code. Number two is: Keep It Simple, Stupid. Number three: But not any simpler than that. Considering all this, I can't recommend the above style to anybody. Ideally, code should be written so that what it does is immediately visible, at first sight. One should also remember that many local temporary variables never get compiled into code. They are there only to make the programmer's intentions explicit -- and the compiler knows that. At the same time, the compiled code may contain temporary variables not invented by the programmer (mostly in registers and the stack). For example, in the above code, the variable "a" is evaluated several times: chances are the compiled code only evaluates it once, and uses this (locally temporarily stored) value instead. It is usual to find "optimisations" in program code, especially written by folks in "the C mindset". In the old times, when the compilers were simpler, the written code pretty much got compiled "as is". And that was okay, since C was essentially a "machine independent high level assembly language". Today we are going away from that -- even with C compilers. (Which means "what you write is what you get" is becoming history.) Code clarity and simplicity are much more valuable than stealing a few clock cycles or bytes, and smart compilers do that better than the programmer anyway.
Sep 15 2005
parent Manfred Nowak <svv1999 hotmail.com> writes:
Georg Wrede wrote:

[...]
 Considering all this, I can't recommend the above style to
 anybody.

I agree with you and the arguments you are giving. But then: how to justify the existence of the asm-statement? -manfred
Sep 15 2005