TL; DR
In the pattern matching syntax with case
-- in
, you can use then
as well as case
-- when
(you may need to use it).
then
Although rarely used, then
is the keyword in Ruby. Use as follows:
if cond then
puts "Y"
else
puts "N"
end
There are several places where this keyword can appear, such as the if
, unless
, rescue
, and case
syntax.
As mentioned above, after writing some condition, put then
and it acts as a marker to indicate that the expression ends there.
# Example:
if x then
a
end
unless x then
a
end
begin
a
rescue then
b
end
case x
when p then
a
end
Normally, you don't write then
in Ruby code. why. You can see it by running the following code.
if true puts 'Hello, World!' end
The following syntax error is output.
20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
if true puts 'Hello, World!' end
^~~~
20:1: syntax error, unexpected `end', expecting end-of-input
...f true puts 'Hello, World!' end
Ignoring the second message and reading the first one, it seems that an error occurs because then
or;
or a variable or a method appears where a line break should come.
The point is that line breaks replace then
(or;
). Try inserting a line break after true
.
if true
puts 'Hello, World!' end
Hello, World! Is now output safely.
then
,;
and line breaks are neededWhy do we need then
,;
and line breaks (hereinafter" then`, etc. ")? See the following example:
if a b end
There are no then
,;
, or line breaks, so an error occurs because you don't know how long the conditional expression continues.
This example can be interpreted in two ways.
#If the evaluation result of the variable or method a is truthy, the variable or method b is evaluated.
if a then
b
end
#Call the method a by passing the variable b or the evaluation result of the method to the method
#If the result is truthy, do nothing
if a(b) then
end
It is clarified that then
etc. is to eliminate this ambiguity, and the conditional expression is between if
and then
etc.
The (
/)
that comes after the C-type if
, and the {
such as the Python :
and Rust/Go/Swift have the same role.
In the case of Ruby, then
can be substituted with line breaks to make it easier for programmers to write, so in most cases then
is not needed.
case
-- then
in in
I finally got to the main subject. The upcoming Ruby 3.0 will include pattern matching syntax using the case
and in
keywords. This syntax also requires then
etc. as a delimiter from the pattern part.
Since there is no formal grammar specification in (current) Ruby, I referred to the definition file of yacc (the explanation of yacc is omitted).
https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986
p_case_body : keyword_in
{
SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
p->command_start = FALSE;
$<ctxt>1 = p->ctxt;
p->ctxt.in_kwarg = 1;
$<tbl>$ = push_pvtbl(p);
}
{
$<tbl>$ = push_pktbl(p);
}
p_top_expr then
{
pop_pktbl(p, $<tbl>3);
pop_pvtbl(p, $<tbl>2);
p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
}
compstmt
p_cases
{
/*%%%*/
$$ = NEW_IN($4, $7, $8, &@$);
/*% %*/
/*% ripper: in!($4, $7, escape_Qundef($8)) %*/
}
;
Simplified version:
p_case_body : keyword_in p_top_expr then compstmt p_cases
;
Here, keyword_in
is literally in
, p_top_expr
is the so-called pattern, then
is not the then
keyword, but what we call then
etc. in this article, that is, the then
keyword. , ;
, One of the line breaks.
From this, it was found that then
etc. should be inserted after the pattern in the same way as the conventional syntax of case
-- when
. In other words, it can be one of the following three ways:
case x
in 1 then a
in 2 then b
in 3 then c
end
case x
in 1
a
in 2
b
in 3
c
end
case x
in 1; a
in 2; b
in 3; c
end
By the way, p_top_expr
can have a guard clause by if
, so in that case it looks similar to if
-then
.
case x
in 0 then a
in n if n < 0 then b
in n then c
end
if
or case
must be followed by then
,;
, or a newlineCase
-- in
, which will be included in 3.0, requires then
etc.parse.y
directlyRecommended Posts