Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Zig なんもわからん 〜あるいは学びのモチベーション〜

Smith
October 19, 2022

Zig なんもわからん 〜あるいは学びのモチベーション〜

2022/10/16 に開催した Drecom Tech Day での登壇資料です。

Smith

October 19, 2022
Tweet

More Decks by Smith

Other Decks in Technology

Transcript

  1. Smith
 BtoB 事業本部 AROW部
 • 部長
 • プロデューサー
 • エンジニア


    SRE部 クライアントグループ
 • グループ長
 • 御用聞き
 わたしはだれ?
 @dolow
 @do_low

  2. ってなんですか?
 まずはこれを見て欲しい。
 これ、なんと・・・見た目通りに処理されるんです。
 var a = b + c.d; foo();

    var(); 演算子オーバーロードなんてない! 
 プロパティアクセスに見せかけたアクセサがない! 

  3. ってなんですか?
 まずはこれを見て欲しい。
 これ、なんと・・・見た目通りに処理されるんです。
 var a = b + c.d; foo();

    var(); 演算子オーバーロードなんてない! 
 プロパティアクセスに見せかけたアクセサがない! 
 勝手に例外起こして変な所でキャッチされない! 

  4. ってなんですか?
 まずはこれを見て欲しい。
 これ、なんと・・・見た目通りに処理されるんです。
 var a = b + c.d; foo();

    var(); 演算子オーバーロードなんてない! 
 プロパティアクセスに見せかけたアクセサがない! 
 勝手に例外起こして変な所でキャッチされない! 
 だから絶対実行されるやーつ! 

  5. ってなんですか?
 まずはこれを見て欲しい。
 これ、なんと・・・見た目通りに処理されるんです。
 var a = b + c.d; foo();

    var(); 演算子オーバーロードなんてない! 
 プロパティアクセスに見せかけたアクセサがない! 
 勝手に例外起こして変な所でキャッチされない! 
 だから絶対実行されるやーつ! 
 B-E-A-Utiful !!!

  6. ってなんですか?
 あとこれも見て欲しい。
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; }
  7. ってなんですか?
 あとこれも見て欲しい。
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; } • 無名の構造体を返せるのね 

  8. ってなんですか?
 あとこれも見て欲しい。
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; } • 無名の構造体を返せるのね 
 • 引数は型、なるほど、これはジェネリッ クみたいなもんね

  9. ってなんですか?
 あとこれも見て欲しい。
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; } • 無名の構造体を返せるのね 
 • 引数は型、なるほど、これはジェネリッ クみたいなもんね
 • init は静的メソッドみたいなもんで、これ で MyType のインスタンスが作られるの ね

  10. ってなんですか?
 あとこれも見て欲しい。
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; } • 無名の構造体を返せるのね 
 • 引数は型、なるほど、これはジェネリッ クみたいなもんね
 • init は静的メソッドみたいなもんで、これ で MyType のインスタンスが作られるの ね
 ここまでは「ほーん」って感じだけど。

  11. ってなんですか?
 fn sum(my_type: MyType(u8)) u8 { return my_type.get() + 10;

    } test "value as type" { const t = MyType(u8).init(10); const v: u8 = 20; try std.testing.expectEqual(v, sum(t)); } んで、これはさっきの MyType を使った 実装ね・・・

  12. ってなんですか?
 fn sum(my_type: MyType(u8)) u8 { return my_type.get() + 10;

    } test "value as type" { const t = MyType(u8).init(10); const v: u8 = 20; try std.testing.expectEqual(v, sum(t)); } んで、これはさっきの MyType を使った 実装ね・・・
 
 ・・・ん!?

  13. ってなんですか?
 fn sum(my_type: MyType(u8)) u8 { return my_type.get() + 10;

    } test "value as type" { const t = MyType(u8).init(10); const v: u8 = 20; try std.testing.expectEqual(v, sum(t)); } んで、これはさっきの MyType を使った 実装ね・・・
 
 ・・・ん!?

  14. ってなんですか?
 fn sum(my_type: MyType(u8)) u8 { return my_type.get() + 10;

    } test "value as type" { const t = MyType(u8).init(10); const v: u8 = 20; try std.testing.expectEqual(v, sum(t)); } んで、これはさっきの MyType を使った 実装ね・・・
 
 ・・・ん!?
 
 あ、値が型ーー!?!?
 アイエエー!!ニンジャナンデ!?

  15. ってなんですか?
 コンパイル時間で型解決してくれるスグレモノ!
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; } fn sum(my_type: MyType(u8)) u8 { return my_type.get() + 10; } test "value as type" { const t = MyType(u8).init(10); const v: u8 = 20; try std.testing.expectEqual(v, sum(t)); }
  16. ってなんですか?
 コンパイル時間で型解決してくれるスグレモノ!
 fn MyType(comptime T: type) type { return struct

    { const Self = @This(); v: T, pub fn init(v: T) Self { return Self{ .v = v }; } pub fn get(self: Self) T { return self.v; } }; } fn sum(my_type: MyType(u8)) u8 { return my_type.get() + 10; } test "value as type" { const t = MyType(u8).init(10); const v: u8 = 20; try std.testing.expectEqual(v, sum(t)); } B-E-A-Utiful !!!

  17. Install and Hello World
 最初は必ず Hello World をする。
 Hello World

    の達成には次の効果がある。
 • やった感を得られる
 • 開発イテレーションが回せるようになる
 • もっと触りたくなる
 • これさえできなかったら根本的な何かがおかしいと気付ける
 • 完全に理解したと言っても過言ではない (過言)
 一気に難しいことをやろうとすると挫ける。
 繰り返します、最初は必ず Hello World しましょう。

  18. での Hello World は、とくに詰まらずにできた。
 Install and Hello World
 const std

    = @import("std"); pub fn main() !void { const stdout = std.io.getStdOut().writer(); try stdout.print("Hello, {s}!\n", .{"world"}); } % zig build-exe hello.zig % ./hello Hello, world!
  19. 構造体の表現
 他の言語でも構造体はあったり、似 たところでクラスがある。
 でもシンプルな構造体の表 現は既知の知識で半分くらい理解で きた。
 pub const MyStruct =

    struct { const Self = @This(); items: u8, pub fn get(self: Self) u8 { return self.item; } pub fn set(self: *Self, v: u8) void { self.item = v; } }; 表現力を高める

  20. pub const MyStruct = struct { const Self = @This();

    items: u8, pub fn get(self: Self) u8 { return self.item; } pub fn set(self: *Self, v: u8) void { self.item = v; } }; 表現力を高める
 構造体の表現
 ここだけでも言語の特徴が多く垣間 見える。
 関数レシーバとしての self かな? python っぽい
 構造体インスタンスとしての Self 定義かな?
 レシーバがポインタかどうかの違いがある
 go と同じ感じかと思ってた (実際は結構違う)

  21. pub fn Container(comptime T: type) type { return struct {

    const Self = @This(); item: T, pub fn init(v: T) Self { return Self{ .item = v }; } pub fn get(self: Self) T { return self.item; } pub fn set(self: *Self, v: T) void { self.item = v; } }; } 表現力を高める
 ポリモーフィズム
 型 (type) を引数に渡すことで、コード上 で動的に構造体を定義するように記述 できる。
 実際はコンパイル時間に解決される。
 構造体を返す時の型は type 。

  22. 表現力を高める
 「値は型」
 const Containers = struct { pub const U8:

    Container(u8); pub const I8: Container(i8); pub const Usize: Container(usize); }; できた!すげー!!
 fn sum(c: Containers.U8) u8 { return c.get() + 10; } test "value as type" { var c = Container(u8).init(1); const e:u8 = 11; try std.testing.expectEqual(e, sum(c)); } これだけで大興奮、日本酒 3合はやってる。

  23. const const_ = [2]u8{1,2}; var var_ = [2]u8{1,2}; var var_ptr

    = &[2]u8{1,2}; const const_ptr = &[2]u8{1,2}; var var_var_ptr = &var_; var var_const_ptr = &const_; var var_const_ptr_deref = const_ptr.*; 表現力を高める
 mutable/immutable, reference/value
 柔軟な表現だけど慣れるまでは迷子になりやすかった。
 // コンパイルエラーにならないのは? var_[1] = 1; var_ptr[1] = 2; var_var_ptr[1] = 3; var_const_ptr[1] = 4; var_const_ptr_deref[1] = 5; // そのうち reference はどれ? const const_expect:u8 = ?; const var_expect:u8 = ?; try expectEqual(const_expect, const_[1]); try expectEqual(var_expect, var_[1]);
  24. 表現力を高める
 const はずし (コピー)
 const u_1 = [2]u8{1,2}; var u_2

    = u_1; // u_1[1] = 15; u_2[1] = 16; const e: u8 = 16; try std.testing.expectEqual(e, u_2[1]); 迷子になりがちな部分を攻略
 *const と dereference (コピー)
 const u_1 = &[2]u8{1,2}; var u_2 = u_1; var u_3 = u_1.*; // u_1[1] = 14; // u_2[1] = 15; u_3[1] = 16; const e1: u8 = 2; const e2: u8 = 16; try std.testing.expectEqual(2, u_1[1]); try std.testing.expectEqual(16, u_3[1]);
  25. メモリ効率最強かよ
 標準ライブラリで JSON 扱えるから、 JSON の解析は余裕じゃん
 って思うじゃん?
 ファイルコンテンツの文字列を
 参照している 


    (コピーではない)
 parse の直後に file_content を使わないからってリリースしたら、parsed の中身の u8[] もリリースされる・・・

  26. HTTP サーバは、net モジュールが想像していたよりは整えられていたが・・・
 
 • あれ、 HTTP ボディの終端ってどうやって判断するんだっけ?
 • Content-Length

    が不正な場合の正しいサーバの振る舞いは?
 • サボらないでメソッド名見ないと・・・
 RFC からやり直してきやがれ

  27. HTTP サーバは、net モジュールが想像していたよりは整えられていたが・・・
 
 • あれ、 HTTP ボディの終端ってどうやって判断するんだっけ?
 • Content-Length

    が不正な場合の正しいサーバの振る舞いは?
 • サボらないでメソッド名見ないと・・・
 RFC からやり直してきやがれ
 あれ、 思ったより HTTP サーバ実装してるじゃん?

  28. RFC からやり直してきやがれ
 accept からする実装が新鮮、HTTP というより TCP 仕様を読む 
 https://www.rfc-editor.org/rfc/rfc793#section-3.4 


    クソダサヘッダーフィールドディテクション 
 https://www.rfc-editor.org/rfc/rfc2616#section-4.2 
 GET 以外で Content-Length がなければ 400、「私が法だ」 
 https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 

  29. RFC からやり直してきやがれ
 accept からしなければならないのが新鮮、HTTP というより TCP 
 https://www.rfc-editor.org/rfc/rfc793#section-3.4 
 クソダサヘッダーフィールドディテクション

    
 https://www.rfc-editor.org/rfc/rfc2616#section-4.2 
 GET 以外で Content-Length がなければ 400、「私が法だ」 
 https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 
 めっちゃ RFC
 読んでるじゃん?

  30. github に公開しているのはもう習慣として。
 (そもそも作業記録のために push してるものが公開されてるだけ)
 
 作業中も、思ったことは Twitter でぽつぽつつぶやいたり。
 •

    #ziglang タグ付ける
 • 素人だけど臆さない
 基本的には、遊ばせてもらっている恩返しのスタンス。
 アウトプットする

  31. モチベーション
 
 課題・仕事
 趣味・遊び
 成果
 不安・焦燥
 目的達成のために 
 やらざるをえない 


    発散しがち
 飽きたらやめられる 
 なんとなくやってる 
 場合が多い

  32. モチベーション
 
 課題・仕事
 成果
 進捗や成果が目に見えると 
 モチベーションが加速する 
 機能、品質、効率 etc…

    
 学習以前に、成果に対して 
 モチベーションを持っているハズ 
 そうでない「やらされ」ケースは 
 ここでは取り扱わない 

  33. モチベーション
 
 課題・仕事
 成果
 進捗や成果が目に見えると 
 モチベーションが加速する 
 機能、品質、効率 etc…

    
 学習以前に、成果に対して 
 モチベーションを持っているハズ 
 そうでない「やらされ」ケースは 
 ここでは取り扱わない 
 コツ: 得られる成果を最大化する
 学習そのものが目的ではない典型パ ターン
 • 学習は手段、成果が目的
 • 成果に反映される学習を行う
 • 成果が出ていることを確かめる
 • 成果を共有する
 • 勘違いしない

  34. モチベーション
 
 趣味・遊び
 課題
 課題を定めて
 学びの方向性を定める 
 課題の達成を体験する 
 コツ:

    意義のある遊びにする
 始めるのは簡単、続けるのは難しい
 • 自分なりの課題を設定する
 • できることがわかりきった課題は設 定しない
 • 大きい課題ひとつよりも、こまめな 課題を多く設定する
 • シェアする
 放っておいてもしばらく続く 
 しかし無目的になりがち 

  35. モチベーション
 
 不安・焦燥
 「なぜこれを学んでいるのか」 
 が常につきまとう最も厄介なパターン 
 チュートリアルを 1日1つ写経する 


    などの脳死ルーチンから始める 
 コツ: 負荷の少ないことから始める
 意義はそのうち見つければいい
 • 「本当に必要なのか」は最初に自問 すること
 • 気長に取り組む
 • まずは教科書どおりすすめる
 • クリエイティブなことは高負荷
 • 反復学習で修得を体感する

  36. モチベーション
 
 趣味・遊び
 Smith の場合
 課題・仕事
 不安・焦燥
 いつもの課題をやる
 課題
 新しい言語に触るときの定番課題を自分で用意している

    
 Rust サーバ: https://github.com/dolow/server.rs 
 Go サーバ: https://github.com/dolow/server.go 
 JavaScript サーバ: https://github.com/dolow/server.js (これは経緯がちょっと違う) 
 Go フォーマット変換: https://github.com/dolow/nt-go 
 今回の Zig: https://github.com/dolow/zig-playground 

  37. 捨てたもの
 • JSON トークン解析
 • HTTP サーバーのルーティング処理
 拾ったもの
 • ref/value,

    imutable/mutable の理解
 • HTTP 学び直し (ちょこっと)
 取捨選択する
  38. 全体像理解 メモリ
 CPU
 linux
 Ruby
 Rails
 Go
 Zig
 アセンブ リ


    HTTP
 Docker
 Unity
 iOS
 Android
 C#
 C/C++
 Java
 Script
 AWS
 ブロック
 チェーン
 DB
 TCP
 GCP
 Solidity
 FS
 ※ ←適当に配置しただけなので、宗教 観とか歴史認識の相違とかで文句言わ ないでね

  39. 全体像理解 メモリ
 CPU
 linux
 Ruby
 Rails
 Go
 Zig
 アセンブ リ


    HTTP
 Docker
 Unity
 iOS
 Android
 C#
 C/C++
 Java
 Script
 AWS
 ブロック
 チェーン
 DB
 TCP
 GCP
 Solidity
 FS
 ※ ←適当に配置しただけなので、宗教 観とか歴史認識の相違とかで文句言わ ないでね
 • すべての技術はつながっている
 • 今、触っている技術が枝葉なのか幹なのかを把握する
 • 枝葉の技術はトレンドになりやすいが、うつろいやすくもある
 • 枝葉の技術は、幹の技術に習熟していれば修得が早くなる
 (逆に、枝葉の技術をそんなに頑張ってもなぁ、って取捨選択もできる) 

  40. の場合
 • Rust と同じ立ち位置
 ◦ Rust の方が複雑と言われているが、そうでもない気がする・・・ 
 • まだ若いので導入判断は慎重に


    • 弊社事業領域の主要サービスですぐに使うことはない
 • C/C++ を書くシーンでは を検討したい
 • メモリ操作やポインタなどのパラダイム
 • golang って本当にバランスいいなぁ・・・   
 全体像理解
  41. まとめ
 のまとめ
 • C/C++ やメモリ管理の理解があれば取っつきやすい
 • 思ったよりも表現力が高い
 • メモリ効率が徹底している
 •

    const やポインタが C/C++ よりも多彩で複雑
 新しい技術を学ぶまとめ
 • 自分の状態に適したモチベーションコントロールをしよう
 • いま学ぶもの、後に回すものを取捨選択しよう
 • 全体像を理解し、どのように使うかイメージしよう