Riddle me this (a question about expressions)

Hello all,
   I am new to Ruby and am toying around with the language to get a feel for the expression ubiquity in ruby. Anyway, explain to me the following. The below bits of code have no real relevance; they are merely illustrative of my question. The first declaration works as expected; the return value is 9. The second declaration doesn't run at all. I get a "void value expression" error. Is the runtime looking into my if statement, realizing that there is no ability for x to get set and failing? Obviously the code is ridiculous, but it seems odd to me that it would not even run. Why does the interpreter care that x will never get set if the function will return cleanly none the less?

def foo()
   x = 0
   x = if 3 > 4
           8
         else
           9
         end
   return x
end

def foo()
   x = 0
   x = if 3 > 4
           return 8
         else
           return 9
         end
   return x
end

Patrick Toomey wrote:

Hello all,
  I am new to Ruby and am toying around with the language to get a feel for the expression ubiquity in ruby. Anyway, explain to me the following. The below bits of code have no real relevance; they are merely illustrative of my question. The first declaration works as expected; the return value is 9. The second declaration doesn't run at all. I get a "void value expression" error. Is the runtime looking into my if statement, realizing that there is no ability for x to get set and failing? Obviously the code is ridiculous, but it seems odd to me that it would not even run. Why does the interpreter care that x will never get set if the function will return cleanly none the less?

def foo()
  x = 0
  x = if 3 > 4
          8
        else
          9
        end
  return x
end

def foo()
  x = 0
  x = if 3 > 4
          return 8
        else
          return 9
        end
  return x
end

I think the return statement has void context itself

check out this - in fact what you are doing is:

return (return "foo")

lopex

Patrick Toomey wrote:

The second declaration doesn't run at all. I get a "void value expression" error. Is the runtime looking into my if statement, realizing that there is no ability for x to get set and failing?

No. The 'return' keyword is one of the few things in Ruby that isn't an expression -- it doesn't have a return value. Ruby's complaining 'cause you're trying to set x to it.

Devin

Patrick Toomey wrote:

def foo()
   x = 0
   x = if 3 > 4
           return 8
         else
           return 9
         end
   return x
end

The problem is that you are effectively trying to do this
x = return 9
And that doesn't have a well defined meaning

Fred

···

--
Posted via http://www.ruby-forum.com/\.

Others have commented this already. Just another bit: once you think about semantics of "return" for a moment it should be immediately clear that it is not and cannot be an expression simply because it never returns control flow but instead transfers it to someplace else. The same holds true for "next".

Interestingly enough "raise" does not provoke such a compile error although I cannot see how it would ever return control flow locally:

RUBY_VERSION

=> "1.8.3"

def foo() x = raise "Test" end

=> nil

RUBY_VERSION

=> "1.8.5"

def foo() x = raise "Test" end

=> nil

Kind regards

    robert

Robert Klemme schrieb:

Interestingly enough "raise" does not provoke such a compile error although I cannot see how it would ever return control flow locally:

   def raise *args
     "my raise"
   end

   x = raise NameError
   p x # => "my raise"

Don't ask me why it is implemented like this, though.

Regards,
Pit

I guess that is what surprises me. I would expect return to work exactly like raise. It just seems strange to me that I can have a perfectly good expression such as

if (3 < 4)
   return 5
end

and then have that fail when I do

x = if (3 < 4)
         return 5
       end

Someone else gave the example of simplifying my question down to the equivalent of trying the following

x = return 9

Why shouldn't this be valid? As shown above, raise seems to return nil, and return seems like it should return a similar value if there is no other reasonable return value. Just for my own curiosity, what implications would returning "nil" have? Anyway, thanks for all your help. I realize most of this is of academic value, but it really helps to see how Ruby works underneath.

Patrick

···

On Sep 24, 2006, at 5:45 AM, Robert Klemme wrote:

Others have commented this already. Just another bit: once you think about semantics of "return" for a moment it should be immediately clear that it is not and cannot be an expression simply because it never returns control flow but instead transfers it to someplace else. The same holds true for "next".

Interestingly enough "raise" does not provoke such a compile error although I cannot see how it would ever return control flow locally:

RUBY_VERSION

=> "1.8.3"

def foo() x = raise "Test" end

=> nil

RUBY_VERSION

=> "1.8.5"

def foo() x = raise "Test" end

=> nil

Kind regards

   robert

Patrick Toomey wrote:

Someone else gave the example of simplifying my question down to the
equivalent of trying the following

x = return 9

Why shouldn't this be valid? As shown above, raise seems to return
nil, and return seems like it should return a similar value if there
is no other reasonable return value. Just for my own curiosity, what
implications would returning "nil" have? Anyway, thanks for all your
help. I realize most of this is of academic value, but it really
helps to see how Ruby works underneath.

Hi Patrick,

I've no idea what goes on under the hood, but I would think it is
because raise doesn't exit the current stack frame (it can be rescued
and execution continues), so it's more like a method that gets
evaluated and its return (nil) then gets assigned (nb: right hand side
of assignment is always resolved before it is assigned). But return
(and I assume break / next) break out of the current stack frame, so
the assignment is left dangling. That's my guess.

Regards,
Jordan

Patrick Toomey wrote:

I guess that is what surprises me. I would expect return to work exactly like raise.

I on the other hand expect "raise" to work exactly like "return". :slight_smile:

Someone else gave the example of simplifying my question down to the equivalent of trying the following

x = return 9

Why shouldn't this be valid?

Because "return" never returns. (Uh, this starts sounding like Zen...)

> As shown above, raise seems to return nil,

No, "raise" does neither return nil nor anything else. It does not return in the same way as "return" never returns. The whole point of the two is that they do *not* behave like an expression but transfer control flow up the call stack.

and return seems like it should return a similar value if there is no other reasonable return value. Just for my own curiosity, what implications would returning "nil" have?

It does not work. Please take the time and meditate about this.

> Anyway, thanks for all your

help. I realize most of this is of academic value, but it really helps to see how Ruby works underneath.

In this case I'd rather say, you hit behavior that is common to *all* programming languages that know "return". But I get the feeling that you still not fully understood the difference between an arbitrary expression and a return statement...

Kind regards

  robert

Funnily enough, despite having blogged it two weeks ago, I failed to mention that you can hack around the "void value expression" problem:

def foo
   $a = (return 7; 5)
end

p foo #=> 7
p $a #=> nil
__END__

Devin

Hmmm. But raise does actually break out of the current frame (and the
whole main loop) if it isn't rescued...mabye raise, since it already
enters to exception handler, shortcircuts the void assignment
exception; or mabye it completes the assignment with nil, then exists
the stack? Like I said, I'm just guessing here...I have no idea what
really happens under the hood.

Regards,
Jordan

Patrick Toomey wrote:
>I guess that is what surprises me. I would expect return to work
>exactly like raise.

I on the other hand expect "raise" to work exactly like "return". :slight_smile:

>Someone else gave the example of simplifying my question down to the
>equivalent of trying the following
>
>x = return 9
>
>Why shouldn't this be valid?

Because "return" never returns. (Uh, this starts sounding like Zen...)

> As shown above, raise seems to return nil,

No, "raise" does neither return nil nor anything else. It does not
return in the same way as "return" never returns. The whole point of
the two is that they do *not* behave like an expression but transfer
control flow up the call stack.

Regardless of whether or not it makes logical sense to say a = return b,
I think the confusion is that
x = raise b is _not_ a syntax error while
x = return b _is_ a syntax error.
Frankly, I think this is probably either a) an oversight in the grammar
or b) the need to handle the super weird edge case of
a = raise 'error' rescue nil

Either a = raise b should be a syntax error, or a = return b should not.
I'd lean towards the former, if it were up to me.

···

On Mon, Sep 25, 2006 at 05:10:18AM +0900, Robert Klemme wrote:

>and return seems like it should return a similar value if there is no
>other reasonable return value. Just for my own curiosity, what
>implications would returning "nil" have?

It does not work. Please take the time and meditate about this.

> Anyway, thanks for all your
>help. I realize most of this is of academic value, but it really helps
>to see how Ruby works underneath.

In this case I'd rather say, you hit behavior that is common to *all*
programming languages that know "return". But I get the feeling that
you still not fully understood the difference between an arbitrary
expression and a return statement...

Kind regards

  robert

Funnily enough, despite having blogged it two weeks ago, I failed to
mention that you can hack around the "void value expression" problem:

You can get around it, yes, but should not. A return
simply is a different kind of beast an the kind of
code that spawned this thread is nonsensical. Why
would one assign the result of an expression that
can never complete (nor do anything useful with
the assignment).

def foo
  $a = (return 7; 5)
end

  def foo
    $a = nil
    7
  end

···

On 2006.09.27 11:18, Devin Mullins wrote:

No, "raise" does neither return nil nor anything else. It does not return in the same way as "return" never returns. The whole point of the two is that they do *not* behave like an expression but transfer control flow up the call stack.

Nevertheless I think it's significant that raise is a method
whereas return (of course) is not.

I wonder if there is some case where raise would/does return
a meaningful value somehow? My gut reaction is 'no'... but
this is Ruby...

Hal

Eero Saynatkari wrote:

You can get around it, yes, but should not. A return
simply is a different kind of beast an the kind of
code that spawned this thread is nonsensical.

Well, DUH. Thanks for ruining my party.

Personally, I'll only use return as a cheap guard clause at the top of a method definition (return "He gently caresses her left shoulder." unless you.age > 18) -- often it saves a couple lines. Otherwise, I try to get all functional on everybody's ass.

Nonetheless, nonsense is fun. Hamhock!

Devin
Or, if you prefer: SPOOOOOOOOOOOOOOON!

Hi --

No, "raise" does neither return nil nor anything else. It does not return in the same way as "return" never returns. The whole point of the two is that they do *not* behave like an expression but transfer control flow up the call stack.

Nevertheless I think it's significant that raise is a method
whereas return (of course) is not.

I think so too. I would not want to see a method call of any kind be
dealt with as a syntax error just because it has an assignment to its
left. Since return can't really be a method (at least my brain can't
wrap itself around that concept :slight_smile: I don't think that the two of them
need to be thought of together with regard to the syntax-error matter.

I wonder if there is some case where raise would/does return
a meaningful value somehow? My gut reaction is 'no'... but
this is Ruby...

I am fairly certain that the return value can never be captured. At
least I can't figure out how to do it.

In this:

  def raise_value
    x = raise
  rescue
    x
  end

  p raise_value # nil

I'm pretty sure that x is nil because of the thing where the parser
sees an assignment and defines the variable. I don't think an
assignment ever actually takes place -- as witness the fact that:

   x = raise || 1

also leaves x as nil.

David

···

On Mon, 25 Sep 2006, Hal Fulton wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Devin Mullins wrote:

Or, if you prefer: SPOOOOOOOOOOOOOOON!

Heh! Spork! :slight_smile:

+1

Regards,
Jordan

Well, since it is a method...

module Kernel
   def raise
      'not what you expected'
   end
end

x = raise
p x

Maybe that is cheating, but as long as raise is a method there is the
possibility that it might return a value.

Gary Wright

···

On Sep 24, 2006, at 4:50 PM, dblack@wobblini.net wrote:

On Mon, 25 Sep 2006, Hal Fulton wrote:

I wonder if there is some case where raise would/does return
a meaningful value somehow? My gut reaction is 'no'... but
this is Ruby...

I am fairly certain that the return value can never be captured. At
least I can't figure out how to do it.

But try:

x = raise rescue nil || 1

Of course this is a trivial example, but the point is that raise can
in fact have a value.

···

On 9/24/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

Hi --

On Mon, 25 Sep 2006, Hal Fulton wrote:

>
> Nevertheless I think it's significant that raise is a method
> whereas return (of course) is not.

I think so too. I would not want to see a method call of any kind be
dealt with as a syntax error just because it has an assignment to its
left. Since return can't really be a method (at least my brain can't
wrap itself around that concept :slight_smile: I don't think that the two of them
need to be thought of together with regard to the syntax-error matter.

> I wonder if there is some case where raise would/does return
> a meaningful value somehow? My gut reaction is 'no'... but
> this is Ruby...

I am fairly certain that the return value can never be captured. At
least I can't figure out how to do it.

In this:

  def raise_value
    x = raise
  rescue
    x
  end

  p raise_value # nil

I'm pretty sure that x is nil because of the thing where the parser
sees an assignment and defines the variable. I don't think an
assignment ever actually takes place -- as witness the fact that:

   x = raise || 1

also leaves x as nil.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

>Hi --
>
>

>>
>> Nevertheless I think it's significant that raise is a method
>> whereas return (of course) is not.
>
>I think so too. I would not want to see a method call of any kind be
>dealt with as a syntax error just because it has an assignment to its
>left. Since return can't really be a method (at least my brain can't
>wrap itself around that concept :slight_smile: I don't think that the two of them
>need to be thought of together with regard to the syntax-error matter.
>
>> I wonder if there is some case where raise would/does return
>> a meaningful value somehow? My gut reaction is 'no'... but
>> this is Ruby...
>
>I am fairly certain that the return value can never be captured. At
>least I can't figure out how to do it.
>
>In this:
>
> def raise_value
> x = raise
> rescue
> x
> end
>
> p raise_value # nil
>
>I'm pretty sure that x is nil because of the thing where the parser
>sees an assignment and defines the variable. I don't think an
>assignment ever actually takes place -- as witness the fact that:
>
> x = raise || 1
>
>also leaves x as nil.

But try:

x = raise rescue nil || 1

Of course this is a trivial example, but the point is that raise can
in fact have a value.

def x
fail "Exception"
end

x = return x() rescue nil

Just muddying the waters.

···

On Mon, Sep 25, 2006 at 12:34:27PM +0900, Rick DeNatale wrote:

On 9/24/06, dblack@wobblini.net <dblack@wobblini.net> wrote:
>On Mon, 25 Sep 2006, Hal Fulton wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/