Last active
April 11, 2023 14:11
-
-
Save JoshCheek/5625007 to your computer and use it in GitHub Desktop.
void value expressions make no sense
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-> { a = case when true then return end } # this is allowed | |
-> { a = if true then return end } # this is not | |
-> { a = if true then return; 2 end } # this is | |
-> { a = (true && return) } # this is allowed | |
-> { a = (return && true) } # this is not | |
-> { a = begin; return | |
rescue; return | |
ensure; return | |
end } # this is allowed | |
-> { a = begin; return; end } # this is not |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You have cleanly nailed it; to my complete surprise, there are some devs out there that still confuse a void-value-expression (an expression with no inherent value) with a void-value-expression-error (an error caused by mixing so-called "value expressions" with "void-expressions").
Interestingly enough, the most basic forms of void-value-expressions are
break
,next
,return
andraise
, all of which, intuitively, are used to change the natural path of execution in some way. To me, that has been the reason of the dichotomy between value-expressions and void-expressions -- to prevent things like12 * break
or12 * (return 12)
.To a sane mind, a void value expression error is raised only when the value of a void value expression is needed to resume the execution of the program in some way:
12 * break
: the value forbreak
is needed to calculate the value for12 * break
, and that is where the error occurs.break && l()
-- the value forbreak
is needed to decide whetherl()
should execute. this, too, is an error.12 && break
-- the value for12
is needed to decide whether we should proceed to executingbreak
-- which makes complete sense to be honest, because, even though we had abreak
, its value was not needed.Now consider this:
(12 && break) && return
. Sanity-wise, the reasoning that supposed to lead us through executing it would be:* the value for
12
is needed to decide whetherbreak
should execute (nothing wrong with that!)* the value for
12 && break
is needed to decide whetherreturn
should execute (12 && break
has no inherent value -- it's not even nil, it must be thought of as a "compound" void-expression, and at this point a "void-value-expression-error" must be actually raised!)** BUT IT WON'T **
That to me is nothing but poor and insane implementation of a feature that could have had a slight value.
Ruby as a language is not insane (it's a mere description), but the way its standard implementation behaves makes me run for cover occasionally. tl;dr Checks performed for hunting void-value-expression-errors are half-baked and are, at their best, useless, at least the way they are implemented currently.