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

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

asuka
January 19, 2025

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

FlutterKaigi mini #3 @Fukuoka
https://flutterkaigi.connpass.com/event/339556/

asuka

January 19, 2025
Tweet

More Decks by asuka

Other Decks in Technology

Transcript

  1. WHOAMI asuka • 株式会社モニクル所属 SWE ◦ 技術書典17: Monicle Techbook vol.1

    • Wasm関連の同人誌・商業誌を執筆 ◦ ご注文はWASIですか?? ◦ Wasm Cookbook vol.2 ◦ 実践入門WebAssembly ◦ WebAssembly System Interface入門 SNSなどでは「Wasmの人」になりつつある → ウェブ技術やWasm界隈に生息 (Flutterをやっていたのは2019年) //おすすめ\\ 2
  2. この2年でDartに起きた変化 • 2023年5月 Dart 3のリリース ◦ PatternとRecordの導入 ◦ class修飾子 interface,sealedなどの導入

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

    • 2024年5月 Dart 3.4のリリース ◦ Wasmのサポート 13 PatternとRecord使ってますか? 🙋 → 使ってみた
  4. パターンマッチめっちゃ良かった 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, )); }
  5. パターンマッチめっちゃ良かった 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: // 省略 }
  6. パターンマッチめっちゃ良かった 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つの要素がある ことが保証されている
  7. パターンマッチめっちゃ良かった 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: // 省略 }
  8. パターンマッチめっちゃ良かった 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: // 省略 }
  9. パターンマッチめっちゃ良かった 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') { // 省略 } }
  10. 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
  11. 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! }