Pro Yearly is on sale from $80 to $50! »

セミコロン完全マスター

 セミコロン完全マスター

セミコロンに関する蘊蓄です

Ba655e3712aaabfbca289fe136f85fe4?s=128

Masaki Hara

March 12, 2019
Tweet

Transcript

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

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

  3. 2019/3/12 3 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x

    = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]
  4. 2019/3/12 4 セミコロン完全マスター 配列型と繰り返し構文 • 元々は [0, ..42] という構文だったものがRFC0520で変更に なった経緯がある

    [i32; 42] [0; 42]
  5. 2019/3/12 5 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x

    = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]
  6. 2019/3/12 6 セミコロン完全マスター 宣言マクロの腕 macro_rules! foo { () => {

    foo!(42) }; ($x:expr) => {}; }
  7. 2019/3/12 7 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x

    = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]
  8. 2019/3/12 8 セミコロン完全マスター なぜセミコロン終端? 終端記号が必須 Rust, C, C++, Java, C#,

    Perl, Prolog 改行終端が可能 Ruby, Python, JavaScript, Go, Swift, Haskell, VB 終端が不要 OCaml 括弧 Scheme
  9. 2019/3/12 9 セミコロン完全マスター なぜセミコロン終端? • 最近もURLOにその話題があった https://users.rust- lang.org/t/why-semicolons/25074 • 端的に言えば……

    暗黙のreturnとの相性のため & 構文的な複雑性の回避
  10. 2019/3/12 10 セミコロン完全マスター 暗黙のreturn { let x = 42; println!("{}",

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

    x); x; } 文 文 文 最後の値を使うかどうかが明確なので、 人間にもコンパイラにも優しいと考えられている
  12. 2019/3/12 12 セミコロン完全マスター 構文的な複雑性の回避 自動セミコロン挿入は 構文が複雑になりがち ……というようなことが よく主張される

  13. 2019/3/12 13 セミコロン完全マスター Pythonの改行の扱い • 字句解析のシンプルなルールで記述されている • 原則として改行 = 文終端

    • 括弧の中では改行を無視 • 文末がバックスペースなら 続く改行を無視 ……しかし、Pythonは文と式が交互にネストしない という特殊事情がある
  14. 2019/3/12 14 セミコロン完全マスター JavaScriptの改行の扱い • 構文エラーで駆動(ECMA-262 ECMAScript 2018, §11.9) •

    改行位置で構文エラーが起きたら セミコロンを挿入する
  15. 2019/3/12 15 セミコロン完全マスター Haskellの改行の扱い • 基本は字句解析の仕事だが、 部分的に構文エラーで駆動(Haskell 2010, §2.7) •

    インデントが同じだったら セミコロンを挿入する • 構文エラーで必要に応じて } を挿入する
  16. 2019/3/12 16 セミコロン完全マスター 構文的な複雑性の回避 — 私見 自動セミコロン挿入は 構文が複雑になりがち 改行を条件つきで使用する仕組みはどうしても構文全体と 相互作用してしまうので、やはり複雑性のコストは高そう

    特にRustのマクロはトークン列を入力とするので難しそう
  17. 2019/3/12 17 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x

    = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]
  18. 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 {} 内に書ける など
  19. 2019/3/12 19 セミコロン完全マスター アイテム類の終端記号 ; OR 排他規則 {} struct Color

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

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

    Serialize}; use serde::*; } はuse構文自体に由来するものではない 引数の一部としてたまたま出てきただけ ……と解釈されている
  22. 2019/3/12 22 セミコロン完全マスター セミコロンの用途 アイテム類の終端記号 fn foo(); 文の終端記号 let x

    = 42; 配列 宣言マクロの腕 ($e:expr) => { $e * 2 }; [i32; 42] [0; 42]
  23. 2019/3/12 23 セミコロン完全マスター 復習: 暗黙のreturn { let x = 42;

    println!("{}", x); x } 文 文 式 (戻り値) セミコロン終端 = その値を使わない という解釈 ブロック末尾以外はセミコロンが来ない??
  24. 2019/3/12 24 セミコロン完全マスター 文終端の原則 文は原則としてセミコロンで終端する。 しかし…… ➢ 暗黙のreturn のためには最終文のセミコロンの省略が必須。 文は式文なら何でもよい。

    ➢ {} OR ; 排他規則 のために文のセミコロンの省略が可能。 文は特定のブロック式である必要がある。 型は () である必要がある。
  25. 2019/3/12 25 セミコロン完全マスター 末尾以外のセミコロン省略 if true { 42; } else

    { 53; }; println!("Hello!"); どちらか片方は残す必要がある。 セミコロンがなければ 型がついてしまうからだ。
  26. 2019/3/12 26 セミコロン完全マスター 接頭辞禁止規則 x = if true { 42

    } else { 53 } println!("Hello!"); ここで区切っても if文にはならない
  27. 2019/3/12 27 セミコロン完全マスター セミコロン省略規則の罠 if true { 42 } else

    { 53 } - 1; println!("Hello!"); これはコンパイルが通らない。 中置・前置演算子を式文として使うことは ほぼないので、気にすることはあまりない
  28. 2019/3/12 28 セミコロン完全マスター マクロとセミコロン マクロ呼び出しの構文は文脈によって微妙に異なる アイテム類マクロ 文マクロ 式類マクロ foo!(); foo![];

    foo!{} foo!(); foo![]; foo!{}; foo!() foo![] foo!{} foo!{} セミコロンあり セミコロンなし foo! ident (); foo! ident []; foo! ident {} マクロ定義用構文 ※ () と [] は完全互換
  29. 2019/3/12 29 セミコロン完全マスター アイテム類マクロ macro_rules! foo { ($x:ident) => {

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

    42 } } (foo!()); (foo![]); (foo!{}); セミコロンをつけないので 全部同じ
  31. 2019/3/12 31 セミコロン完全マスター これは? fn main() { dbg!(42); let x

    = dbg!(42); } 文マクロ 式マクロ
  32. 2019/3/12 32 セミコロン完全マスター 文マクロの展開規則 fn main() { dbg! { 42

    } // Bad! dbg! { 42 }; // Good! dbg!(42); // Good! } セミコロンがついたときは、 展開後の文リストの最後の文に セミコロンを付加する ※RustのマクロはASTの構造に沿って行われるので、 「セミコロンを付加する」というのは特例的な操作になる
  33. 2019/3/12 33 セミコロン完全マスター まとめと宣伝 セミコロンひとつとっても色々な設計判断が見える • {} OR ; 排他規則

    • 暗黙のreturnのための規則 • 文マクロと式マクロが整合するための規則 • etc...
  34. 2019/3/12 34 セミコロン完全マスター まとめと宣伝 こういう蘊蓄をまとめた本を作っています 技術書典に出せるよう計画中!