Slide 1

Slide 1 text

至極の難問言語仕様クイズ 〜最強のマルチリンガル決定戦〜 2021.5.6

Slide 2

Slide 2 text

至極の難問言語仕様クイズとは ● YAML / PHP / Ruby / JavaScript / Java の5言語から4択クイズを出題 ○ バージョンが明記されてなければ最新の実装で動くものと思ってください ● 最も正答率の高かった人が複数のプログラミング言語を極めし 王者! ● 最強のマルチリンガルには、王者にふさわしい豪華景品を用意しています

Slide 3

Slide 3 text

景品1 最強のマルチリンガルRoleを付与 目立つこと間違いなし!!!

Slide 4

Slide 4 text

景品2 重箱の隅をつつく人をモチーフ にした「多言語王トロフィー」 ※複数名優勝の場合は抽選 1名

Slide 5

Slide 5 text

ルール説明

Slide 6

Slide 6 text

フォームでご回答ください

Slide 7

Slide 7 text

󰢄 禁止事項 ● irbやdevconsoleなどで実行して動作確認しないでください ● ぐぐらないでください ● 答えが出てからフォームに回答しないでください ● #エンジニアクイズ大会 に正解に近づくヒント、もしくは解答を 書かないでください ● 正々堂々最強のエンジニアになりましょう

Slide 8

Slide 8 text

󰢐 推奨事項 ● #エンジニアクイズ大会 での実況・感想など ● Twitterへの感想の投稿など ○ #pixivdevmeetup をつけていただけると嬉しいです

Slide 9

Slide 9 text

練習問題 必ず解答ください

Slide 10

Slide 10 text

1. Hello Worldが出力される 2. Hello pixivが出力される 3. Hell pixivが出力される 4. 何も出力されない Ruby puts 'Hello pixiv'

Slide 11

Slide 11 text

1. Hello Worldが出力される 2. Hello pixivが出力される 3. Hell pixivが出力される 4. 何も出力されない Ruby puts 'Hello pixiv'

Slide 12

Slide 12 text

12 なぜ? ● putsは標準出力をするためのメソッド ● 渡された文字列を出力します

Slide 13

Slide 13 text

YAML問題

Slide 14

Slide 14 text

14 自己紹介 ● sue445 ● 2018年7月入社 ○ もうすぐ4年目 ● インフラ部所属 ● 自称YAMLエンジニア ○ Ansible, Docker Compose, CircleCI, Travis CI, Wercker, GitHub Actions, GitLab CI, Serverless Framework, AWS SAM, Kubernetes sue445

Slide 15

Slide 15 text

1. {"a"=>"1"} 2. {"a"=>1} 3. シンタックスエラー 4. その他 YAML 1問目 # problem1.yml a: 1 # Rubyで実行 YAML.load_file("problem1.yml" )

Slide 16

Slide 16 text

1. {"a"=>"1"} 2. {"a"=>1} 3. シンタックスエラー 4. その他 YAML 1問目 # problem1.yml a: 1 # Rubyで実行 YAML.load_file("problem1.yml" )

Slide 17

Slide 17 text

17 なぜ? ● YAMLの数字っぽい文字列はその言語の数字の型( Rubyだと Integer ) として解釈されます。 ● 文字列として解釈させたい場合は "1" (ダブルクオーテーション)や '1' (シングルクォーテーション)のように囲んでください

Slide 18

Slide 18 text

1. "ふたりはプリキュア Splash Star,Yes!プリキュア5,Yes!プリ キュア5GoGo,フレッシュプリキュ ア!" 2. "ふたりはプリキュア Splash Star,,Yes!プリキュア5GoGo,フレッ シュプリキュア!" 3. ",Yes!プリキュア5,Yes!プリキュア 5GoGo,フレッシュプリキュア!" 4. シンタックスエラー YAML 2問目 # problem2.yml splash: ふたりはプリキュア Splash Star yes: Yes!プリキュア5 yes_gogo: Yes!プリキュア5GoGo fresh: フレッシュプリキュア! # Rubyで実行 data = YAML.load_file("problem2.yml" ) "#{data['splash']}, #{data['yes']}, #{data['yes_gogo']} ,#{data['fresh']}"

Slide 19

Slide 19 text

1. "ふたりはプリキュア Splash Star,Yes!プリキュア5,Yes!プリ キュア5GoGo,フレッシュプリキュ ア!" 2. "ふたりはプリキュア Splash Star,,Yes!プリキュア5GoGo,フレッ シュプリキュア!" 3. ",Yes!プリキュア5,Yes!プリキュア 5GoGo,フレッシュプリキュア!" 4. シンタックスエラー YAML 2問目 # problem2.yml splash: ふたりはプリキュア Splash Star yes: Yes!プリキュア5 yes_gogo: Yes!プリキュア5GoGo fresh: フレッシュプリキュア! # Rubyで実行 data = YAML.load_file("problem2.yml" ) "#{data['splash']}, #{data['yes']}, #{data['yes_gogo']} ,#{data['fresh']}"

Slide 20

Slide 20 text

20 なぜ? ● true, false, yes, no, on, off はダブルクオーテーションなどで囲まない限り YAMLでは全て 真偽値 として扱われます ● Hashのvalueだけでなくkeyに対しても同様に適用されます data = YAML.load_file("problem2.yml") => {"splash"=>"ふたりはプリキュア Splash Star", true=>"Yes!プリキュア5GoGo!", "yes_gogo"=>"Yes!プリキュア5GoGo", "fresh"=>"フレッシュプリキュア!"}

Slide 21

Slide 21 text

1. {"slack"=>{"webhook_url"=> "https://example.com/", "channel"=>"random"}} 2. {"slack"=>{"webhook_url"=> "https://example.com/", "channel"=>"production_notify"}} 3. {"slack"=>{"channel"=> "production_notify"}} 4. シンタックスエラー YAML 3問目 # problem3.yml default: &default slack: webhook_url: "https://example.com/" channel: "random" production: <<: *default slack: channel: "production_notify" # Rubyで実行 data = YAML.load_file("problem3.yml" ) data["production"]

Slide 22

Slide 22 text

1. {"slack"=>{"webhook_url"=> "https://example.com/", "channel"=>"random"}} 2. {"slack"=>{"webhook_url"=> "https://example.com/", "channel"=>"production_notify"}} 3. {"slack"=>{"channel"=> "production_notify"}} 4. シンタックスエラー YAML 3問目 # problem3.yml default: &default slack: webhook_url: "https://example.com/" channel: "random" production: <<: *default slack: channel: "production_notify" # Rubyで実行 data = YAML.load_file("problem3.yml" ) data["production"]

Slide 23

Slide 23 text

23 なぜ? ● & (アンカー)と * (エイリアス)で定義済みの値をいい感じに共通化できる のはYAMLのよくあるリファクタリング手法ですが、 <<: (マージ)はdeep merge(要素内に別の要素があった時に再帰的にマージされる)で はなく第1要素だけを上書きするマージ(代入に近い)なので、 今回の場合 default の内容が打ち消されます。

Slide 24

Slide 24 text

1. [1.9, 1.10, 1.11, 1.12] 2. [1.9, 1.1, 1.11, 1.12] 3. [1.90, 1.10, 1.11, 1.12] 4. シンタックスエラー YAML 4問目 # problem4.yml go: - 1.9 - 1.10 - 1.11 - 1.12 # Rubyで実行 data = YAML.load_file("problem4.yml" ) data["go"]

Slide 25

Slide 25 text

1. [1.9, 1.10, 1.11, 1.12] 2. [1.9, 1.1, 1.11, 1.12] 3. [1.90, 1.10, 1.11, 1.12] 4. シンタックスエラー YAML 4問目 # problem4.yml go: - 1.9 - 1.10 - 1.11 - 1.12 # Rubyで実行 data = YAML.load_file("problem4.yml" ) data["go"]

Slide 26

Slide 26 text

26 なぜ? ● クオーテーションで囲んでいないので小数として解釈されるため 1.10 は 1.1 として解釈されます ● 厳密に 1.10 として評価するには "1.10" のように囲む必要があります。 ● 余談ですがGo 1.10が出た時に .travis.yml に 1.10 を追加したらGo 1.1で CIが実行されてビルドが失敗したことがあります。

Slide 27

Slide 27 text

1. aのみシンタックスエラー 2. bのみシンタックスエラー 3. aとb両方シンタックスエラー 4. シンタックスエラーは無い YAML 5問目 # この中でシンタックスエラーになるのは? # a excludes: - *_test.rb # b excludes: - test/**

Slide 28

Slide 28 text

1. aのみシンタックスエラー 2. bのみシンタックスエラー 3. aとb両方シンタックスエラー 4. シンタックスエラーは無い YAML 5問目 # この中でシンタックスエラーになるのは? # a excludes: - *_test.rb # b excludes: - test/**

Slide 29

Slide 29 text

29 なぜ? ● *_test.rb の * が前述のエイリアスとして評価されるのですが、 対応する _test.rb という名前のエイリアスが存在しないため シンタックスエラーになります。 ● シンタックスエラーにしないためには "*_test.rb" のように囲む必要があります。

Slide 30

Slide 30 text

PHP問題

Slide 31

Slide 31 text

31 自己紹介 ● /たっ?どさん/ ● 2012年11月入社 ○ 入社前はRubyをやってました ○ PHPは入社してからの付き合いです ● pixiv運営本部開発支援チーム ● Emacs PHP Mode 現行メンテナー ○ シンタックス色付け係 ○ 連休中も正規表現書いてました tadsan

Slide 32

Slide 32 text

1. Http\Referer が 出力される 2. Referer が出力される 3. object(Referer)#1 (0) {} が 出力される 4. 実行時に Class "Referer" not found エラーで落ちる PHP 1問目

Slide 33

Slide 33 text

1. Http\Referer が 出力される 2. Referer が出力される 3. object(Referer)#1 (0) {} が 出力される 4. 実行時に Class "Referer" not found エラーで落ちる PHP 1問目

Slide 34

Slide 34 text

34 なぜ? ● PHPの ::class マジック定数はクラス名のFQCN(名前空間付きクラス名)を 文字列として返します ● しかし、そのクラスが定義済みか、ロード可能かなどは 一切問いません ● 未定義だとしても ::class の左側に記述したクラス名を名前空間付きにした 文字列をそのまま返します ● このようなミスの検出にはPHPStanのような静的解析が有効です

Slide 35

Slide 35 text

1. $a 2. $b 3. $c 4. $d PHP 2問目

Slide 36

Slide 36 text

1. $a 2. $b 3. $c 4. $d PHP 2問目

Slide 37

Slide 37 text

37 なぜ? ● PHP用語で関数として呼び出し可能な値を callable擬似型と呼びます ● callableとして型宣言できる値は「関数名の文字列」「クラス名 ::メソッド名の文字列」 「Closureオブジェクト」そして「2要素の配列」などです ○ 2要素の配列とは [$obj, 'method'] または ['Klass', 'staticmethod'] ○ 未定義のメソッド名が渡された場合はきちんと弾けます ● 言語機能としてClosureが実装されるPHP 5.3より前はcreate_function()という 関数で引数に文字列を渡すと、擬似的な無名関数が作れました

Slide 38

Slide 38 text

1. CONST 2. CONST_2 3. CONST_3 4. CONST_4 PHP 3問目

Slide 39

Slide 39 text

1. CONST 2. CONST_2 3. CONST_3 4. CONST_4 PHP 3問目 ヒント: define()関数は実行時(関数呼び出し時)に、 const文はコンパイル時に定数を定義します。 . は文字列結合演算子 strtolower()は文字列を小文字にする関数 constant()は定義済み定数の値を得る関数

Slide 40

Slide 40 text

40 なぜ? ● const文に書けるのは定数式と呼ばれるもので、定数およびリテラル (配列含む)および、 それらを組み合わせた演算子式です。引数のデフォルト値と同じ。 ● 1.はひっかけです。PHPの予約語はケースインセンシティブなので、大文字 小文字問わずconstという定数・関数は定義できません。 (変数とメソッドは可) ○ define()で定義される定数をconstから参照するのは可能です ● 2.はリテラル同士の演算子式なので合法です。 ● 3., 4. は実行時に評価される関数なので const文には書けません。 PHPにはC++のconst exprのような概念はいまのところありません。

Slide 41

Slide 41 text

1. Aが出力される 2. Bが出力される 3. 実行時エラーで落ちる 4. syntax errorで実行できない PHP 4問目

Slide 42

Slide 42 text

1. Aが出力される 2. Bが出力される 3. 実行時エラーで落ちる 4. syntax errorで実行できない PHP 4問目

Slide 43

Slide 43 text

43 なぜ? ● ここまで関数がそうだったように、 newにも変数が使えます ● $class = 'B'; $obj = new $class; のように 文字列 'B' を渡すと、Bのインスタンスに初期化になります ● newの右辺の変数が文字列ではなくインスタンスオブジェクトだった場合、 そのインスタンスのクラスとして初期化が実行されます ○ この文脈では __toString() の有無は影響を及ぼさず、ひっかけです ○ echoなどでは暗黙的に呼び出されますが、 newは呼び出しません

Slide 44

Slide 44 text

ゲスト問題 uzulla

Slide 45

Slide 45 text

1. hiと出力される 2. hihiと出力される 3. hihihihi…と無限ループする 4. レスポンスが返ってこない PHP 5問目

Slide 46

Slide 46 text

1. hiと出力される 2. hihiと出力される 3. hihihihi…と無限ループする 4. レスポンスが返ってこない PHP 5問目

Slide 47

Slide 47 text

47 なぜ? ● 通常、__FILE__マジック定数はファイル名の文字列として展開されます ● eval 内で展開される二度目の__FILE__の文字列 "/path/eval.php(4) : eval()'d code" のような形式で、 ファイル名ではなくなります ● このコードは初回起動と一回の evalでそれぞれ hi と出力され、 それ以上は再帰することなく終了します ● エラー出力は ini_set("display_errors", 0); で抑制され、最終出力は hihi です

Slide 48

Slide 48 text

Ruby問題

Slide 49

Slide 49 text

49 自己紹介 ● usa (unak) ● 2018年3月入社 ● 配信技術部エンジニアマネージャー ● Rubyコミッタ ○ 毎年Rubyの安定版を殺す係の人 ○ https://www.ruby-lang.org/ で一番多くの記 事を書いてる人 ○ x64版Windowsへの移植をした人 usa

Slide 50

Slide 50 text

1. nil と改行が出力される 2. nil だけ出て無改行 3. 改行のみが出力される 4. 改行も含めて一切何も出力さ れない Ruby 1問目 # 以下のスクリプトを実行すると何が # 起きますか? p

Slide 51

Slide 51 text

1. nil と改行が出力される 2. nil だけ出て無改行 3. 改行のみが出力される 4. 改行も含めて一切何も出力さ れない Ruby 1問目 # 以下のスクリプトを実行すると何が # 起きますか? p

Slide 52

Slide 52 text

52 なぜ? ● 特に解説するほどでもないですが、 p は無引数の場合は何も出力しません。

Slide 53

Slide 53 text

1. 改行のみが出力される 2. 何も出力されない 3. 42 が出力される 4. SystemStackError 例外が発 生する Ruby 2問目 # 以下のスクリプトを実行すると何が # 起きますか? def p(p=42) p end p p

Slide 54

Slide 54 text

1. 改行のみが出力される 2. 何も出力されない 3. 42 が出力される 4. SystemStackError 例外が発 生する Ruby 2問目 # 以下のスクリプトを実行すると何が # 起きますか? def p(p=42) p end p p

Slide 55

Slide 55 text

55 なぜ? ● スクリプト内で再定義された p メソッド内で使われている p は仮引数の p なので、このメ ソッドは無引数で呼ばれた場合には単に 42 を返すだけのメソッドとなります。 ● 括弧があるか引数の指定があればここで自分を再帰呼び出しするんですが、この場合は メソッド呼び出しではなく変数参照が優先されるんですね。 ● で、p p では、まず後ろの p の呼び出しが発生し、無引数なので 42 を返します。

Slide 56

Slide 56 text

56 なぜ? ● つづいて、この 42 を引数として再び p が呼ばれますが、今度はこの引数である 42 を返 すだけです。 ● 結局、組み込みの p は呼ばれませんので、特になんの出力も行われません。

Slide 57

Slide 57 text

1. Bは a に 42 が入るが、AとCは syntax errorになる 2. AとBは a に 42 が入るが C は syntax errorになる 3. BとCは a に 42 が入るが A は syntax errorになる 4. 全部 a に 42 が入る Ruby 3問目 # Rubyには本当の意味での右代入はないですが、 # Ruby 3.0からは類似のことが 1行パターン # マッチング構文で実現可能となっています。 # では、Ruby 3.0において、以下のスクリプト の # A・B・Cについて、正しい答えを選んで # ください。 42 => a # A (42) => (a) # B [42] => [a] # C

Slide 58

Slide 58 text

1. Bは a に 42 が入るが、AとCは syntax errorになる 2. AとBは a に 42 が入るが C は syntax errorになる 3. BとCは a に 42 が入るが A は syntax errorになる 4. 全部 a に 42 が入る Ruby 3問目 # Rubyには本当の意味での右代入はないですが、 # Ruby 3.0からは類似のことが 1行パターン # マッチング構文で実現可能となっています。 # では、Ruby 3.0において、以下のスクリプト の # A・B・Cについて、正しい答えを選んで # ください。 42 => a # A (42) => (a) # B [42] => [a] # C

Slide 59

Slide 59 text

59 なぜ? ● 全て1行パターンマッチング構文として正しく、 a に 42 が入ります。 ● ただし、Cだけは現状は常時警告が出ます。 ● 来るRuby 3.1ではこの警告も消えるかもです。 ● なお、これらは式の値自体は nil になりますのでご注意くださいませ。

Slide 60

Slide 60 text

1. {42 => 42} が出力される 2. syntax errorになる 3. nil が出力される 4. 何も出力されない Ruby 4問目 # Ruby 3.0で以下のスクリプトを実行すると # 何が起きるでしょう? a = b = 42 p { a => b }

Slide 61

Slide 61 text

1. {42 => 42} が出力される 2. syntax errorになる 3. nil が出力される 4. 何も出力されない Ruby 4問目 # Ruby 3.0で以下のスクリプトを実行すると # 何が起きるでしょう? a = b = 42 p { a => b }

Slide 62

Slide 62 text

62 なぜ? ● { a => b } はハッシュロケット構文なのでHashオブジェクト {42 => 42} になって、それを p するから答えは1……ではありません。ここでは { はハッシュ式ではなくブロック引数の始ま りとみなされますので、Hashオブジェクトにはなりません。Rubyを書き始めたばかりの人 がよく踏むやつです。 ● というわけで、ハッシュ式の中以外ではハッシュロケット => は書けませんので、ここで syntax errorになるので答えは2……となりそうな気がしますし、実際、 Ruby 2.7までではそ の通りなのですが、Ruby 3.0では第3問で述べた1行パターンマッチング構文が導入され たので、a => b は文法的に正しい式です。

Slide 63

Slide 63 text

63 なぜ? ● 従って、これは正しい文なので a => b が評価され、その結果は nil なので nil が出力され て答えは3…… となるわけではなくて、実はRubyではブロックを引数として受け取らないメ ソッドに敢えてブロックを渡した場合、単にそれを無視するという不思議な性質がありま す。構文解析だけはされるので、文法的に書けない式を書くと syntax errorにはなるんで すけどね。 ● というわけで、{ a => b } は結局 p メソッドには無視されてしまい、引数がないという扱い になるので、第1問と同じように、何も出力されないのでした。

Slide 64

Slide 64 text

ゲスト問題 mame

Slide 65

Slide 65 text

1. gsub! 2. sub 3. = 4. ! Ruby 5問目 # 次のコードに"pixiv!"と出力させるには、 # [] のあたりに選択肢のどれを書き込めばよ い? str = "p!xiv!" str. [] (/!/, 'i') puts str

Slide 66

Slide 66 text

1. gsub! 2. sub 3. = 4. ! Ruby 5問目 # 次のコードに"pixiv!"と出力させるには、 # [] のあたりに選択肢のどれを書き込めばよ い? str = "p!xiv!" str. [] (/!/, 'i') puts str

Slide 67

Slide 67 text

67 なぜ? ● ! を両方置き換えたらまずいから gsub! はダメだというのはみなさんすぐにわかると思い ますが、sub では元の文字列は変更されないし、どういうことなの? ってなったと思いま す。 ● 実は、「[] のあたりに」というのが罠で、[] 部分を置き換えるのではなくて [] の後ろに = を 入れるのが正解です。

Slide 68

Slide 68 text

68 なぜ? ● String#[]= は、引数が整数であればそこで指定されたインデックスの文字を 置き換え、整数の範囲式であればその指定された範囲の部分文字列を置き換え ますが、引数が正規表現の場合は最初にマッチした部分文字列を置き換えます。 ● このマイナーな挙動に加えて、それを代入式記法 (str[/!/] = 'i')ではなく メソッド式記法(str.[]=(/!/, 'i'))で使わせるという、普段書かないので 頭に浮かびにくいコードとなっており、罠が何重にもかけられているという 問題でした。

Slide 69

Slide 69 text

JavaScript問題

Slide 70

Slide 70 text

70 自己紹介 ● moriken (petamoriken) ● 2017年5月入社(アルバイト) ● プロダクト支援本部 課題解決部 エンジニア ○ 福岡オフィス ● JavaScript が好きで TC39 会議を追っています ○ 「moriken scrapbox」で検索! ○ 2018年くらいから TC39 会議の流れが日本語 で読めます(最近サボリ気味) moriken

Slide 71

Slide 71 text

1. "PIXIV DEV MEETUP 2021" 2. "PIXIV undefined MEETUP 2021" 3. "PIXIV DEV [object String] 2021" 4. "PIXIV undefined [object String] 2021" JavaScript 1問目 // 最後の式の結果は? const str1 = "PIXIV"; str1.word = "DEV"; const str2 = new String("MEETUP"); str2.word = "2021"; `${str1} ${str1.word} ${str2} ${str2.word}`;

Slide 72

Slide 72 text

JavaScript 1問目 // 最後の式の結果は? const str1 = "PIXIV"; str1.word = "DEV"; const str2 = new String("MEETUP"); str2.word = "2021"; `${str1} ${str1.word} ${str2} ${str2.word}`; 1. "PIXIV DEV MEETUP 2021" 2. "PIXIV undefined MEETUP 2021" 3. "PIXIV DEV [object String] 2021" 4. "PIXIV undefined [object String] 2021"

Slide 73

Slide 73 text

73 なぜ? ● プリミティブ値に対してプロパティを設定することはできません。 ● str1 はプリミティブで str2 はプリミティブラッパーオブジェクトなので、 str2 にのみプロパティを設定できます。 ● また Object.prototype.toString.call(str2) は "[object String]" を返すのですが これはひっかけで、str2.toString() の結果と同じ "MEETUP" の文字列が含まれる 形になります。

Slide 74

Slide 74 text

1. [5, 10, 15, "10"] 2. [5, 10, "10", 15] 3. [10, "10", 15, 5] 4. 実装依存 (一意に定まらない) JavaScript 2問目 // ソートの結果は? [10, 15, "10", 5].sort();

Slide 75

Slide 75 text

1. [5, 10, 15, "10"] 2. [5, 10, "10", 15] 3. [10, "10", 15, 5] 4. 実装依存 (一意に定まらない) // ソートの結果は? [10, 15, "10", 5].sort(); JavaScript 2問目

Slide 76

Slide 76 text

76 なぜ? ● Array.prototype.sort のデフォルトソートは何故か文字列の比較となっている ため、文字列化した際の辞書順に並びます。 ● Array.prototype.sort は安定ソートとは限らないため実装依存と思った方もいらっしゃる かもしれません(数値の 10 と文字列の "10" のどっちが先に来るかわからない)が、これ については ES2019 から安定ソートが必須化されています。 ○ 2, 3年くらい前の古い V8 エンジンの環境でない限り安定ソートだと考えて 問題ありません。

Slide 77

Slide 77 text

1. PIXIV { DEV: "MEETUP" } (PIXIV オブジェクト) 2. "2021" 3. String { "2021" } (プリミティブラッパーオブ ジェクト) 4. throws TypeError // 最後の式の結果は? class PIXIV { constructor() { this.DEV = "MEETUP"; return "2021"; } } new PIXIV(); JavaScript 3問目

Slide 78

Slide 78 text

// 最後の式の結果は? class PIXIV { constructor() { this.DEV = "MEETUP"; return "2021"; } } new PIXIV(); 1. PIXIV { DEV: "MEETUP" } (PIXIV オブジェクト) 2. "2021" 3. String { "2021" } (プリミティブラッパーオブ ジェクト) 4. throws TypeError JavaScript 3問目

Slide 79

Slide 79 text

79 なぜ? ● コンストラクタの返り値がオブジェクトの場合はそれで上書きできますが、 プリミティブ値の場合は上書きできずにそのままスルーされて this が返ります。

Slide 80

Slide 80 text

1. { value: "PIXIV", done: false } 2. { value: "MEETUP", done: false } 3. { value: undefined, done: true } 4. throws TypeError // 最後の式の結果は? function* gen() { yield* ["PIXIV", "DEV", "MEETUP", "2021"]; } const iter = gen(); for (const word of iter) { if (word === "DEV") { break; } } iter.next(); JavaScript 4問目

Slide 81

Slide 81 text

1. { value: "PIXIV", done: false } 2. { value: "MEETUP", done: false } 3. { value: undefined, done: true } 4. throws TypeError // 最後の式の結果は? function* gen() { yield* ["PIXIV", "DEV", "MEETUP", "2021"]; } const iter = gen(); for (const word of iter) { if (word === "DEV") { break; } } iter.next(); JavaScript 4問目

Slide 82

Slide 82 text

82 なぜ? ● この問題は for-of とジェネレーター函数について問われた問題です。 ○ for-of の途中でループから抜ける場合、イテレーターに return メソッドが定義されて いる場合はそれを実行します。 ○ ジェネレーター函数から作ったイテレーターにはプロトタイプに return メソッドが定義 されています。実行すると列挙が終わった扱いになります。 ● 余談ですが ["PIXIV", "DEV", "MEETUP", "2021"].values() で ArrayIterator を作った場合 は、プロトタイプに return メソッドが定義されていないため結果が変わります。

Slide 83

Slide 83 text

ゲスト問題 gaogao_9

Slide 84

Slide 84 text

1. "PIXIV" 2. "DEV" 3. "MEETUP" 4. "2021" // 最後の式の結果は? const obj = Object.create(null, { [Symbol("PIXIV")]: { value: "PIXIV", enumerable: true }, DEV: { value: "DEV", enumerable: true }, MEETUP: { value: "MEETUP", enumerable: true }, 2021: { value: "2021", enumerable: true }, }); Object.values(obj)[ Object.keys(obj).length-1 ]; JavaScript 5問目

Slide 85

Slide 85 text

1. "PIXIV" 2. "DEV" 3. "MEETUP" 4. "2021" // 最後の式の結果は? const obj = Object.create(null, { [Symbol("PIXIV")]: { value: "PIXIV", enumerable: true }, DEV: { value: "DEV", enumerable: true }, MEETUP: { value: "MEETUP", enumerable: true }, 2021: { value: "2021", enumerable: true }, }); Object.values(obj)[ Object.keys(obj).length-1 ]; JavaScript 5問目

Slide 86

Slide 86 text

86 なぜ? ● これは Object.keys と Object.values がどんな配列を返すのかを問う問題です。 ○ 両方ともオブジェクトのプロパティのキーが文字列なもののみを含みます(シンボルは 含まれません)。 ● 列挙順は以下の通りです。 ○ まず配列のキーになり得る数値の文字列を小さい方から列挙します。 ○ それ以外の文字列はオブジェクトのキーの定義順に返します。 ● よって ["2021", "DEV", "MEETUP"] のうちの最後の要素が答えです。

Slide 87

Slide 87 text

Java問題

Slide 88

Slide 88 text

88 自己紹介 ● orekyuu ● 2017年4月新卒入社 ● BOOTH部所属 ● Javaが好きなRailsエンジニア ○ 業務のちょっとしたスクリプトでも Javaで書き始める書くおじさん ○ 好きなIDEはIntelliJ orekyuu

Slide 89

Slide 89 text

1. false/false/false/false 2. true/false/true/true 3. true/true/true/false 4. true/false/true/false Java 1問目 void hoge() { String literalJava = "Java"; final String finalJava = "Java"; final String newJava = new String("Java"); System.out.print("Hello, Java" == "Hello, Java"); System.out.print("/"); System.out.print(("Hello, " + literalJava) == "Hello, Java"); System.out.print("/"); System.out.print(("Hello, " + finalJava) == "Hello, Java"); System.out.print("/"); System.out.print(("Hello, " + newJava) == "Hello, Java"); } hoge();

Slide 90

Slide 90 text

1. false/false/false/false 2. true/false/true/true 3. true/true/true/false 4. true/false/true/false Java 1問目 void hoge() { String literalJava = "Java"; final String finalJava = "Java"; final String newJava = new String("Java"); System.out.print("Hello, Java" == "Hello, Java"); System.out.print("/"); System.out.print(("Hello, " + literalJava) == "Hello, Java"); System.out.print("/"); System.out.print(("Hello, " + finalJava) == "Hello, Java"); System.out.print("/"); System.out.print(("Hello, " + newJava) == "Hello, Java"); } hoge();

Slide 91

Slide 91 text

91 なぜ? ● 同じ文字列のリテラルはプールされるため、参照が等しくなります (1つ目) ● literalJavaとつないだときは新しく文字列が作られるため違うインスタンスになります (2つ 目) ● finalで宣言されたStringはコンパイル時にインライン化されるため、 "Hello, Java"と同等 になるので等しいです(3つ目) ● newされた場合はプールされないため別のインスタンスになります (4つ目) ● Javaの文字列は==で比較せずにequalsメソッドを使って比較しろってことです 😡

Slide 92

Slide 92 text

1. true 2. false 3. 環境によって異なる 4. 実行時エラー Java 2問目 URL hoge = new URL("http://hoge:[email protected]" ); URL fuga = new URL("http://fuga:[email protected]" ); System.out.println(hoge.equals(fuga)) ;

Slide 93

Slide 93 text

1. true 2. false 3. 環境によって異なる 4. 実行時エラー Java 2問目 URL hoge = new URL("http://hoge:[email protected]" ); URL fuga = new URL("http://fuga:[email protected]" ); System.out.println(hoge.equals(fuga)) ;

Slide 94

Slide 94 text

94 なぜ? ● URLのequalsはオーバーライドされていて次の条件に一致する場合 trueを返します ○ 同じプロトコルを持ち ○ 同じホストを参照し ○ 同じホストとは同じIPに解決される ● 名前解決できない場合は大文字小文字に関係なくホスト名が等しいか ● ホスト上のポート番号が同じでファイルとファイルのフラグメントが同じ場合 ● ユーザー名の情報は 等価性に含まれない のでtrueになります

Slide 95

Slide 95 text

1. main.showText();の行で コンパイルエラー 2. void showText(Main Main.this)の行で コンパイルエラー 3. System.out.printlnの行で コンパイルエラー 4. pixivが出力される Java 3問目 public class Main { String text; public static void main(String[] args) { Main main = new Main(); main.text = "pixiv"; main.showText() ; } void showText(Main Main.this) { System. out.println(Main. this.text); } }

Slide 96

Slide 96 text

1. main.showText();の行で コンパイルエラー 2. void showText(Main Main.this)の行で コンパイルエラー 3. System.out.printlnの行で コンパイルエラー 4. pixivが出力される Java 3問目 public class Main { String text; public static void main(String[] args) { Main main = new Main(); main.text = "pixiv"; main.showText() ; } void showText(Main Main.this) { System. out.println(Main. this.text); } }

Slide 97

Slide 97 text

97 なぜ? ● かなりマイナーな構文ですが、非 staticなメソッドではReceiver parameterと呼ばれるも のを定義できます ● Receiver parameterを受け取ってなにかの情報を取ることはできないので無意味なよう に見える構文です ● 嬉しさとしてはここにアノテーションを書くことができるので、コンパイル時に Receiverに対 して何かしらのチェックを走らせたいときに使うらしいです

Slide 98

Slide 98 text

1. 常にtrue 2. 常にfalse 3. 実行ごとに結果が変わる 4. 実行時エラー Java 4問目 boolean prev = true; int matchCount = 0; for (int i = 0; i < 100; i++) { boolean other = new Random(System.currentTimeMillis()) .nextBoolean() ; if (prev == other) matchCount++ ; prev = other; } System.out.println(matchCount > 50);

Slide 99

Slide 99 text

1. 常にtrue 2. 常にfalse 3. 実行ごとに結果が変わる 4. 実行時エラー Java 4問目 boolean prev = true; int matchCount = 0; for (int i = 0; i < 100; i++) { boolean other = new Random(System.currentTimeMillis()) .nextBoolean() ; if (prev == other) matchCount++ ; prev = other; } System.out.println(matchCount > 50);

Slide 100

Slide 100 text

100 なぜ? ● よくよく見るとRandomのシード値がミリ秒になっています ● 現代のマシンでは1ミリ秒の間にループがすべて回ってしまうため同じシード値になってし まう ● Randomは使い回さない + デフォルトコンストラクタを使いましょう

Slide 101

Slide 101 text

ゲスト問題 noko_k

Slide 102

Slide 102 text

1. 実行時例外 2. Hello null 3. 何も出力されない 4. それ以外 Java 5問目 class Words { static String HELLO = "Hello"; static String WORLD = "World"; } Words words = new Words(); "%s %s".formatted(words. HELLO, ((Words) null).WORLD) .chars().forEach(System. out::print);

Slide 103

Slide 103 text

1. 実行時例外 2. Hello null 3. 何も出力されない 4. それ以外 72101108108111328711111 4108100が出力されます Java 5問目 class Words { static String HELLO = "Hello"; static String WORLD = "World"; } Words words = new Words(); "%s %s".formatted(words. HELLO, ((Words) null).WORLD) .chars().forEach(System. out::print);

Slide 104

Slide 104 text

104 なぜ? ● ((Words) null).WORLD の部分については、NullPointerExceptionとなりません。static フィールドの呼び出しは、参照するインスタンスが nullかどうかに関わらず参照することが 出来ます(つまりこの式は"World"になります) ● chars() メソッドは文字列をIntStreamに変換します(CharStreamは存在しません) ● IntStream#forEachはIntConsumerを受け取ります。それによりここで呼び出されるメ ソッドは引数がintのprintメソッドとなります。 ● これにより、実行するとそれぞれの文字を整数表現にした数字がそれぞれ表示されてし まいます。

Slide 105

Slide 105 text

結果発表!