Slide 1

Slide 1 text

久しぶりに自作ライブラリをリ ファクタした話 FlutterKaigi mini #3 福岡 Jan 19, 2025 1

Slide 2

Slide 2 text

WHOAMI asuka ● 株式会社モニクル所属 SWE ○ 技術書典17: Monicle Techbook vol.1 ● Wasm関連の同人誌・商業誌を執筆 ○ ご注文はWASIですか?? ○ Wasm Cookbook vol.2 ○ 実践入門WebAssembly ○ WebAssembly System Interface入門 SNSなどでは「Wasmの人」になりつつある → ウェブ技術やWasm界隈に生息 (Flutterをやっていたのは2019年) //おすすめ\\ 2

Slide 3

Slide 3 text

新宿御苑.dev (もくもく会) #2025.1.18 → 新宿でもくもく会やってました 昨日 3 昨日の新宿御苑

Slide 4

Slide 4 text

今日 FlutterKaigi mini #3 @Fukuoka 4

Slide 5

Slide 5 text

新宿 → 福岡 5

Slide 6

Slide 6 text

久しぶりに 自作ライブラリをリファクタした話 6

Slide 7

Slide 7 text

自作ライブラリ tiamat CASL2のコンパイラと,COMET2のエ ミュレータ 7

Slide 8

Slide 8 text

自作ライブラリ tiamat CASL2のコンパイラと,COMET2のエ ミュレータ COMET→彗星→ティアマト→tiamat 8

Slide 9

Slide 9 text

自作ライブラリ tiamat CASL2のコンパイラと,COMET2のエ ミュレータ COMET→彗星→ティアマト→tiamat 9

Slide 10

Slide 10 text

自作ライブラリ tiamat CASL2のコンパイラと,COMET2のエ ミュレータ 最終リリースが 2年前 Dartにいろいろ変化があったのでそれを 反映したい 10

Slide 11

Slide 11 text

この2年でDartに起きた変化 ● 2023年5月 Dart 3のリリース ○ PatternとRecordの導入 ○ class修飾子 interface,sealedなどの導入 ● 2024年5月 Dart 3.4のリリース ○ Wasmのサポート 11

Slide 12

Slide 12 text

この2年でDartに起きた変化 ● 2023年5月 Dart 3のリリース ○ PatternとRecordの導入 ○ class修飾子 interface,sealedなどの導入 ● 2024年5月 Dart 3.4のリリース ○ Wasmのサポート 12 PatternとRecord使ってますか? 🙋

Slide 13

Slide 13 text

この2年でDartに起きた変化 ● 2023年5月 Dart 3のリリース ○ PatternとRecordの導入 ○ class修飾子 interface,sealedなどの導入 ● 2024年5月 Dart 3.4のリリース ○ Wasmのサポート 13 PatternとRecord使ってますか? 🙋 → 使ってみた

Slide 14

Slide 14 text

パターンマッチめっちゃ良かった 14

Slide 15

Slide 15 text

パターンマッチめっちゃ良かった Before 15 After if (operand.length < 2 || operand.length > 3) { return Result.err(ParseError( '[SYNTAX ERROR] ${opecode.runesAsString} wrong number of operands. wants 2 or 3 operands.', start: opecode.start, end: opecode.end, lineStart: opecode.lineStart, lineNumber: opecode.lineNumber, )); } final r = operand[0]; final adr = operand[1]; final x = operand.length == 3 ? operand[2] : null; if (r.type != TokenType.gr) { Result.err(ParseError( '[SYNTAX ERROR] ${r.runesAsString} is not an expected value. value expects between GR0 and GR7.', start: r.start, end: r.end, lineStart: r.lineStart, lineNumber: r.lineNumber, )); } if (x != null) { if (x.type != TokenType.gr) { return Result.err(ParseError( '[SYNTAX ERROR] ${x.runesAsString} is not an expected value. value expects between GR1 and GR7.', start: x.start, end: x.end, lineStart: x.lineStart, lineNumber: x.lineNumber, )); } if (x.runesAsString == 'GR0') { return Result.err(ParseError( '[SYNTAX ERROR] ${x.runesAsString} is not an expected value. value expects between GR1 and GR7.', start: x.start, end: x.end, lineStart: x.lineStart, lineNumber: x.lineNumber, )); } } switch (stmt.operand) { case [final r, _] when r.isNotGr: return Err(CompileError.fromToken( '[SYNTAX ERROR] ${r.string} is not an expected value. value expects between GR0 and GR7.', r, )); case [final r, final adr]: return _compileRadrx(stmt.opecode, r, adr, gr0); case [final r, _, _] when r.isNotGr: return Err(CompileError.fromToken( '[SYNTAX ERROR] ${r.string} is not an expected value. value expects between GR0 and GR7.', r, )); case [_, _, final x] when x.isNotGr: return Err(CompileError.fromToken( '[SYNTAX ERROR] ${x.string} is not an expected value. value expects between GR1 and GR7.', x, )); case [_, _, final x] when x.string == 'GR0': return Err(CompileError.fromToken( '[SYNTAX ERROR] ${x.string} is not an expected value. value expects between GR1 and GR7.', x, )); case [final r, final adr, final x]: return _compileRadrx(stmt.opecode, r, adr, x); default: return Err(CompileError.fromToken( '[SYNTAX ERROR] ${stmt.opecode.string} wrong number of operands. wants 2 or 3 operands.', stmt.opecode, )); }

Slide 16

Slide 16 text

パターンマッチめっちゃ良かった Before 16 After if (operand.length < 2 || operand.length > 3) { // 省略 } final r = operand[0]; final adr = operand[1]; final x = operand.length == 3 ? operand[2] : null; if (r.type != TokenType.gr) { // 省略 } if (x != null) { if (x.type != TokenType.gr) { // 省略 } if (x.runesAsString == 'GR0') { // 省略 } } switch (stmt.operand) { case [final r, _] when r.isNotGr: // 省略 case [final r, final adr]: // 省略 case [final r, _, _] when r.isNotGr: // 省略 case [_, _, final x] when x.isNotGr: // 省略 case [_, _, final x] when x.string == 'GR0': // 省略 case [final r, final adr, final x]: // 省略 default: // 省略 }

Slide 17

Slide 17 text

パターンマッチめっちゃ良かった Before 17 After if (operand.length < 2 || operand.length > 3) { // 省略 } final r = operand[0]; final adr = operand[1]; final x = operand.length == 3 ? operand[2] : null; if (r.type != TokenType.gr) { // 省略 } if (x != null) { if (x.type != TokenType.gr) { // 省略 } if (x.runesAsString == 'GR0') { // 省略 } } switch (stmt.operand) { case [final r, _] when r.isNotGr: // 省略 case [final r, final adr]: // 省略 case [final r, _, _] when r.isNotGr: // 省略 case [_, _, final x] when x.isNotGr: // 省略 case [_, _, final x] when x.string == 'GR0': // 省略 case [final r, final adr, final x]: // 省略 default: // 省略 } [_, _, _]と[_, _]という書き方に よって,常に2または3つの要素がある ことが保証されている

Slide 18

Slide 18 text

パターンマッチめっちゃ良かった Before 18 After if (operand.length < 2 || operand.length > 3) { // 省略 } final r = operand[0]; final adr = operand[1]; final x = operand.length == 3 ? operand[2] : null; if (r.type != TokenType.gr) { // 省略 } if (x != null) { if (x.type != TokenType.gr) { // 省略 } if (x.runesAsString == 'GR0') { // 省略 } } switch (stmt.operand) { case [final r, _] when r.isNotGr: // 省略 case [final r, final adr]: // 省略 case [final r, _, _] when r.isNotGr: // 省略 case [_, _, final x] when x.isNotGr: // 省略 case [_, _, final x] when x.string == 'GR0': // 省略 case [final r, final adr, final x]: // 省略 default: // 省略 }

Slide 19

Slide 19 text

パターンマッチめっちゃ良かった Before 19 After if (operand.length < 2 || operand.length > 3) { // 省略 } final r = operand[0]; final adr = operand[1]; final x = operand.length == 3 ? operand[2] : null; if (r.type != TokenType.gr) { // 省略 } if (x != null) { if (x.type != TokenType.gr) { // 省略 } if (x.runesAsString == 'GR0') { // 省略 } } switch (stmt.operand) { case [final r, _] when r.isNotGr: // 省略 case [final r, final adr]: // 省略 case [final r, _, _] when r.isNotGr: // 省略 case [_, _, final x] when x.isNotGr: // 省略 case [_, _, final x] when x.string == 'GR0': // 省略 case [final r, final adr, final x]: // 省略 default: // 省略 }

Slide 20

Slide 20 text

パターンマッチめっちゃ良かった Before 20 条件分岐がそこそこ複雑なので, どういう時にどう あって欲しいか,というのがわかりにくかった if (operand.length < 2 || operand.length > 3) { // 省略 } final r = operand[0]; final adr = operand[1]; final x = operand.length == 3 ? operand[2] : null; if (r.type != TokenType.gr) { // 省略 } if (x != null) { if (x.type != TokenType.gr) { // 省略 } if (x.runesAsString == 'GR0') { // 省略 } }

Slide 21

Slide 21 text

After switch (stmt.operand) { case [final r, _] when r.isNotGr: // 省略 case [final r, final adr]: // 省略 case [final r, _, _] when r.isNotGr: // 省略 case [_, _, final x] when x.isNotGr: // 省略 case [_, _, final x] when x.string == 'GR0': // 省略 case [final r, final adr, final x]: // 省略 default: // 省略 } パターンマッチめっちゃ良かった どういう時にどうあって欲しいかを, フラットに書け るようになり,コードが読みやすくなった 21

Slide 22

Slide 22 text

switch構文に毛が生えた構文じゃなく, ちゃんとタ イプガードを書ける (感動) パターンマッチめっちゃ良かった 22 void foo(dynamic foo) { switch (foo) { case int _: print("is int!"); case String _: print("is string!"); default: print("is any!"); } } void main() { foo(1); // is int! foo("bar"); // is string! foo(true); // is any! }

Slide 23

Slide 23 text

めっちゃ良いじゃん 23

Slide 24

Slide 24 text

JSにも欲しい 24 fin. 久しぶりに自作ライブラリのリファクタリングをやってみた