Riddle me this (a question about expressions)

P

Patrick Toomey

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
 
M

Marcin Mielżyński

Patrick said:
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
 
D

Devin Mullins

Patrick said:
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
 
F

Frederick Cheung

Patrick said:
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
 
R

Robert Klemme

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:
=> nil
=> nil

Kind regards

robert
 
P

Pit Capitain

Robert said:
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
 
P

Patrick Toomey

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:

=> nil

=> nil

Kind regards

robert

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
 
M

MonkeeSage

Patrick said:
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
 
M

MonkeeSage

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
 
R

Robert Klemme

Patrick said:
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". :)
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
 
L

Logan Capaldo

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


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


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.
 
H

Hal Fulton

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
 
D

dblack

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 :) 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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
G

gwtmp01

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

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
 
R

Rick DeNatale

Hi --

On Mon, 25 Sep 2006, Hal Fulton wrote:


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 :) I don't think that the two of them
need to be thought of together with regard to the syntax-error matter.


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.
 
L

Logan Capaldo

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.
 
D

dblack

Hi --

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.

Even more trivial:

x = raise rescue 1

:) But I'd still say that the return value of the call to raise is
not what's being captured in x.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
K

Kero

But try:
Even more trivial:

x = raise rescue 1

:) But I'd still say that the return value of the call to raise is
not what's being captured in x.

Of course not :) viz.

(x = raise) rescue 1; x #=> nil
x = (raise rescue 1); x #=> 1

and indeed it's more trivial than the case at the top of this post, I'm not
going to enumerate all possibilities of that ;)

Bye,
Kero.
 
R

Rick DeNatale

Hi --



Even more trivial:

x = raise rescue 1

:) But I'd still say that the return value of the call to raise is
not what's being captured in x.

Well, from a syntax point of view, it sure LOOKs like the rvalue of
the assignment is the expression "raise rescue 1"

It's an interested corner of the language. Kernel#raise is a method
so it should have a value, even though unless it's rescued it causes a
non-local return.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,214
Messages
2,571,110
Members
47,702
Latest member
gancflex

Latest Threads

Top