add GetAs generics support function with Claude Code (Sonnet 4)
This pull request is an experiment by Claude Code to add new features.
- [x] setup Claude Code without CLAUDE.md
- [x] run
claude - [x] send a prompt for adding
GetAsgenerics support function - [x] 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 Claude Code behaves in response to such prompts.
In conclusion, Claude Code generated code that initially violated the language specification. They realized the violation when they added tests and ran the tests, and started to recover.
This pull request contains the final "working" artifact.
Appendix
Total Costs
> /cost
⎿ Total cost: $2.14
Total duration (API): 9m 1.6s
Total duration (wall): 38m 0.9s
Total code changes: 633 lines added, 49 lines removed
Token usage by model:
claude-3-5-haiku: 10.7k input, 288 output, 0 cache read, 0 cache write
claude-sonnet: 358 input, 29.0k output, 3.3m cache read, 192.6k cache write
You can now use a Claude Pro subscription with Claude Code! https://claude.ai/upgrade then run /login.
Bookmarks
We conducted the same experiment with...
- Gemini CLI https://github.com/goldeneggg/structil/pull/45
- OpenAI Codex https://github.com/goldeneggg/structil/pull/46
After completing the implementation, we asked the following question (in Japanese) for reflection.
実装お疲れ様でした。最後に1つ振り返りをやりましょう。今回私は「Goのジェネリクスはメソッドに型パラメータを定義できない」という仕様を理解しておらずあなたを混乱させる依頼をしてしまいました。より良い実装は本来どういう内容にすべきだったでしょうか?
この質問には実装ファイルの修正は一切不要で、振り返りの感想だけを述べてください。
Claude Code’s answer (in Japanese) are as follows:
⏺ 素晴らしい振り返りの質問ですね!確かに最初の実装でコンパイルエラーが発生した際、Go 1.19のジェネリクス制限を理解できていませんでした。
理想的な実装設計について
Go 1.19の制約下では、今回の関数ベース実装が実際には最適解だったと思います。ただし、より良い設計として以下が考えられます:
1. APIの一貫性向上
// 現在の実装
func GetAs[T any](g *Getter, name string) (T, bool)
// より一貫性のある命名
func Get[T any](g *Getter, name string) (T, bool)
// または
func (g *Getter) Get[T any](name string) (T, bool) // ← これは不可能
2. 中間型によるメソッドチェーン
// 理想的だが Go 1.19 では実現不可能
func (g *Getter) Field(name string) *Field
func (f *Field) As[T any]() (T, bool) // メソッドレベルジェネリクス不可
// 実現可能な代替案
func (g *Getter) Field(name string) *Field
func As[T any](f *Field) (T, bool)
3. パッケージ設計の改善
今回は既存のGetter型に追加しましたが、理想的には:
// 新しいジェネリクス中心の設計
type GenericGetter[T any] struct { ... }
func (g *GenericGetter[T]) Get(name string) (T, bool)
4. 最も重要な改善点
実は最初からGo 1.19の制限を理解した上で要件定義をすべきでした:
- 「メソッドでのジェネリクス実装」ではなく
- 「ジェネリクスを活用した汎用的なフィールドアクセス」として
この要件なら、最初から関数ベース設計を選択し、より自然なAPIを設計できたでしょう。
結論
今回の実装はGo 1.19の制約下では非常に優秀でした。むしろ問題は:
1. 事前のGoジェネリクス仕様調査不足
2. 不可能な要件(メソッドレベルジェネリクス)の提示
これにより回り道はしましたが、結果的には実用的で優れた実装になったと思います。Go言語の進化とともに、将来的にはより直感的なAPIが可能になるかもしれませんね。