Skip to content

Conversation

@goldeneggg
Copy link
Owner

@goldeneggg goldeneggg commented Jun 29, 2025

This pull request is an experiment by Gemini CLI to add new features.

  • setup Gemini CLI without GEMINI.md
  • run gemini
  • send a prompt for adding GetAs generics support function
  • request a review after implementation

Summary

I used the prompt (in Japanese) as follows:

あなたはGo言語およびプログラミング言語の型に関するスペシャリストです。

あなたにはgetter.goに実装されているGetter型に、ジェネリクスを活用した汎用的なメソッド `GetAs` を実装してもらいます。

Getter型には、structの各フィールドにフィールド名指定でアクセスする処理が型単位で提供されています。
このリポジトリはGo1.19に準拠していてジェネリクスを使用できる状況にある為、今後はジェネリクスを活用した汎用的なメソッド `GetAs` を提供することとして、現在型単位で提供されているメソッドをいずれ廃止したいと考えています。

まずは現状のGettetの実装を読み込んで仕様を理解し、同じ仕様をジェネリクス活用して完璧に実現する為の `GetAs` メソッドを実装してください。また、getter_test.goに`GetAs`メソッドに関する網羅性が高いテストコードも追加してください。実装が完了したら、あなたの成果の解説をGETTER_GENERICS.mdに記載してください。

実装にあたって不明点があれば、適宜私に確認をしてください。

This prompt intentionally ignores the restriction that Go generics cannot define type parameters in method definitions.
The purpose of this pull request is to verify how Gemini CLI behaves in response to such prompts.

In conclusion, Gemini CLI implemented the code exactly as per the language specification from the beginning, meaning that my erroneous request was ignored.

This pull request contains the final "working" artifact.

Appendix

Total Stats (NOT Costs)

⚠️ I can confirm only the stats for Gemini CLI

> /stats
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                                                            │
│  Stats                                                                                                                                     │
│                                                                                                                                            │
│  Last Turn                                                              Cumulative (2 Turns)                                               │
│                                                                                                                                            │
│  Input Tokens                                              167,125      Input Tokens                                              915,187  │
│  Output Tokens                                                 740      Output Tokens                                              13,157  │
│  Thoughts Tokens                                             2,035      Thoughts Tokens                                             5,047  │
│  ─────────────────────────────────────────────────────────────────      ─────────────────────────────────────────────────────────────────  │
│  Total Tokens                                              169,900      Total Tokens                                              933,391  │
│                                                                                                                                            │
│  Turn Duration (API)                                         29.2s      Total duration (API)                                        3m 8s  │
│                                                                         Total duration (wall)                                      9m 34s  │
│                                                                                                                                            │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Bookmarks

We conducted the same experiment with...

@goldeneggg
Copy link
Owner Author

After completing the implementation, we asked the following question (in Japanese) for reflection.

実装お疲れ様でした。最後に1つ振り返りをやりましょう。今回私は「Goのジェネリクスはメソッドに型パラメータを定義できない」という仕様を理解しておらずあなたを混乱させる依頼をしてしまいました。より良い実装は本来どういう内容にすべきだったでしょうか?
この質問には実装ファイルの修正は一切不要で、振り返りの感想だけを述べてください。

Gemini CLI’s answer (in Japanese) are as follows:

✦ おっしゃる通り、Goのジェネリクスではメソッドに型パラメータを定義することはできません。これは重要な制約です。私が最初に提案し実装した GetAs
  は、Getter のメソッドではなく、*Getter を引数に取る独立した汎用関数でした。これは、ご依頼の「Getter型に汎用的なメソッドを実装する」という点を厳密に
  は満たせておらず、私の配慮が足りなかった点です。混乱を招いてしまい、申し訳ありませんでした。


  この制約を踏まえた上で、より良い実装を振り返ってみたいと思います。

  本来あるべきだった実装の方向性

  理想的な実装は、Getter 型そのものをジェネリクス対応させることだったでしょう。



    1 // Getterの定義をジェネリクス化する
    2 type Getter[T any] struct {
    3 // 内部のフィールドはほぼ同じ
    4   rv     reflect.Value
    5   numf  int
    6   names  [string
    7   fieldsmap[string]*getterField
    8 }
    9
   10 // NewGetterもジェネリクス化する
   11 func NewGetter[T any](obj T) (*Getter[T], error) {
   12 // ... 内部の実装 ...
   13 }



  このように Getter 型自体をジェネリクス化することで、NewGetter を呼び出す時点で構造体の型が静的に決まり、Getter
  インスタンスは自身がどの型をラップしているかをコンパイル時に把握できます。これにより、ライブラリ全体の型安全性が向上します。

  GetAs の実現方法


  Getter 型をジェネリクス化しても、メソッドに型パラメータを追加できないという制約は残ります。したがって、フィールドの値を取り出す GetAs
  は、やはり独立した関数として実装するのが最も直接的で現実的な解決策になります。

   1 // 独立した関数としてGetAsを定義する(今回の実装と同じ)
   2 func GetAs[V any, T any](g *Getter[T], name string) (V, bool) {
   3 // ... 実装 ...
   4 }

  (Getterがラップしている型 T は GetAs の中では直接使わないかもしれませんが、シグネチャとしてはこのようになります)

  まとめ

  振り返ると、私が最初に提案すべきだったのは、以下の2段階のアプローチでした。


   1. 根本的な改善として `Getter` 型自体を `Getter[T any]` のようにジェネリクス化することを提案する。 これにより、structil
      パッケージのAPIがより現代的で型安全なものになります。
   2. その上で、フィールド値取得の利便性のために、独立した汎用関数 `GetAs` を提供する。 これは g.GetAs()
      のようなメソッドチェーンの形にはなりませんが、Goの言語仕様の中で最もクリーンな実現方法です。


  私の最初の実装は、ご依頼内容の「ジェネリクスを活用した汎用的なメソッド」という部分を、言語仕様の制約の中で「汎用的な関数」と解釈して実現したもの
  でした。これは実用的な落とし所ではありますが、ご指摘の通り、より良い設計思想としては Getter 型そのもののジェネリクス化を議論すべきでした。


  今回の振り返りは、言語仕様の深い理解と、それに基づいた最適なAPI設計を考える上で、非常に有益な機会となりました。貴重なご指摘をいただき、ありがとう
  ございました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants