Slide 1

Slide 1 text

2019/3/12 1 セミコロン完全マスター Rust セミコロン完全マスター @qnighy 原 将己 (Wantedly株式会社) shinjuku.rs #3 @FORCIA 2019-03-12

Slide 2

Slide 2 text

2019/3/12 2 セミコロン完全マスター 話す内容 • 最近色々忙しくてRustを書けてないので、いつものように蘊蓄 を話します • セミコロンで迷わなくなります (たぶん)

Slide 3

Slide 3 text

2019/3/12 3 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]

Slide 4

Slide 4 text

2019/3/12 4 セミコロン完全マスター 配列型と繰り返し構文 • 元々は [0, ..42] という構文だったものがRFC0520で変更に なった経緯がある [i32; 42] [0; 42]

Slide 5

Slide 5 text

2019/3/12 5 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]

Slide 6

Slide 6 text

2019/3/12 6 セミコロン完全マスター 宣言マクロの腕 macro_rules! foo { () => { foo!(42) }; ($x:expr) => {}; }

Slide 7

Slide 7 text

2019/3/12 7 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]

Slide 8

Slide 8 text

2019/3/12 8 セミコロン完全マスター なぜセミコロン終端? 終端記号が必須 Rust, C, C++, Java, C#, Perl, Prolog 改行終端が可能 Ruby, Python, JavaScript, Go, Swift, Haskell, VB 終端が不要 OCaml 括弧 Scheme

Slide 9

Slide 9 text

2019/3/12 9 セミコロン完全マスター なぜセミコロン終端? • 最近もURLOにその話題があった https://users.rust- lang.org/t/why-semicolons/25074 • 端的に言えば…… 暗黙のreturnとの相性のため & 構文的な複雑性の回避

Slide 10

Slide 10 text

2019/3/12 10 セミコロン完全マスター 暗黙のreturn { let x = 42; println!("{}", x); x } 文 文 式 (戻り値)

Slide 11

Slide 11 text

2019/3/12 11 セミコロン完全マスター 暗黙のreturn { let x = 42; println!("{}", x); x; } 文 文 文 最後の値を使うかどうかが明確なので、 人間にもコンパイラにも優しいと考えられている

Slide 12

Slide 12 text

2019/3/12 12 セミコロン完全マスター 構文的な複雑性の回避 自動セミコロン挿入は 構文が複雑になりがち ……というようなことが よく主張される

Slide 13

Slide 13 text

2019/3/12 13 セミコロン完全マスター Pythonの改行の扱い • 字句解析のシンプルなルールで記述されている • 原則として改行 = 文終端 • 括弧の中では改行を無視 • 文末がバックスペースなら 続く改行を無視 ……しかし、Pythonは文と式が交互にネストしない という特殊事情がある

Slide 14

Slide 14 text

2019/3/12 14 セミコロン完全マスター JavaScriptの改行の扱い • 構文エラーで駆動(ECMA-262 ECMAScript 2018, §11.9) • 改行位置で構文エラーが起きたら セミコロンを挿入する

Slide 15

Slide 15 text

2019/3/12 15 セミコロン完全マスター Haskellの改行の扱い • 基本は字句解析の仕事だが、 部分的に構文エラーで駆動(Haskell 2010, §2.7) • インデントが同じだったら セミコロンを挿入する • 構文エラーで必要に応じて } を挿入する

Slide 16

Slide 16 text

2019/3/12 16 セミコロン完全マスター 構文的な複雑性の回避 — 私見 自動セミコロン挿入は 構文が複雑になりがち 改行を条件つきで使用する仕組みはどうしても構文全体と 相互作用してしまうので、やはり複雑性のコストは高そう 特にRustのマクロはトークン列を入力とするので難しそう

Slide 17

Slide 17 text

2019/3/12 17 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]

Slide 18

Slide 18 text

2019/3/12 18 セミコロン完全マスター アイテム類とは extern crate, mod, use, impl, trait, type, struct, enum, static, const, fn const, type, fn 真正なアイテム ルートや mod 内に書ける トレイトアイテム trait {} 内に書ける const, type, fn 実装アイテム impl {} 内に書ける static, type, fn 外部アイテム extern {} 内に書ける など

Slide 19

Slide 19 text

2019/3/12 19 セミコロン完全マスター アイテム類の終端記号 ; OR 排他規則 {} struct Color { red: u8; green: u8; blue: u8; } struct Color(u8, u8, u8);

Slide 20

Slide 20 text

2019/3/12 20 セミコロン完全マスター アイテム類の終端記号 ; OR 排他規則…の例外? {} use serde::{Deserialize, Serialize};

Slide 21

Slide 21 text

2019/3/12 21 セミコロン完全マスター アイテム類の終端記号 ; OR 排他規則…の例外? {} use serde::{Deserialize, Serialize}; use serde::*; } はuse構文自体に由来するものではない 引数の一部としてたまたま出てきただけ ……と解釈されている

Slide 22

Slide 22 text

2019/3/12 22 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]

Slide 23

Slide 23 text

2019/3/12 23 セミコロン完全マスター 復習: 暗黙のreturn { let x = 42; println!("{}", x); x } 文 文 式 (戻り値) セミコロン終端 = その値を使わない という解釈 ブロック末尾以外はセミコロンが来ない??

Slide 24

Slide 24 text

2019/3/12 24 セミコロン完全マスター 文終端の原則 文は原則としてセミコロンで終端する。 しかし…… ➢ 暗黙のreturn のためには最終文のセミコロンの省略が必須。 文は式文なら何でもよい。 ➢ {} OR ; 排他規則 のために文のセミコロンの省略が可能。 文は特定のブロック式である必要がある。 型は () である必要がある。

Slide 25

Slide 25 text

2019/3/12 25 セミコロン完全マスター 末尾以外のセミコロン省略 if true { 42; } else { 53; }; println!("Hello!"); どちらか片方は残す必要がある。 セミコロンがなければ 型がついてしまうからだ。

Slide 26

Slide 26 text

2019/3/12 26 セミコロン完全マスター 接頭辞禁止規則 x = if true { 42 } else { 53 } println!("Hello!"); ここで区切っても if文にはならない

Slide 27

Slide 27 text

2019/3/12 27 セミコロン完全マスター セミコロン省略規則の罠 if true { 42 } else { 53 } - 1; println!("Hello!"); これはコンパイルが通らない。 中置・前置演算子を式文として使うことは ほぼないので、気にすることはあまりない

Slide 28

Slide 28 text

2019/3/12 28 セミコロン完全マスター マクロとセミコロン マクロ呼び出しの構文は文脈によって微妙に異なる アイテム類マクロ 文マクロ 式類マクロ foo!(); foo![]; foo!{} foo!(); foo![]; foo!{}; foo!() foo![] foo!{} foo!{} セミコロンあり セミコロンなし foo! ident (); foo! ident []; foo! ident {} マクロ定義用構文 ※ () と [] は完全互換

Slide 29

Slide 29 text

2019/3/12 29 セミコロン完全マスター アイテム類マクロ macro_rules! foo { ($x:ident) => { fn $x() {} } } foo!(f1); foo![f2]; foo! { f3 } {} OR ; 排他規則で説明できる

Slide 30

Slide 30 text

2019/3/12 30 セミコロン完全マスター 式類マクロ macro_rules! foo { () => { 42 } } (foo!()); (foo![]); (foo!{}); セミコロンをつけないので 全部同じ

Slide 31

Slide 31 text

2019/3/12 31 セミコロン完全マスター これは? fn main() { dbg!(42); let x = dbg!(42); } 文マクロ 式マクロ

Slide 32

Slide 32 text

2019/3/12 32 セミコロン完全マスター 文マクロの展開規則 fn main() { dbg! { 42 } // Bad! dbg! { 42 }; // Good! dbg!(42); // Good! } セミコロンがついたときは、 展開後の文リストの最後の文に セミコロンを付加する ※RustのマクロはASTの構造に沿って行われるので、 「セミコロンを付加する」というのは特例的な操作になる

Slide 33

Slide 33 text

2019/3/12 33 セミコロン完全マスター まとめと宣伝 セミコロンひとつとっても色々な設計判断が見える • {} OR ; 排他規則 • 暗黙のreturnのための規則 • 文マクロと式マクロが整合するための規則 • etc...

Slide 34

Slide 34 text

2019/3/12 34 セミコロン完全マスター まとめと宣伝 こういう蘊蓄をまとめた本を作っています 技術書典に出せるよう計画中!