can’t see anyway to explain the results syntactically other than
saying that the ‘raise … rescue …’ is an rvalue in the assigment.
I still agree with you I find it interesting to look at what
raise is actually doing/returning, but clearly x gets its 1 from that
whole expression, and there’s no way (that I can see) to drive a wedge
between the calling of raise and the execution of the rescue clause.
I can’t agree.
Neither can I. The rescue modifier is a special dispensation, but
raise is still just a method call and shouldn’t cause a syntax error.
I’m still thinking a “stacked” exception might explain the behavior.
When an unrescued raise enters the exception handler, then the further
void assignment exception that you get with return never happens
because the interpreter is already in an exception context and simply
aborts before it sees the next exception (right side of assignment
evaluated first). But if the exception is rescued, the nil return from
raise is assigned (unless the value of the rescue is used, ala Kero’s
example?). With return you simply break out of the context and leave
the assignment dangling, so you get the void assignment exception. That
seems to make sense…
And some have expressed the opinion that both should be disallowed.
I can’t agree. I think that the proper documentation of
Kernel#raise/Thread#raise should be that it causes a non-local return
unless it is rescued, in which case the value is the value of the
expression in the rescue. That’s how it works now.
Well, those words are sort of confusing:
begin @x = raise
rescue
42
end
p @x #=> nil
@x = raise rescue 42
p @x #=> 42
To put the result into better perspective, the binding of = is to the
entire expression including the rescue, which has the result of 42
[1]. This makes much more sense as one could imagine an invisble
wrapper like:
@x = begin raise rescue 42 end
So should raise w/o the rescue be illegal? (no begin/end semantically)
Of course the final arbiter is Matz.
Agreed. I personally think that this is a rather unimportant corner
case. I’m not sure I would change anything myself.
@x = raise
No it’s the same thing. The value of the lvalue in this case is the
value of raise, which since the raise was rescued is 42.
I think that my proposed documentation covers this case.
No it doesn’t. I would say that is was rescued in my example as well.
The language might look like:
Kernel#raise/Thread#raise causes a non-local return unless it is
rescued, in which case the result of the begin…end block is the
result of the expression in the rescue clause.
To put the result into better perspective, the binding of = is to the
entire expression including the rescue, which has the result of 42
[1].
Except in this case the only ‘entire expression’ which includes the rescue is:
begin; x=raise;rescue; 42;end
And x is not being assigned the value of this expression.
Actually, single line rescue has tighter bindings than =. So it would
be like I show.
x = raise rescue 42
becomes:
x = (raise rescue 42)
This makes much more sense as one could imagine an invisble
wrapper like:
@x = begin raise rescue 42 end
But I think it makes even more sense to explain the syntax as it is
rather than modifying it.
That was my attempt. I am explaining that:
x = raise “something” rescue 42
has the same result as:
x = begin raise “something” rescue 42 end
This dispelling any doubt about what other differences might be. We
could safely use such a mechanism mentally if it happened to help us.
So should raise w/o the rescue be illegal? (no begin/end semantically)
Too fussy, I think.
I’m not sure what you mean here. I am trying to say that it is overly
complex to think of raise as an expression which returns. It’s kind of
like trying to get the result of calling a continuation; it doesn’t
return one. It is much easier to use a structured interpretation where
there are begin…end clauses which happen to behave very dependably.
It is; that expression evaluates to 1, and that’s what x gets. But I
I can’t agree.
Neither can I. The rescue modifier is a special dispensation, but
raise is still just a method call and shouldn’t cause a syntax error.
David
I think a more interesting question is, whether or not raise should be
a method. It is a method in, Smalltalk for instance, but Smalltalk also
reifies the callstack. I agree that a method should not cause a syntax
error (in that position), but I’m not
so sure I agree with the idea that raise should be a method. But it
isn’t my baby.
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).
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.
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.