Slide 1

Slide 1 text

Go に Generics がやってきた!
 Smith
 [
 ]


Slide 2

Slide 2 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 3

Slide 3 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 4

Slide 4 text

@dolow 自己紹介
 smith := &Employee[Drecom]{ Divisions: []Division{ Division{“BtoB事業本部”, “AROW部”}, Division{“SRE部”, “クライアントグループ”}, }, RecentTechs: []Tech{ techs.GeospacialInformation, techs.Blockchain, techs.GeneralWebApp, }, Books: []Book{ Book{“HTML5 ゲーム開発の教科書”, “ボーンデジタル社”}, } } @do_low

Slide 5

Slide 5 text

@dolow 自己紹介
 smith := &Employee[Drecom]{ Divisions: []Division{ Division{“BtoB事業本部”, “AROW部”}, Division{“SRE部”, “クライアントグループ”}, }, RecentTechs: []Tech{ techs.GeospacialInformation, techs.Blockchain, techs.GeneralWebApp, }, Books: []Book{ Book{“HTML5 ゲーム開発の教科書”, “ボーンデジタル社”}, } } @do_low ??


Slide 6

Slide 6 text

ミッション
 プロダクトのクライアント技術領域における信頼性向上。
 (とはいえ、1~2名体制なので出来る範囲で)
 よくある業務
 ● 協業パートナー技術選定
 ● メンバー不定のプロジェクトの技術ディレクション
 ● 及びテクニカルスパイクの解決
 SRE クライアントグループ?


Slide 7

Slide 7 text

● 自己紹介
 ● 本発表の主な対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 8

Slide 8 text

本発表の主な対象者
 基本的には初学者を想定した易しめな内容です。
 下記に当てはまる方は、今回の発表内容はちょうど良いと思います。
 ● 「どうも、動的型付けの世界から来ました!」
 ● 「Go で Hello World しました!」
 ● 「Generics ってなんですか!」
 
 全体的に甘口の発表ですが、辛口なところは唐辛子マーク を付けています。
 唐辛子マークの内容は TIPS みたいなものです。


Slide 9

Slide 9 text

本発表を通して、下記をそこはかとなく感じていただければ幸いです。
 ● インターフェースや多態性の必要性
 ● 静的型付け言語ならではの多態性表現
 ● 言語仕様としての表現力の大切さ
 本発表の主な対象者


Slide 10

Slide 10 text

Go に Generics がやってきた!
 [
 ]


Slide 11

Slide 11 text

でも、Go の話はほとんどないです!
 [
 ]
 ブフォ


Slide 12

Slide 12 text

Go に Generics がやってきた!
 
 
 


Slide 13

Slide 13 text

Go に Generics がやってきた!
 
 けど特別なことは何もなかったので、 
 静的型付けとかポリモーフィズムとか interface あたりについておさらいしようじゃないか 


Slide 14

Slide 14 text

「・・・」


Slide 15

Slide 15 text

「Go ってなに?」


Slide 16

Slide 16 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 17

Slide 17 text

ありきたりな情報は ggrks
 個人的に好きなところを 3つ挙げると・・・
 Go ってなんだっけ
 1. もちろん、静的型付けなところ!
 2. クロスコンパイルが超絶楽ちん!
 3. defer, goroutine, channel とかのゆとり厨二要素が沢山!


Slide 18

Slide 18 text

Go にはこんな使い方もあるぞ
 ● switch 対応で go2cpp が生み出された
 ● WASM 以外のシングルスレッドのランタイムにも期待 (なお需要)
 https://tech.drecom.co.jp/ac2021-go-cgo-c-php/


Slide 19

Slide 19 text

● ドリコムではもともと Ruby on Rails が主流だったけど
 ● いまどき Ruby on Rails だけできててもヤバいだろってなった
 ● 機会さえあれば Go を採用するようになった
 ● ので、そんなに歴史は深くない
 
 という背景から、社内ではサーバ用言語としての文脈が主です。
 とはいえクライアントの観点からでもポテンシャルに溢れています。
 Go in Drecom


Slide 20

Slide 20 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 21

Slide 21 text

「・・・」


Slide 22

Slide 22 text

「静的型付けってなに?」


Slide 23

Slide 23 text

逆に動的型付けから見ていこう


Slide 24

Slide 24 text

JavaScript (動的型付け言語)
 const dog = {}; dog.name = “John” dog.greet = () => “bowwow”;

Slide 25

Slide 25 text

JavaScript (動的型付け言語)
 const dog = {}; dog.name = “John” dog.greet = () => “bowwow”; 何が入るかも決まっていない空のオブジェクトに、
 後から自由にプロパティを定義できる。


Slide 26

Slide 26 text

JavaScript (動的型付け言語)
 const dog = {}; dog.name = “John” dog.greet = () => “bowwow”; 何が入るかも決まっていない空のオブジェクトに、
 後から自由にプロパティを定義できる。
 JavaScript は動的型付け言語ですが、こ れを静的型付けっぽく記述してみると・・・


Slide 27

Slide 27 text

JavaScript (動的型付け言語)
 const dog = {}; dog.name = “John” dog.greet = () => “bowwow”; 静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John”; dog.greet = () => “bowwow”; 何が入るかも決まっていない空のオブジェクトに、
 後から自由にプロパティを定義できる。


Slide 28

Slide 28 text

JavaScript (動的型付け言語)
 const dog = {}; dog.name = “John” dog.greet = () => “bowwow”; 静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John”; dog.greet = () => “bowwow”; 何が入るかも決まっていない空のオブジェクトに、
 後から自由にプロパティを定義できる。
 オブジェクト定義の時点で、予め name や greet というプロ パティを定義し、想定する型のゼロ値をアサインする。


Slide 29

Slide 29 text

JavaScript (動的型付け言語)
 const dog = {}; dog.name = “John” dog.greet = () => “bowwow”; 静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John”; dog.greet = () => “bowwow”; // でもこういうことできちゃう dog.offend = () => “bark!”; dog.name = [“John”, “Joe”]; 何が入るかも決まっていない空のオブジェクトに、
 後から自由にプロパティを定義できる。


Slide 30

Slide 30 text

静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John” dog.greet = () => “bowwow”; // でもこういうことできちゃう dog.offend = () => “bark!”; dog.name = [“John”, “Joe”];

Slide 31

Slide 31 text

Q. できちゃうことの何がダメなの?
 A. そのオブジェクトが確実に持っている プロパティやその型がわからない。
 関数の引数などで間接的にオブジェ クトが受け渡された時、利用したいプ ロパティをいちいち検証しなければな らない。
 静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John” dog.greet = () => “bowwow”; // でもこういうことできちゃう dog.offend = () => “bark!”; dog.name = [“John”, “Joe”];

Slide 32

Slide 32 text

静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John” dog.greet = () => “bowwow”; // でもこういうことできちゃう dog.offend = () => “bark!”; dog.name = [“John”, “Joe”]; もしもそれができちゃうのが問題と感じる のなら、その時は静的型付け言語の TypeScript の出番!


Slide 33

Slide 33 text

静的型付け風に書いた JavaScript
 const dog = { name: “”, greet: () => {}, }; dog.name = “John” dog.greet = () => “bowwow”; // でもこういうことできちゃう dog.offend = () => “bark!”; dog.name = [“John”, “Joe”]; もしもそれができちゃうのが問題と感じる のなら、その時は静的型付け言語の TypeScript の出番!
 できない!させない!


Slide 34

Slide 34 text

ちょうざっくりまとめ
 ● 静的型付けではプログラム中で扱うデータ構造やデータ型は予め宣言する
 ● 宣言に違反する場合はコンパイル時にエラーを出してくれる
 ● これすなわち型安全
 ● (TypeScript がこんなに普及しているとは、つまりそういうことだ)
 静的型付け
 ● 動的型付け言語でプログラミングできるエンジニアはすごいと思う


Slide 35

Slide 35 text

コラム: AppStore でリリースするアプリバイナリは AOT じゃないとダメ。 
 実行時に振る舞いが変えられるようなものはセキュリティ観点から NG です。 ● 代表的な静的型付け言語は、AOT (Ahead Of Time) コンパイル
 ● AOT コンパイルを通してプログラムを実行可能形式のバイナリにする
 ○ C/C++ とか とか とか 
 ● プログラム内の型に関する情報をコンパイル時点で検証する
 ● 型に関する食い違いが検知されれば、コンパイルは失敗する
 おまけ: コンパイル


Slide 36

Slide 36 text

おまけ: コンパイル
 ● 反対に、プログラム実行中に逐次コンパイルを行うのが JIT (Just In Time) コンパ イル
 ● 例えばコード上で静的に記述されたクラスに対してランタイムでメソッドを追加する などができる
 ● JavaScript も、 V8 などの JavaScript エンジンによってランタイムで JIT コンパイ ルされている
 ○ V8 は Chromium などに使われている Google 製 JavaScript エンジン 
 ○ 興味があれば V8 の Hidden Class あたりを調べてみてください 
 ● TypeScript のトランスパイルは AOT 的役割を果たすが、ランタイムは JavaScript


Slide 37

Slide 37 text

● 動的型付けは好きなタイミングで好きなようにオブジェクトを定義できる
 ● 静的型付けでは予め宣言された型の使い方以外は許容できない
 ● 静的型付けは実行前に予め実行可能形式にコンパイルする
 ● 動的型付けと静的型付けではプログラミングの書き方が大きく変わる
 
 次項からポリモーフィズムを例に、もう少し違いを深堀りしていこう。
 徐々に本日の主題の Generics に近づいてくぞ。
 2つのタイプの言語を見比べてざっくりわかったこと


Slide 38

Slide 38 text

「・・・」


Slide 39

Slide 39 text

「ポリモ・・・なに?」


Slide 40

Slide 40 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 41

Slide 41 text

ポリモーフィズム(多態性)
 おさかな
 ● 泳ぐ
 ● 卵を生む
 ● エラ呼吸する


Slide 42

Slide 42 text

ポリモーフィズム(多態性)
 カクレクマノミです


Slide 43

Slide 43 text

ポリモーフィズム(多態性)
 カクレクマノミです
 エイです


Slide 44

Slide 44 text

ポリモーフィズム(多態性)
 カクレクマノミです
 エイです
 マンボゥォェェ--!!!


Slide 45

Slide 45 text

ポリモーフィズム(多態性)
 「おさかな」
 カクレクマノミです
 エイです
 マンボゥォェェ--!!!


Slide 46

Slide 46 text

ポリモーフィズム(多態性)
 プログラム的には
 
 ● 「おさかな」 → interface
 ● 「マンボゥォェェーー!!!」 → interface の実装
 


Slide 47

Slide 47 text

ポリモーフィズム(多態性)
 ユースケース的には
 
 ● 「おさかな」 → 魚なら何でもいい時
 ● 「マンボゥォェェーー!!!」 → マンボウじゃないとダメな時
 


Slide 48

Slide 48 text

ポリモーフィズム(多態性)
 function 水揚げ量():number { const fishes: おさかな[] = getFishes(); return fishes.length; } function マンボウの生息数():number { const fishes: [] = getFishes(“manbo”); return fishes.length; } 魚ならなんでもいい
 getFishes()
 マンボウが欲しい
 getFishes()


Slide 49

Slide 49 text

ポリモーフィズムとは・・・
 インターフェースに準拠した多種多様な定義があること。
 e.g) おさかなというインターフェースの特性を満たした
 カクレクマノミ、エイ、マンボウ
 
 仕事の内容によって求められるおさかなの具体性が異なるユースケース が共存する時、ポリモーフィズムの担保が求められる。
 ポリモーフィズム(多態性)


Slide 50

Slide 50 text

ポリモーフィズムの担保とは
 インターフェーズに基いた多態性を実現しつつ、多態的なエンティティや 関数、クラスなどを一元的に利用可能にすること
 ポリモーフィズムの担保
 const = getFIsh(“nemo”); const = getFIsh(“ei”); const = getFIsh(“manbo”); putFish( ); putFish( ); putFish( ); 要は、一個の関数で沢山の型が使えたらいいよね、ってのを実現するなどのこと。 


Slide 51

Slide 51 text

ダックタイピング
 ● greet したら、それが greet するもの
 ● greet できればその実体はなんでも良い
 ● 関数利用者は greet するものを渡せばよい
 ポリモーフィズムの担保 (動的型付け言語での例)
 const dog = { greet: () => "bowwow", } const cat = { greet: () => "meow", } function polyGreet(someone) { console.log(someone.greet()); } polyGreet(dog); polyGreet(cat); 注) 左記はとりあえず greet を実行しているだけなので、意図的 なポリモーフィズムかどうかはコードからは読み取れない。 


Slide 52

Slide 52 text

type Dog struct {} type Cat struct {} func (Dog) Greet() string { return “bowwow” } func (Cat) Greet() string { return “meow” } func polyGreet(maybeGreet interface{}) { // コンパイルエラー fmt.Printf("%s\n", maybeGreet.Greet()); } ダックタイピングを静的型付けの でやると・・・


Slide 53

Slide 53 text

Go には「どんな型でも OK !」という意味の interface{} 型が 用意されており、引数型が決定的でない場合は interface{} での定義ができる
 type Dog struct {} type Cat struct {} func (Dog) Greet() string { return “bowwow” } func (Cat) Greet() string { return “meow” } func polyGreet(maybeGreet interface{}) { // コンパイルエラー fmt.Printf("%s\n", maybeGreet.Greet()); } ダックタイピングを静的型付けの でやると・・・
 しかし interface{} 型は、具体的な構造体のインターフェース を持たないためコンパイルエラーになる。
 (この厳格さは TypeScript の any とは異なる)


Slide 54

Slide 54 text

静的型付け言語でポリモーフィズムを担保する一般的な手法はある。
 
 ● interface とその実装
 ● generics
 ● 抽象クラス & クラス継承
 ● embedded (Go)
 ● template (C++)
 
 静的型付け言語でのポリモーフィズム担保


Slide 55

Slide 55 text

静的型付け言語でポリモーフィズムを担保する一般的な手法はある。
 
 ● interface とその実装
 ● generics <- やっと出てきたな
 ● 抽象クラス & クラス継承
 ● embedded (Go)
 ● template (C++)
 
 静的型付け言語でのポリモーフィズム担保


Slide 56

Slide 56 text

(ちょっと話逸れるけど)


Slide 57

Slide 57 text

静的型付けでも例外的にダックタイピング class Human { public string Greet() { return “hello”; } } public class Main : MonoBehavior { void ImplicitGreet(dynamic maybeGreet) { Debug.Log(maybeGreet.Greet()); } void Start() { ImplicitGreet(new Human()); } } class Human { public greet(): string { return "hello"; } } function implicitGreet(maybeGreet: any) { console.log(maybeGreet.greet()); } implicitGreet(new Human()); // hello TypeScript
 根は JavaScript なので。
 
 C#
 言語仕様としてサポート(?) 
 内部的に reflection で JIT コンパイル。 
 (C# 詳しくないです、すいません) 


Slide 58

Slide 58 text

て、template… void greet(Dog* subject) { std::cout << subject->greet() << std::endl; } void greet(Cat* subject) { std::cout << subject->greet() << std::endl; } #include class Dog { public: std::string greet() { return "bowwow"; } }; class Cat { public: std::string greet() { return "meow"; } }; template void greet(T subject) { std::cout << subject->greet() << std::endl; } int main(const int argc, const char** argv) { greet(new Dog()); greet(new Cat()); } こう書いたら
 こうなる(イメージ)
 C++ には template 呼ばれる仕様が用意さ れている。
 Generics のコンセプトが型の制約なら、 template のコンセプトは型に基づいて定義 を量産すること。(名前通り)
 結果的に、構文上はダックタイピングに見 える。


Slide 59

Slide 59 text

(意外とできたわ、ごめん)
 型破りなので、型を覚えてから適切に使ってください。 
 C++ の template はまたちょっと違う派閥です。 


Slide 60

Slide 60 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 61

Slide 61 text

関数や構造体が型パラメーターを持てること。
 型パラメーターを通して単一の関数や構造体を複数の型で実行できること。
 Generics ってなんだっけ
 function print(v: T) { console.log(v); } 宣言側
 const i: number = 123; print(i); const s: string = “abc”; print(s); 利用者側


Slide 62

Slide 62 text

Generics ってなんだっけ
 ありきたりな情報は ggrks
 私見を 3行で述べると
 ● 型パラメータで多態性を一元的に利用できる仕様 (パラメトリック)
 ● キャストするより全然マシ
 ● interface をより強力にするモノ
 /> どうでもいいけど、JSX だと 
 なんかちょっとモヤっとしません? 


Slide 63

Slide 63 text

Interface だけじゃだめな時
 const repo: Repository = open(“mysql”); repo.put(obj); interface Repository { open(); put(); ... } class MySql implements Repository { ... show() { ... } } 抽象的で良い場合もあるが・・・


Slide 64

Slide 64 text

Interface だけじゃだめな時
 const repo: Repository = open(“mysql”); repo.put(obj); interface Repository { open(); put(); ... } class MySql implements Repository { ... show() { ... } } const repo: Repository = open(“mysql”); // MySql 特異のメソッドを使いたいときは? repo.show(obj); 抽象的で良い場合もあるが・・・
 具体的に使いたいケースでは満たせない


Slide 65

Slide 65 text

Interface だけじゃだめな時
 const repo: Repository = open(“mysql”); (repo as MySql).put(obj); const repo: MySql = openMySql(); const repo: MySql = open(); キャストしたり個別関数を用意したり することでも回避はできる。
 Generics であればスマートにポリ モーフィズムを担保できる。


Slide 66

Slide 66 text

Generics と interface を組み合わせると実装の意味が伝わりやすくなる。
 そして何より、コンパイル時間で検証される。
 組み合わせると強力!
 function open(): T { const repo = createRepository(); repo.open(); return repo; } const repo: MySql = open(); repo.put(obj);

Slide 67

Slide 67 text

Generics と interface を組み合わせると実装の意味が伝わりやすくなる。
 そして何より、コンパイル時間で検証される。
 組み合わせると強力!
 function open(): T { const repo = createRepository(); repo.open(); return repo; } ● open の対象の性質が一目瞭然 
 ● Repository の実装以外はコンパイルで 弾かれる
 const repo: MySql = open(); repo.put(obj); ● MySql という具体的な知識を持って いてよいことが分かる


Slide 68

Slide 68 text

● 自己紹介
 ● 本資料の対象者
 ● Go ってなんだっけ
 ● 静的型付けってなんだっけ
 ● ポリモーフィズムってなんだっけ
 ● Generics ってなんだっけ
 ● Generics のなかった Go
 ● まとめ
 AGENDA


Slide 69

Slide 69 text

やっと Go のはなし


Slide 70

Slide 70 text

func Print(int v) { fmt.Printf(“%d\n”, v) } func Print(float v) { fmt.Printf(“%f\n”, v) } func Print(string v) { fmt.Printf(“%s\n”, v) } には generics がなかった!
 しかも同じ関数名は NG!
 func PrintInt(int v) { fmt.Printf(“%d\n”, v) } func PrintFloat(float v) { fmt.Printf(“%f\n”, v) } func PrintString(string v) { fmt.Printf(“%s\n”, v) } 涙ぐましい努力が必要!


Slide 71

Slide 71 text

type Users []*User func (l Users) Find(id uint) *User { for _, user := range l { if user.GetID() == id { return user } } return nil } 複数型共通処理を
 type Books []*Book func (l Books) Find(id uint) *Book { for _, book := range l { if book.GetID() == id { return book } } return nil } 具体的な型で量産
 には generics がなかった!
 任意処理を複数型でも一元的に利用するシンプルな方法がなかった。
 (だからコード生成をするといソリューションが多いように感じる)


Slide 72

Slide 72 text

func Find(id uint, items []interface{}) *interface{} { for _, item := range items { value := reflect.ValueOf(item) method := value.MethodByName("GetID") result := method.Call([]reflect.Value{}) if result[0].Uint() == id { return &item } } return nil } やろうと思えば interface{} & reflection でできるけど
 コンパイル時間で問題が検知できないのでとてもやりたくない。
 e.g) メソッド名が変わったり返り値の型が変わっても検知できない


Slide 73

Slide 73 text

var users Records[User] ... user := users.Find(uint(1)) fmt.Printf("%v\n", user.GetID()) それが今じゃあ超絶楽ちん
 type Record interface { GetID() uint } type Records[T Record] []*T func (l Records[T]) Find(id uint) *T { for _, item := range l { if (*item).GetID() == id { return item } } return nil } 一回書くだけで OK !


Slide 74

Slide 74 text

Generics, 来てくれてありがとう!
 [
 ]


Slide 75

Slide 75 text

の Generics は 1.18 から
 2月に 1.18 はリリースされる予定だったけど、まだ RC。
 docker で 1.18 RC イメージはあるので気軽に試してみよう。
 
 https://hub.docker.com/_/golang


Slide 76

Slide 76 text

まとめ
 ● AOT コンパイルにおいて型は厳格にチェックされる
 ● 型のポリモーフィズム表現手法として interface や generics がある
 ● interface では具体的な型を扱いたい場合に苦しい場面がある
 ● 具体的な型として利用する手法に generics がある
 ● Go には generics がなかった
 ● しかし遂に go 1.18 で generics が提供予定!


Slide 77

Slide 77 text

ご清聴ありがとうございました
 [
 ]