エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

RubyKaigi 2023にPlatinum Sponsorとして参加しました!(&難読Rubyクイズ)

エンジニアリンググループの田口です。 エムスリーは5/11〜5/13に長野県松本市で開催された「RubyKaigi 2023」に、Platinum Sponsorとして協賛・ブース出展しました。

私は初めてのRubyKaigi参加となりましたが、Rubyist達のRuby愛を強く感じた3日間でした。 この記事では、イベント・ブースの様子や、ブースで出題していた難読Rubyクイズの問題・解説についてまとめます。

イベント・ブースの様子

今回のRubyKaigiは「Ruby横丁」というテーマで設計されており、お祭り感のあるブースとなっていました。

ブース全体の様子

エムスリーブースではRubyで開発されているエムスリーデジカルの紹介動画の上映や、もはや恒例となった難読Rubyクイズの出題をしました。 Rubyクイズは3日間それぞれ問題を用意していましたが、多くのRubyist達に挑戦していただきました。 本記事ではこれらの答え・解説についても紹介します。

エムスリーブースの様子

Ruby難読クイズ

ブースでは毎日異なるテーマの問題を出題していました。 RubyKaigiへ参加できなかった方もぜひ挑戦してみてください。

問題のコードをirbで実行した時の評価値を選択肢から選んでください。 選択肢の下へスクロールするとそれぞれの問題の答え、解説が表示されます。 なお、作問は全てRubyWorldConference2022でも担当したowlが行いました。

www.m3tech.blog

Day1. Hash

1-1

選択肢

1. nil
2. 1
3. ""
4. Error

答え・解説(クリックして展開) 答えは (1) nil が正解になります。

このコードは {nil: 1} というハッシュを作成し、このハッシュに対してキー [nil] でアクセスした値を評価したものになります。 {nil: 1} のハッシュを初期化していますが、この時 :nil というシンボルがキーになるため、キー nil に対応する値がなく、nil が評価されます。 {nil:1}[:nil] の場合はハッシュのキーを正しく参照でき、1 と評価されます。

1-2

選択肢

1. nil
2. 1
3. {}
4. Error

答え・解説(クリックして展開) 答えは (4) Error が正解になります。

{nil: 1} は一見ハッシュを初期化しているように見えますが、p のようなメソッドの後に来る { ... }ブロックとして解釈されます。 このため、ブロック内に nil: 1 という不正な式が残り、シンタックスエラーになります。 {nil: 1} をハッシュとして p メソッドの引数に渡したい場合は、 p({nil: 1}) のようにすることで可能になります。

1-3

1、2行目の実行結果を踏まえて、3行目に出力されるものをものを解答してください。

選択肢

1. nil
2. 1
3. {}
4. Error

答え・解説(クリックして展開) 答えは(2) 1 が正解になります。

1行目では、ハッシュをJSON形式で初期化しようとしていますが、JSON形式の初期化では、キーは文字列であることが期待されます{1 => 1} という形式であれば、エラーにならずハッシュを初期化することができます。

2行目では、1に対してtap のブロック内でレシーバを操作しているように見えます。 +=自己代入演算子 であり以下と等価になります。

1.tap{|o|o=o+1}.to_s

この時、一時変数 o の向き先を別のオブジェクトに変えているだけなので、ブロック外には影響を及ぼさず、1 が出力されます。 オブジェクトのIDを一緒に出してみると理解しやすいですね。

> 1.tap{|o|puts(o.object_id);o+=1;puts(o.object_id)}
3
5          

一方、3行目の問題については、ハッシュのアクセスは tap のレシーバに対する操作であるため、ブロックを抜けても変更が反映されます。 先ほどと同様にオブジェクトIDを出力してみると、レシーバに変更が加えられていることが分かります。

> {}.tap{|h|puts(h.object_id);h[1]=1;puts(h.object_id)}
453560
453560      

Day1 まとめ

1日目の解答は以下のようになりました。 1-2は {nil: 1} と解答された方が多く、良い引っかけ問題となりました。

Day2. Question

2-1

選択肢

1. "!"
2. true
3. false
4. "|"

答え・解説(クリックして展開) 答えは(4) "|" が正解になります。

Day2のテーマはquestionでしたが、これらの問題を解くにあたって? にまつわる知識が必要になります。 それは、Rubyでは ? の後に1文字指定すると文字リテラルとして解釈される、という機能です。 リテラル (Ruby 3.2 リファレンスマニュアル)

つまり、問題は以下と同じ式として書き換えることができます。

> !?| || ?|

> !"|" || "|"

> false || "|"

また、Rubyでは ||最初に真と評価されたものを返す演算子であるため、最終的に "|" が評価されます。

2-2

選択肢

1. []
2. nil
3. {}
4. Error

答え・解説(クリックして展開) 答えは(2) nil が正解になります。

シンタックスエラーになりそうな見た目をしていますが、2-1と同様に ? と後1文字を変換して見てみましょう。 すると問題は以下のように書き換えることができます。

{ "}" => "{" }[{}]

つまり、問題のコードはキーが "}" で値が "{" のハッシュを作成し、これに対しキー {} でアクセスする、という式になります。 実際には、キー {} に対応する値が存在しないため nil が評価されます。

2-3

選択肢

1. 0
2. nil
3. {}
4. Error

答え・解説(クリックして展開) 答えは(1) 0 が正解になります。

この問題も、これまでと同様に ? を置換するところから始めてみましょう。

{ "<" => {} } <=> { "<" => {} }

するとこのように、{ "<" => {} } というハッシュを2つ作成し、これらを <=> で比較している、という式に書き換えることができます。 <=>宇宙船演算子で、両辺を比較して数値を返す演算子になります。 問題は { "<" => {} } というハッシュ同士を宇宙船演算子で比較し、同値判定となるため 0 が正解になります。

Day2 まとめ

2日目も多くの方に挑戦していただきました。 今回も2-3では true と解答された方が多く、正解が少数派となりました。

Day3. Symmetrical

3-1

選択肢

1. true
2. false
3. nil
4. Error

答え・解説(クリックして展開) 答えは(2) false が正解になります。

p組み込みのメソッドで、引数を出力しつつ引数を返すものになります。 問題では p メソッドを引数なしで呼び出した結果を、 | 演算子で評価したものとなっています。 p を引数なしで呼び出した返り値である nil の論理和が評価されるため、最終的にfalse が評価されます。

3-2

選択肢

1. true
2. false
3. nil
4. Error

答え・解説(クリックして展開) 答えは(2) false が正解になります。

a=a は右辺の a が未定義のため一見エラーになりそうですが、実際はそうなりません。

assignment - RDoc Documentation

a=a 右辺の a はまだ未定義ですが、a = 0 if false と同じようなものとして評価され、この代入式は a = nil と等価になります。 代入自体は成功し、結果が nil として返るため3-1同様 nil | nil の論理和が評価され、false が正解になります。

3-3

選択肢

1. nil
2. []
3. {}
4. Error

答え・解説(クリックして展開) 答えは(1) nil が正解になります。

{} の部分は空のハッシュを定義し、[{}] の部分ではこのハッシュにキー {} でアクセスしています。 [{}] の部分について詳しく見ると、{} を引数に [] インスタンスメソッドを呼び出しているとも言い換えることができます。 ここで1-2の問題を思い出すと、最後の {} はメソッド呼び出しに渡されるブロックと解釈されることが分かります。

つまり、問題は以下のように書き換えることができます。

> {}.[]({}) do end

したがって最後の {} は何もしないブロックであり、前半の {}[{}] は2-2の問題同様 nil が評価されるため、nil が正解になります。

Day3まとめ

最終日も多くの方に挑戦していただきました。やはり最後の問題は難しく、多くの方が Error と解答されていました。

We are hiring!!

エムスリーとして久しぶりとなるRubyKaigiオフラインイベントへのブース出展となりました。 ブースでは3日とも多くのRubyist達がクイズに挑戦してくださり、非常に熱のあるコミュニティだと改めて感じました。

また、個人的にもこうした取り組みは始めてでしたが、様々な方のご協力のおかげでつつがなく終えることができました。 この場でもお礼を伝えたいと思います。

エムスリーではデジカルをRuby on Railsを中心に開発しており、サービスをスケールさせていくために日々挑戦をしています。 エムスリーデジカルや医療業界に興味のお持ちの方のエントリーをお待ちしています。

speakerdeck.com

jobs.m3.com