www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proposal: "void f() { return 7; }" should be illegal

reply Don <nospam nospam.com> writes:
In the docs for "return statement" in statement.html it says:
---
ReturnStatement:
     return;
     return Expression ;

Expression is allowed even if the function specifies a void return type. 
The Expression will be evaluated, but nothing will be returned.

----
This makes sense for things we definitely want to allow, such as:
void foo() { return bar(); }
where bar() is another void function. But as currently implemented, it 
also allows bug-prone code. Here's an example from std.utf in Phobos2:

// BUG: should return size_t, not void!
void encode(wchar[2] buf, dchar c){
    if (c <= 0xFFFF)
         return 1;
     return 2;
}

I think that instead, inside a void function, return expression; should 
be the same as: { expression; return; }, ie, like any other expression 
statement, it should be required to have side-effects. I found while 
patching the ICE bug 3344 that this is happening because the expression 
never gets the semantic pass run on it.

In DMD, in statement.c.
Statement *ReturnStatement::semantic(Scope *sc)

=====
	/* Replace:
	 *	return exp;
	 * with:
	 *	exp; return;
	 */
	Statement *s = new ExpStatement(loc, exp);
+	s->semantic(sc);
=====

After making this change, it showed up that bug in Phobos.
I'm not sure if the current behaviour is intended, or is a bug. It 
certainly looks unhelpful, unexpected, and bug-prone to me. As well as 
the one-line compiler patch, I suggest the following change in the spec:

-The Expression will be evaluated, but nothing will be returned.
+The Expression will be evaluated as an ExpressionStatement, but nothing 
will be returned.

Or is there something desirable about the existing behaviour which I 
have missed?
Sep 29 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:

 In the docs for "return statement" in statement.html it says:
 ---
 ReturnStatement:
      return;
      return Expression ;
 
 Expression is allowed even if the function specifies a void return type. 
 The Expression will be evaluated, but nothing will be returned.

I agree that making the language a little more strict in such regards is better.
 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function.

If bar() is a void function then "return bar();" looks like a bug. Why do you want to allow such semantically wrong situation? Bye, bearophile
Sep 29 2009
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
bearophile Wrote:

 Don:
 
 In the docs for "return statement" in statement.html it says:
 ---
 ReturnStatement:
      return;
      return Expression ;
 
 Expression is allowed even if the function specifies a void return type. 
 The Expression will be evaluated, but nothing will be returned.

I agree that making the language a little more strict in such regards is better.
 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function.

If bar() is a void function then "return bar();" looks like a bug. Why do you want to allow such semantically wrong situation? Bye, bearophile

I believe the argument is to allow templated code to gracefully handle a void return type without special cases. It doesn't quite work since void is not a valid type for intermediate variables (leads to increased code duplication)
Sep 29 2009
next sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
Jason House wrote:
 bearophile Wrote:
 
 Don:

 In the docs for "return statement" in statement.html it says:
 ---
 ReturnStatement:
      return;
      return Expression ;

 Expression is allowed even if the function specifies a void return type. 
 The Expression will be evaluated, but nothing will be returned.

 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function.

Bye, bearophile

I believe the argument is to allow templated code to gracefully handle a void return type without special cases.

Well maybe the change could be made only to functions that are not templated.
Sep 29 2009
prev sibling parent grauzone <none example.net> writes:
Denis Koroskin wrote:
 Unfortunately, you still have to special-case void type in a lot of 
 cases. Here are just 2 examples:

And that's why there were ideas to allow declaring void variables. IMHO these void variables should allow all common operations on normal variables (assignment, passing as function parameter, taking address, dereferencing, void.init), and the compilation of those should simply result in no code.
 RetType doSomething(Args, RetType)(Args args, RetType retType)
 {
     RetType result = callSomeDelegate(args);    // doesn't work for 'void'
     addLogEntry("bla-bla-bla");
     return result;
 }
 
 class Test(T)
 {
     T foo(T t) { ... }
     T bar() { ... }
 
     T test()
     {
         return bar(foo()); // works for all types but 'void'
     }
 }

Sep 29 2009
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-09-29 07:23:54 -0400, bearophile <bearophileHUGS lycos.com> said:

 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function.

If bar() is a void function then "return bar();" looks like a bug. Why do you want to allow such semantically wrong situation?

It's handy in generic code because you don't need to special-case for void: R foo(R, A...)(A a) { return bar(a); } That said, returning something other than void from a void function is senseless. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 29 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 29 Sep 2009 15:43:55 +0400, Jason House  
<jason.james.house gmail.com> wrote:

 bearophile Wrote:

 Don:

 In the docs for "return statement" in statement.html it says:
 ---
 ReturnStatement:
      return;
      return Expression ;

 Expression is allowed even if the function specifies a void return  

 The Expression will be evaluated, but nothing will be returned.

I agree that making the language a little more strict in such regards is better.
 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function.

If bar() is a void function then "return bar();" looks like a bug. Why do you want to allow such semantically wrong situation? Bye, bearophile

I believe the argument is to allow templated code to gracefully handle a void return type without special cases. It doesn't quite work since void is not a valid type for intermediate variables (leads to increased code duplication)

Unfortunately, you still have to special-case void type in a lot of cases. Here are just 2 examples: RetType doSomething(Args, RetType)(Args args, RetType retType) { RetType result = callSomeDelegate(args); // doesn't work for 'void' addLogEntry("bla-bla-bla"); return result; } class Test(T) { T foo(T t) { ... } T bar() { ... } T test() { return bar(foo()); // works for all types but 'void' } }
Sep 29 2009
prev sibling next sibling parent Justin Johansson <procode adam-dott-com.au> writes:
Don Wrote:

 In the docs for "return statement" in statement.html it says:
 ---
 ReturnStatement:
      return;
      return Expression ;
 
 Expression is allowed even if the function specifies a void return type. 
 The Expression will be evaluated, but nothing will be returned.
 
 ----
 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function. But as currently implemented, it 
 also allows bug-prone code. Here's an example from std.utf in Phobos2:
 
 // BUG: should return size_t, not void!
 void encode(wchar[2] buf, dchar c){
     if (c <= 0xFFFF)
          return 1;
      return 2;
 }
 
 I think that instead, inside a void function, return expression; should 
 be the same as: { expression; return; }, ie, like any other expression 
 statement, it should be required to have side-effects. I found while 
 patching the ICE bug 3344 that this is happening because the expression 
 never gets the semantic pass run on it.
 
 In DMD, in statement.c.
 Statement *ReturnStatement::semantic(Scope *sc)
 
 =====
 	/* Replace:
 	 *	return exp;
 	 * with:
 	 *	exp; return;
 	 */
 	Statement *s = new ExpStatement(loc, exp);
 +	s->semantic(sc);
 =====
 
 After making this change, it showed up that bug in Phobos.
 I'm not sure if the current behaviour is intended, or is a bug. It 
 certainly looks unhelpful, unexpected, and bug-prone to me. As well as 
 the one-line compiler patch, I suggest the following change in the spec:
 
 -The Expression will be evaluated, but nothing will be returned.
 +The Expression will be evaluated as an ExpressionStatement, but nothing 
 will be returned.
 
 Or is there something desirable about the existing behaviour which I 
 have missed?

How about making a judgement based upon consistency & (co/contra) variance with "type is" operator? Try this for size: if ( is( int: void)) { writefln( "IT IS"); } else { writefln( "IT ISN'T"); } if ( is( void: int)) { writefln( "IT IS"); } else { writefln( "IT ISN'T"); } Therein either lies the answer, or proves that the type system is broken. Fan, do you have a comment about Unit type in Scala?
Sep 29 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 In the docs for "return statement" in statement.html it says:
 ---
 ReturnStatement:
     return;
     return Expression ;
 
 Expression is allowed even if the function specifies a void return type. 
 The Expression will be evaluated, but nothing will be returned.
 
 ----
 This makes sense for things we definitely want to allow, such as:
 void foo() { return bar(); }
 where bar() is another void function. But as currently implemented, it 
 also allows bug-prone code. Here's an example from std.utf in Phobos2:
 
 // BUG: should return size_t, not void!
 void encode(wchar[2] buf, dchar c){
    if (c <= 0xFFFF)
         return 1;
     return 2;
 }
 
 I think that instead, inside a void function, return expression; should 
 be the same as: { expression; return; }, ie, like any other expression 
 statement, it should be required to have side-effects. I found while 
 patching the ICE bug 3344 that this is happening because the expression 
 never gets the semantic pass run on it.
 
 In DMD, in statement.c.
 Statement *ReturnStatement::semantic(Scope *sc)
 
 =====
     /* Replace:
      *    return exp;
      * with:
      *    exp; return;
      */
     Statement *s = new ExpStatement(loc, exp);
 +    s->semantic(sc);
 =====
 
 After making this change, it showed up that bug in Phobos.
 I'm not sure if the current behaviour is intended, or is a bug. It 
 certainly looks unhelpful, unexpected, and bug-prone to me. As well as 
 the one-line compiler patch, I suggest the following change in the spec:
 
 -The Expression will be evaluated, but nothing will be returned.
 +The Expression will be evaluated as an ExpressionStatement, but nothing 
 will be returned.
 
 Or is there something desirable about the existing behaviour which I 
 have missed?

I agree with your assessment. Andrei
Sep 29 2009