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).
thenAlthough 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 inI 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