www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - void main returning int - why compiles?

reply Daren Scot Wilson <darenw darenscotwilson.com> writes:
I'm wondering why the following compiles.  I'm using LDC.  Perhaps it's a 
bug, or there's some subtlety about D.   I have deliberately, out of a 
combination of idleness and desire for mischief, have  main()  declared as 
returning void, but with a return statement giving an integer.

If the first "half evil" return statement is uncommented, the corruption is 
noticed by the compiler and it writes an error.

As shown, the "total evil" return statement gets a value from subroutine 
foo().  Being somehow so perfect in its evilness, this passes through the 
compiler without a burp.  The resulting executable returns zero (or my bash 
shell defaults to zero when receiving nothing.)

When I get religion and like good boy declare main() as returing int, it 
compiles in perfectly.  When executed, the program returns either number 
according to which return statement is uncommented.




int foo(int x)   {
	return x;
}

void main()   {
	// return 333;   /* half evil */
	return foo(666);  /* total evil */
}
Dec 31 2010
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday 31 December 2010 23:37:17 Daren Scot Wilson wrote:
 I'm wondering why the following compiles.  I'm using LDC.  Perhaps it's a
 bug, or there's some subtlety about D.   I have deliberately, out of a
 combination of idleness and desire for mischief, have  main()  declared as
 returning void, but with a return statement giving an integer.
 
 If the first "half evil" return statement is uncommented, the corruption is
 noticed by the compiler and it writes an error.
 
 As shown, the "total evil" return statement gets a value from subroutine
 foo().  Being somehow so perfect in its evilness, this passes through the
 compiler without a burp.  The resulting executable returns zero (or my bash
 shell defaults to zero when receiving nothing.)
 
 When I get religion and like good boy declare main() as returing int, it
 compiles in perfectly.  When executed, the program returns either number
 according to which return statement is uncommented.
 
 
 
 
 int foo(int x)   {
 	return x;
 }
 
 void main()   {
 	// return 333;   /* half evil */
 	return foo(666);  /* total evil */
 }

I don't know what LDC's current state is in terms of being up-to-date with the latest D. However, it is _not_ legal D to return a value from a void function. So, this is definitely a bug in LDC. - Jonathan M Davis
Jan 01 2011
parent Matthias Pleh <matthias net.at> writes:
On 2011-01-01 09:32, Jonathan M Davis wrote:
 On Friday 31 December 2010 23:37:17 Daren Scot Wilson wrote:
 I'm wondering why the following compiles.  I'm using LDC.  Perhaps it's a
 bug, or there's some subtlety about D.   I have deliberately, out of a
 combination of idleness and desire for mischief, have  main()  declared as
 returning void, but with a return statement giving an integer.

 If the first "half evil" return statement is uncommented, the corruption is
 noticed by the compiler and it writes an error.

 As shown, the "total evil" return statement gets a value from subroutine
 foo().  Being somehow so perfect in its evilness, this passes through the
 compiler without a burp.  The resulting executable returns zero (or my bash
 shell defaults to zero when receiving nothing.)

 When I get religion and like good boy declare main() as returing int, it
 compiles in perfectly.  When executed, the program returns either number
 according to which return statement is uncommented.




 int foo(int x)   {
 	return x;
 }

 void main()   {
 	// return 333;   /* half evil */
 	return foo(666);  /* total evil */
 }

I don't know what LDC's current state is in terms of being up-to-date with the latest D. However, it is _not_ legal D to return a value from a void function. So, this is definitely a bug in LDC. - Jonathan M Davis

It's the same with dmd v2.051 on GNU/Linux
Jan 01 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Daren Scot Wilson:

 I'm wondering why the following compiles.

It's yet another small compiler bug, fit for Bugzilla. If you want I may add a bug report to Bugzilla that shows this as "accepts-invalid": int foo(int x) { return x; } void main() { return foo(1); } Bye, bearophile
Jan 01 2011
parent bearophile <bearophileHUGS lycos.com> writes:
 If you want I may add a bug report to Bugzilla that shows this as
"accepts-invalid":
 
 int foo(int x) {
     return x;
 }
 void main() {
     return foo(1);
 }

Simpler: int foo() { return 1; } void main() { return foo(); } But maybe this bug report is already present. Bye, bearophile
Jan 01 2011
prev sibling next sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Daren Scot Wilson <darenw darenscotwilson.com> wrote:

 As shown, the "total evil" return statement gets a value from subroutine  
 foo().  Being somehow so perfect in its evilness, this passes through  
 the compiler without a burp.  The resulting executable returns zero (or  
 my bash shell defaults to zero when receiving nothing.)

This is by design, the feature is made for generic functions. Consider: ReturnType!Fn wrap( alias Fn )( ParameterTypeTuple!Fn args ) { return Fn( args ); } One would expect that to work. If void functions did not allow returning the results of functions, the above function would have had to be changed to something like this: ReturnType!Fn wrap( alias Fn )( ParameterTypeTuple!Fn args ) { static if ( is( typeof( return ) == void ) ) { Fn( args ); } else { return Fn( args ); } } Clearly this code is worse than the above. -- Simen
Jan 01 2011
next sibling parent David Nadlinger <see klickverbot.at> writes:
On 1/1/11 10:08 PM, Simen kjaeraas wrote:
 This is by design, the feature is made for generic functions. Consider:

 ReturnType!Fn wrap( alias Fn )( ParameterTypeTuple!Fn args ) {
 return Fn( args );
 }

I am not sure if this simple argument is valid – if Fn was of return type void, you would, type-wise, have »return void;« in a function returning void, which is clearly different from having »return someInt;« in a function returning void… David
Jan 01 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Simen kjaeraas:

 One would expect that to work. If void functions did not allow returning
 the results of functions, the above function would have had to be changed
 to something like this:
 
 ReturnType!Fn wrap( alias Fn )( ParameterTypeTuple!Fn args ) {
      static if ( is( typeof( return ) == void ) ) {
          Fn( args );
      } else {
          return Fn( args );
      }
 }

I think you are talking about the foo() case. But the OP is talking about the bar() case, that I think it's a compiler bug: void foo() {} int bar() { return 1; } void main() { //return 0; // error //return foo(); // OK, foo returns void return bar(); // error, bar returns int } Bye, bearophile
Jan 01 2011
parent bearophile <bearophileHUGS lycos.com> writes:
http://d.puremagic.com/issues/show_bug.cgi?id=5399
Jan 01 2011
prev sibling parent reply "Manfred_Nowak" <svv1999 hotmail.com> writes:
Daren Scot Wilson wrote:

 As shown, the "total evil" return statement gets a value from subroutine 
 foo().

From the docs: | Expression is allowed even if the function specifies a void return | type. The Expression will be evaluated, but nothing will be returned. | If the Expression has no side effects, and the return type is void, | then it is illegal. http://www.digitalmars.com/d/2.0/statement.html (cited 01/01/11) _and_ foo() is not marked to have no side effects. -manfred
Jan 01 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Manfred Nowak:

 _and_ foo() is not marked to have no side effects.

You are right, thank you for the quotation. So I have updated this, because it's not a bug: http://d.puremagic.com/issues/show_bug.cgi?id=5399 I'm sure there's a rationale behind that special case in the D specs. Is someone able to explain? It looks like an unsafe corner case. Bye, bearophile
Jan 01 2011
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Manfred Nowak:

 | Expression is allowed even if the function specifies a void return
 | type. The Expression will be evaluated, but nothing will be returned.
 | If the Expression has no side effects, and the return type is void,
 | then it is illegal.  
   http://www.digitalmars.com/d/2.0/statement.html (cited 01/01/11)
 
 _and_ foo() is not marked to have no side effects.

Walter has closer my issue with this comment: http://d.puremagic.com/issues/show_bug.cgi?id=5399
It is not a dangerous corner case, it is a deliberate design choice. It is
meant to facilitate writing generic code so that the same code can be generated
for void and non-void return values.<

But I don't understand still, I don't buy Walter's explanation still. I write my comments in D.learn because I don't want to fill Bugzilla with too much discussions. This compiles: int bar() { return 0; } void main() { return bar(); } While this doesn't, and this semantic difference looks like corner case of the general D rule (the good D rule seems that if it's a void function you can't return a value different from void, and if it's not a void function then you must return a value of the right type): int bar() { return 0; } void main() { auto temp = bar(); return temp; } If I want to create a void function foo(), and I want to generate code inside it, can't I just avoid to add a "return" statement in the generated code, instead of adding return and then letting the compiler silently ignore an eventually present return value? Bye, bearophile
Jan 02 2011