Go Wiki: Go 2 ジェネリクスに関するフィードバック
このページは、Go 2 のコントラクト(ジェネリクス)ドラフトデザインに関するフィードバックを収集し、整理することを目的としています。
構文のプロトタイプ実装はhttps://go.dokyumento.jp/cl/149638にあります。これはGoリポジトリのtipにパッチを当てることで利用できます。
ブログ、Medium、GitHub Gists、メーリングリスト、Googleドキュメントなどにフィードバックを投稿してください。そして、ここにリンクしてください。
フィードバック量が増えるにつれて、特定の種類のフィードバックごとにこのページを整理または再編成してください。
支持
-
Roger Peppe, 「Go contracts use case: generic mgo」、2018年9月
-
Richard Fliam, 「Go2 Generics Let You Construct the Natural Numbers」、2018年8月
補足(修正を伴う支持)
-
Matt McCullough, 「Towards Clarity: Syntax Changes for Contracts in Go」および「Angle Brace Delimiters for Go Contracts」、2020年5月
-
Gert Cuykens, 「Complete separation of generic syntax form regular Go code」、2020年1月
-
Court Fowler, 「Thoughts from a lazy programmer on the updated design」、2019年9月
-
Andrew Phillips, 「Example Types as Contracts」、2019年8月
-
Alexey Nezhdanov, 「A syntax simplification proposal」、2019年8月
-
Bryan Ford, 「Are Only Type Parameters Generic Enough for Go 2 Generics?」、2019年7月
-
Tom Levy, 「Go 2 Generics Feedback」、2019年6月
-
Ole Bulbuk, 「Why Go Contracts Are A Bad Idea In The Light Of A Changing Go Community」、2019年4月
-
Tony Mottaz, 「Go generic types and import injection」、2019年3月
-
Gustavo Bittencourt, 「Contracts only for Generic Types」、2019年3月
-
David Heuschmann, 「Problems With Using Parentheses for Type Argument Lists」、2019年2月
-
Gustavo Bittencourt, 「Contract with methods」、2019年2月
-
Chris Siebenmann, 「Go 2 Generics: Contracts are too clever」、2018年11月
-
Chris Siebenmann, 「Go 2 Generics: A way to make contracts more readable for people」、2018年11月
-
Chris Siebenmann, 「Go 2 Generics: Interfaces are not the right model for type constraints」、2018年11月
-
alanfo, 「Proposed changes to the Go draft generics design in the light of feedback received」、2018年10月
-
Andy Balholm 「Enumerated and structural contracts」、2018年10月
-
Burak Serdar 「Types are contracts」、2018年10月
-
Patrick Smith, 「Go generics for built-in and user-defined type parameters」、2018年9月
-
Jacob Carlborg, 「Go 2 draft D corrections」、2018年9月
-
alanfo, 「A simplified generics constraint system」、2018年9月
-
Paul Borman, 「Simplifying syntax」、2018年9月
-
mrwhythat, 「Go 2 generics draft notes」、2018年9月
-
Roger Peppe, 「Operator overloading」、2018年9月
-
Peter McKenzie, 「Alternative generics syntax」、2018年9月
-
Ted Singer, 「The design goal for syntax is to help humans read」、2018年9月
-
alanfo, 「Suggested amendment to Go 2 generics draft design」、2018年9月
-
Dean Bassett, 「If we’re going to use contracts, allow unary + on string、2018年9月」
-
Kevin Gillette, 「Regarding the Go 2 Generics Draft」、2018年9月
-
jimmy frasche, 「Embedding of type parameters should not be allowed」、2018年8月
-
Javier Zunzunegui, 「Compiling Generics」、2018年8月
-
Liam Breck, 「Please Don’t Mangle the Function Signature」、2018年8月
-
DeedleFake, 「Feedback for Go 2 Design Drafts」、2018年8月
-
Roberto (empijei) Clapis, 「Hard to read syntax」、2018年8月
-
Dominik Honnef, 「My thoughts on the Go Generics Draft」、2018年8月
対案
-
dotaheor, 「Declare generics as mini-packages with generic parameters」、2020年8月
-
Beoran, 「Hygienic Macros」、2019年6月
-
Randy O’Reilly, 「Generic Native Types」、2019年6月
-
Michal Štrba, 「Giving up restricting types」、2019年5月
-
Eric Miller, 「Simple generics using const struct fields」、2019年3月
-
dotaheor, 「A solution to unify Go builtin and custom generics」、2019年2月
-
Quentin Quaadgras, No syntax changes, 1 new type, 1 new builtin、2018年12月
-
Andy Balholm, 「Contracts and Adaptors」、2018年11月
-
Dean Bassett, 「Contract embedding」、2018年10月
-
Patrick Smith, 「Go Generics with Adaptors」、2018年10月
-
Ian Denhardt, 「Go Generics: A Concrete Proposal Re: Using Interfaces Instead Of Contracts.」、2018年10月
-
Arendtio 「Generics in Go inspired by Interfaces」、2018年9月
-
Scott Cotton, 「Draft Proposal Modification for Unifying Contracts and Interfaces」(diff)、2018年9月
-
ohir, 「CGG, Craftsman Go Generics」、2018年9月
-
~~Dean Bassett, 「Using interfaces instead of contracts」、2018年9月~~
この問題点を解決する、後述の「契約埋め込み」という2番目の提案をしました -
dotaheor, 「Combine contract and code together and view generic as compile-time calls with multiple outputs」、2018年9月。(随時更新)
-
Aleksei Pavliukov, 「Extend type and func keywords」、2018年9月
-
Han Tuo, “型の一種としてのジェネリック – type T generic {int, float64}”, 2018年9月
-
Nate Finch, “Go2のコントラクトは行き過ぎだ”, 2018年9月
-
Roger Peppe, “型構造体としてのGoのコントラクト”, 2018年9月
-
Axel Wagner, “コントラクトの破棄”, 2018年9月
-
Matt Sherman “組み込み型クラスとしてのジェネリクス”, 2018年9月
-
Roger Peppe, “修正されたジェネリクスの提案”, 2018年9月
-
Steven Blenkinsop, “Go2コントラクト設計草案への回答 – 補助型”, 2018年9月
-
Dave Cheney, “もしかするとGoへのジェネリクスの追加は結局構文の問題なのかもしれない”, 2018年9月
-
Christian Surlykke, “Goジェネリクスの制約, 2018年9月”
-
go-nutsのいくつかのGopher, “インターフェースとコントラクトの統合”, 2018年8月
-
Roger Peppe, “Goジェネリクスへのフィードバック, 2018年8月
-
Ruan Kunliang, “パッケージレベルのジェネリクス”, 2018年8月
-
Emily Maier, “ジェネリクスについて具体的に考える”, 2018年8月
反対意見
- 東京Gophers, “Go 2設計草案フィードバックイベントからのコメント”, 2018年10月
-
Jason Moiron, “Go2ジェネリクス草案に関するメモ”, 2018年9月
-
Yoshiki Shibukawa, “ジェネリクス/コントラクト提案へのフィードバック, 2018年9月”
フィードバックを追加する
すべてのエントリを下記のようにフォーマットしてください。
- あなたの名前, “タイトル”, 月 年
新しいフィードバックを見やすくするためです。Gistを作成してください。また、カテゴリリストの一番上に新しいエントリを追加することで、リストを逆時系列順にソートするのに役立ちます。
簡単なコメント
-
Chester Gould: この提案の唯一の問題は、明示的なコントラクトがコードを冗長にするだけで、シンプルで読みやすいコードという目標に反しているように見えることです。明示的なコントラクトを書く代わりに、実際に書くコードを「暗黙的なコントラクト」として使用する方が、はるかにシンプルでエレガントでしょう。この例はこちらに示されています。これはこちらで対処されていることは認識していますが、明示的なコントラクトが問題の解決策であるとは思いません。コントラクトはインターフェースが提供するものに非常に近いように思えるので、言語にまったく新しい種類のステートメントを追加するのではなく、インターフェースの動作を拡張してコントラクトに近い動作を許可する必要があります。
-
Izaak Weiss: 議論の多くは、コントラクトの実装方法、またはそれに類するものに具体的に焦点を当てています。しかし、「役立つ例」のほとんどはコントラクトを必要としません。それらはパラメトリック多相性のみを必要とします。型安全な
Merge
やSortSlice
は、コントラクトなしで可能です。また、より単純なコントラクトについては、高階関数を介して実装できます。ジェネリックハッシュマップは、Hash
メソッドを持つ型上でパラメトリックにできるか、構築時にfunc(K) int64
を受け取り、それを使用してキーをハッシュできます。さらに多くの関数が必要な場合は、これらの関数を保持する構造体を疑似コントラクトとして宣言し、それらをジェネリック関数に渡すことができます。これにより、Goのポリモーフィズムはシンプルで明示的になり、将来のコントラクトやその他のメカニズムに関するさらなるイノベーションの余地が残されますが、ジェネリック型のメリットのほとんどをすぐに実現できます。 -
Christoph Hack: 私はアレクサンドレスクの最後の講演The next big Thingを見たばかりです。彼は「コンセプトは時間の無駄だ」と述べ、(今日のC++で可能なすべてのものと比較しても)まったく異なる、はるかに強力な方向性を提案しています。Goには、リフレクションや型がオプションのインターフェースを実装しているかどうかをテストするなど、必要な機能のほとんどがすでにあります。唯一欠けているのはコード生成です。たとえば、
json.Marshal
はリフレクションを使用することで正常に機能しますが、コンパイラによって自動的に呼び出される通常のGoコードを実行するGo関数を実装することでコードを(オプションで)生成することもできる場合、すべてが揃います。最初は非常識に聞こえ、おもちゃの例は冗長に見えるかもしれませんが、アレクサンドレスクはそこにポイントを持っていると思います。gqlgenと他のリフレクションベースのgraphql-libsの違いについて考えてみてください。彼の講演をご覧ください! -
Bodie Solomon: ジェネリクスのデザインは少し混乱し、不透明だと感じています。Zigの美しいコンパイル時関数からいくつかのコンセプトを統合することを検討してください!Go 2のジェネリクスの設計は巧妙ですが、Goの伝統的なシンプルなランタイムセマンティクスとシンプルな構文との緊密な結合に反しているように感じます。さらに、Goの最大の問題の1つは、どこでも使用したい場所に使える競合他社になるのを妨げるものですが、GCとランタイムを取り除くことができないことです。Go 2では、コード生成に頼らずに、必要のない場所で動的インターフェースの使用を確実に回避できるコンパイル時のみのジェネリクスが導入されることを強く望んでいました。残念ながら、それは私の入力なしにコンパイラによって決定されるようです。少なくとも、コントラクトのプロパティとして、動的型がコントラクトを満たすためにコンパイルされることを拒否し、コンパイル時のみの解決にジェネリクスを制約する機能をユーザーに提供することを検討してください。
-
Dag Sverre Seljebotn: C++には、メタプログラミング(「ジェネリクス」)を乱用してコンパイル時のメタプログラミングを行うという大きな問題があります。私は、GoがJuliaの道を歩むことを本当に願っていました。Juliaは、衛生的なマクロを提供します。コンパイル時のバリアに厳密に保持され、ランタイムコード生成がない場合でも、C++のテンプレートシステムから生じる悪い傾向を少なくともすべて回避できます。ジェネリクスでできることは、通常、マクロでも実現できます(例:
SortSliceOfInts = MakeSliceSorterFunctionMacro!(int)
は、整数のスライスをソートする新しい関数を生成できます)。リンク: https://docs.julialang.org/en/v0.6.1/manual/metaprogramming/ -
Maxwell Corbin: 「議論と未解決の質問」セクションで提起された問題はすべて、関数または型レベルではなく、パッケージレベルでジェネリクスを定義することで回避できます。その理由は簡単です。型は自分自身を参照できますが、パッケージは自分自身をインポートできず、より多くの型シグネチャをアルゴリズム的に生成する方法はたくさんありますが、importステートメントで同じことを行うことはできません。そのような構文の簡単な例は次のとおりです。
\\ list package list[T] type T interface{} type List struct { Val T Next *List } // main package main import ( il "list"[int] sl "list"[string] ) var iList = il.List{3} var sList = sl.List{"hello"} // etc...
例の構文はおそらく不必要に冗長ですが、重要なのは、ブログ投稿からの不幸なコード例のどれも合法的な構造ではないということです。パッケージレベルのジェネリクスは、メタプログラミングの最も虐待的な問題を回避しながら、その有用性の大部分を保持します。
-
Andrew Gwozdziewycz:
contract
という単語の使用は、契約による設計にある「contract」のオーバーロードのために、少し躊躇します。ジェネリクスのユースケースは、少し見ればDbCの「コントラクト」といくつかの類似点がありますが、コンセプトはまったく異なります。「コントラクト」はコンピュータサイエンスで確立された概念であるため、behavior
やtrait
のような別の名前を使用する方が混乱を招かないと思います。設計ドキュメントでは、interface
を使用することが理想的ではない理由も示唆していますが、Goのコントラクトメカニズムは、すぐに無視するにはあまりにも明白なインターフェースの拡張のように思えます。もしそれが可能であれば、interface setter(x T) { x.Set(string) error }
とinterface addable(x T, y U) { x + y }
は、非常に自然に読みやすく、理解しやすいように見えます。- Russell Johnston: コントラクトとインターフェースをマージすることができれば素晴らしいということに同意します。演算子の命名問題を回避する別の方法は、通常のGoコードでは表現できない本体を持つ、演算子用の標準インターフェースを提供することです。たとえば、標準の
Multipliable
インターフェースは*
および*=
演算子を許可し、標準のComparable
インターフェースは==
、!=
、<
、<=
、>=
、および>
を許可します。複数の型を持つ演算子を表現するには、これらのインターフェース自体に型パラメータが必要になります。たとえば、type Multipliable(s Self /* これはすべてのインターフェースに暗黙的に存在します */, t Other) interface { /* 言語によって提供されます */ }
。次に、ユーザーが作成したインターフェース/コントラクトは、これらの標準識別子ベースの名前を使用できるため、構文と型に関する設計ドキュメントで言及されている問題をうまく回避できます。 - Roberto (empijei) Clapis: この点と、インターフェースをどこで使用し、コントラクトをどこで使用するかをより明確にする必要があるという事実に同意します。両者が重複する問題に対処しようとするため、2つを統合することは素晴らしいでしょう。
- Kurnia D Win:
contract
よりもconstraint
の方がキーワードとして適切だと思います。個人的には、インターフェースと統合するのではなく、type addable constraint(x T, y U) { x + y }
の方が好きです。
- Russell Johnston: コントラクトとインターフェースをマージすることができれば素晴らしいということに同意します。演算子の命名問題を回避する別の方法は、通常のGoコードでは表現できない本体を持つ、演算子用の標準インターフェースを提供することです。たとえば、標準の
-
Hajime Hoshi: 提案されている提案は、https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md にリストされている解決したい問題に対して大きすぎるように感じます。この機能が悪用され、コードの可読性が低下することを心配しています。見落としている場合は申し訳ありませんが、提案では
go generate
については何も言及していません。go generate
は問題に対して十分ではないでしょうか? -
Stephen Rowles: メソッド構文は、人間が読むには解析が難しいと感じます。型セクションには異なる種類の括弧を使用すると、より明確になるかもしれません。例:私もです👍 +1。さらに👍 +1(Pasha Osipyants)。
func Sum<type T Addable>(x []T) T { var total T for _, v := range x { total += v } return total }
-
yesuu: この例では、
T
をパラメータ名、type
をパラメータ型と考えてください。明らかに、type
は後ろに置く方が合理的であり、コントラクトはchan int
のようにtype
が続きます。func Sum(T type Addable)(x []T) T
-
Seebs: フィードバックが長文なのでインラインで書くのは控えます。2018年8月。要約すると、「2つの型それぞれに1つのコントラクトを指定する方法が欲しい。両方の型に1つのコントラクトではなく」と、「
map[T1]T2
を、"T1は許可されたマップキーでなければならない"という規範的な形式として、t1var == t1var
よりも好む」ということです。 -
Seebs: コントラクトが型パラメータ付き関数だったらどうだろうか?。(2018年9月1日)
-
Sean Quinlan: コントラクト構文はかなり混乱します。必要なものを正確に定義し、APIのドキュメントの一部となるはずのものなのに、コントラクトに影響を与えないあらゆる種類の無駄なものが含まれています。さらに、デザインから引用すると、「コントラクト本体に記述できるすべてのステートメントの意味を説明する必要はない」とあります。それは私がコントラクトに求めるものとは正反対のように思えます。関数の本体をコントラクトにコピーして動作するように見えるのは、機能ではなくバグのように思えます。個人的には、インターフェースとコントラクトを統合するモデルを好みます。インターフェースは、私がコントラクトに求めるものに非常に近く、多くの重複があります。多くのコントラクトがインターフェースにもなる可能性が高いと思われます。
-
Nodir Turakulov: 詳しく説明してください。
container/listやcontainer/ringのようなパッケージ、およびsync.Mapのような型は、コンパイル時の型安全になるように更新されます。
そして
mathパッケージは、すべての数値型に対する簡単な標準アルゴリズムのセット(定番のMin関数やMax関数など)を提供するように拡張されます。
または理想的には、既存の型/関数を型多相を使用するように移行/移行することに関するセクションを追加してください。FWIUでは、既存の型/関数に型パラメータを追加すると、その型/関数を使用する既存のプログラムが壊れる可能性が非常に高くなります。
math.Max
は具体的にどのように変更されますか?後方互換性のない変更を行い、コードをGo2に自動的に変換するツールを作成するつもりですか?現在interface{}
で動作する関数や型を提供する他のライブラリの作成者に対する一般的な推奨事項は何ですか?型パラメータのデフォルト値は検討されましたか?例えば、math.Max
の型パラメータはデフォルトでfloat64
になり、"container/list".List
の型パラメータはデフォルトでinterface{}
になるように。 -
Ward Harold: 完全を期すためだけに、Modula-3のジェネリクスの設計を他の言語の設計セクションに組み込む必要があります。Modula-3は美しい言語でしたが、残念ながら導入されたタイミングが悪かったです。
- Matt Holiday: CLUとほぼ同時期に開発され、Adaの設計にも影響を与えたAlphard言語についても言及してください。さまざまな論文を集めたAlphard: Form and Content, Mary Shaw編、Springer 1991を参照してください。AlphardとAdaは、私がジェネリックプログラミングを初めて知ったきっかけでした。Goは、40年間待ち続けた後、ついにコントラクトを実現することでC++を打ち負かすことができるでしょうか?
-
Ole Begemann: ジェネリクスの概要ページに「Swiftは2017年にリリースされたSwift 4でジェネリクスを追加した」と書かれていますが、これは事実ではありません。Swiftは2014年の最初の公開リリースからジェネリクスを備えていました。証拠(多数の例の1つ):WWDC 2014でのSwiftに関するApple開発者向け講演のトランスクリプトでは、Swiftのジェネリクス機能について詳しく説明しています。
これも正しくありません。「
Equatable
はSwiftの組み込みであり、他の方法で定義することはできないようです。」Equatable
プロトコルはSwift標準ライブラリで定義されていますが、特別なことは何もありません。「通常の」コードで同じものを定義することは完全に可能です。 -
Kevin Gillette: 2018年8月30日現在の「コントラクト」ドラフトの修正
check.Convert(int, interface{})(0, 0)
の1つのインスタンスは、代わりにcheck.Convert(int, interface{})(0)
である必要があります。または、関数が1つではなく2つのゼロを取る理由の説明を提供する必要があります。 -
Adam Ierymenko: 数値コードでこの提案をより有用にする可能性のある、Goで制限された演算子オーバーロードを行うためのアイデアがあります。それは大きいので、ここにGistに貼り付けました。
- DeedleFake: 私は演算子オーバーロードに対する議論に完全に同意しており、全体的にGoにそれがなくて非常に満足していますが、コントラクトを介して
a == b
とa.Equals(b)
の違いを解決できないことが、現在のドラフト設計の最大の問題でもあると思います。つまり、かなりの数のものに対して複数の関数を記述することになります。例えば、二分木を書いてみてください。t < t
またはt.Less(t)
のどちらでコントラクトを使用する必要がありますか?合計関数では、t + t
またはt.Plus(t)
のどちらを使用する必要がありますか? 私は間違いなく、演算子オーバーロードを含まないソリューションを望んでいます。おそらく、次のようなアダプターを指定する方法があるかもしれません。コントラクトAを満たすがBを満たさない型Tが、コントラクトBによって制約されたパラメータに使用される場合、コントラクトBを満たすためにこれを適用する
というものです。コントラクトBは、たとえば、Plus()
メソッドを必要とする可能性があります。一方、コントラクトAは、+
の使用を必要とするため、アダプターは、そのコントラクトでの使用中に、ユーザー指定のPlus()
メソッドをT
に自動的にアタッチします。- この提案で機能する可能性のあるものは、
a.Equals(b)
が存在する場合はそれを使用し、それ以外の場合はa == b
を使用するequal(a, b)
組み込みです。型が比較できない場合はコンパイルに失敗します(同様に他の演算子も同様です)。真剣に検討するには奇妙すぎますが、コントラクトで機能し、演算子を持つ型と持たない型の間の非対称性を、演算子オーバーロードを導入せずに回避できます—jimmyfrasche - 別のアイデアとしては、明示的にオーバーロード可能な演算子があります。
a + b
はオーバーロード可能ではありませんが、a [+] b
はオーバーロードできます。プリミティブ型には通常の+を使用しますが、オブジェクトにOperator+()
などがある場合はそれを使用します。演算子オーバーロードまたはそれに似た適切な形式なしのジェネリクスは、それを行うことさえしないほうが良いというくらいに有用性が低いと本当に思います。-Adam Ierymenko(オリジナルポスター)
- この提案で機能する可能性のあるものは、
- Ian Denhardt: DeedleFakeは、演算子オーバーロードがないことの問題をよくまとめています。オーバーロードを「うるさく」する提案は間違っていると思います。代わりに、次の基準を満たす演算子にオーバーロードできる演算子を制限する必要があります。
- 演算子のセマンティクスは、メソッド呼び出しとして理解できます。数値に関する演算子のほとんどはこのテストに合格します。
big.Add
は、int32、uint64などから知っている意味では依然として加算です。このテストに失敗する演算子の例は、&&
と||
です。これらはショートサーキットするため、関数またはメソッドでは複製できません。これらは、どのように見ても本質的にメソッドではなく、メソッドでオーバーライドすることはできません。演算子オーバーロードは、C++がカンマ演算子のような非常識なものを含め、すべてをオーバーライドできるようにしているため、悪評を招いていると思います。 - それらをオーバーライドするための明確なユースケースが必要です。繰り返しますが、算術演算子は、
<
などと共にこのテストに合格します。ポインタのデリファレンスは最初のテストに合格しますが、「他の種類のポインタ」に実際に良いアイデアだと思われる用途を思いつくのが難しいです。C++ではもう少し正当化されますが、ガベージコレクションされたポインタは基本的にカバーされています。 - 演算子の通常の意味は、推論しやすいものである必要があります。例えば、ポインタはバグの原因となる厄介なものであり、
*foo
がメモリ アドレスからの読み取り以外に何かをしている可能性があると、すでに困難なデバッグ セッションがさらに困難になります。一方、+
がbig.Add
の呼び出しである可能性があることは比較的自己完結しており、大きな混乱を引き起こす可能性は低いでしょう。 - 最後に、標準ライブラリが良い例を示す必要があります。たとえば、
+
をオーバーライドするメソッドは、概念的には加算である必要があります。C++は、道徳的にos.Stdout.ShiftLeft("Hello, World!")
であるものを定義することで、まったく間違った方向へ進んでいます。
- 演算子のセマンティクスは、メソッド呼び出しとして理解できます。数値に関する演算子のほとんどはこのテストに合格します。
- DeedleFake: 私は演算子オーバーロードに対する議論に完全に同意しており、全体的にGoにそれがなくて非常に満足していますが、コントラクトを介して
-
Eltjon Metko: 関数パラメータ内の型識別子の後にコントラクトを指定するのはどうでしょうか?これにより、Tが何であるかを推論でき、最初の括弧のグループを削除できます。
func Sum(x []T:Addable) T { var total T for _, v := range x { total += v } return total }
-
Tristan Colgate-McFarlane: しばらくの間、行ったり来たりしましたが、私は提案にほぼ賛成することになりました。コントラクトの制限された構文が好ましいかもしれませんが、特定のフィールド(一部の人が提案しているようにメソッドだけでなく)を参照できるようにする必要があると思います。互換性のあるインターフェイスとコントラクトの相互使用を容易にするために何かできることがあれば、それも良いでしょう(追加の仕様は必要ないかもしれませんが)。最後に、インターフェイス型を非推奨にすることを検討する価値があると思います。過激ではありますが、コントラクトは本質的に動作も指定できるようにします。(パッケージ内の他の型を参照するなど)それを制限するコントラクトの制限は、おそらく解除されるべきです。コントラクトはインターフェイスの厳密なスーパーセットであるように見え、私は一般的に2つの重複する機能を持つことに反対です。インターフェイスの作成を支援するツールも検討する必要があります。
-
パトリック・スミス:ジェネリック型でメソッドを定義する際に、typeキーワードを必須にすることを検討してもよいかもしれません。これにより、コードは少し冗長になりますが、より明確になり、一貫性が増します(現在、型パラメータは常にtypeキーワードが先行します)。
func (x Foo(type T)) Bar()
-
パトリック・スミス:この例では、
Foo(T)
はBar(T)
に埋め込まれているのでしょうか、それともBar(T)
がFoo
という名前のメソッドを持っているのでしょうか?type Foo(type T) interface {} type Bar(type T) interface { Foo(T) }
-
趙興濤:提案には丸括弧が多すぎます。提案では「[]」が場合によってはあいまいであると述べられています。一方、[type T, S contract]を使用すれば、あいまいさはなくなります。
-
デイブ・チェイニー:以前の型関数提案では、型宣言がパラメータをサポートできることが示されました。これが正しい場合、提案されているコントラクト宣言は以下のように書き換えることができます。
contract stringer(x T) { var s string = x.String() }
から
type stringer(x T) contract { var s string = x.String() }
これは、コントラクトがインターフェースのスーパーセットであるというロジャーの指摘をサポートします。
type stringer(x T) contract { ... }
は、type stringer interface { ... }
が新しいインターフェース型を導入するのと同じように、新しいコントラクト型を導入します。- jimmyfrasche:しかし、コントラクトは型ではありません。
stringer
である値を保持することはできません。stringer
である型の値を保持することはできます。それはメタ型です。型は値に対する述語の一種です。コンパイラに「この値はstring
ですか?」と尋ねると、コンパイラはyes(コンパイルを続行)またはno(エラーを報告するために停止)と答えます。コントラクトは、型のベクトルに対する述語です。コンパイラに2つの質問をします。これらの型はこのコントラクトを満たしていますか?次に、これらの値はこれらの型を満たしていますか?インターフェースは、型が適切なメソッドを持っている場合に、(type, value)
ペアを格納することで、これらの線を曖昧にします。それは同時に型であり、メタ型でもあります。インターフェースをメタ型として使用しないジェネリックシステムは、必然的にインターフェースのスーパーセットを含みます。インターフェースをメタ型としてのみ使用するジェネリックシステムを定義することは完全に可能ですが、それはインターフェースが扱えない演算子などのものを使用するジェネリック関数を記述する機能を失うことを意味します。型について質問できる内容は、そのメソッドセットに制限する必要があります。(私はこれで構いません)。
- jimmyfrasche:しかし、コントラクトは型ではありません。
-
btj:設計ドキュメントの「他の言語での設計」セクションには、非常に重要な2つの項目が欠落しています。型クラスを持つHaskellと、暗黙の引数を持つScalaです。
-
iamgoroot:より良い型エイリアスサポートを行い、ユーザーがオプションとしてジェネリックを使用できるようにするのは自然ではないでしょうか?そのために多くの構文は必要ありません。
type Key _
type Value _
type IntStringHolder Holder<Key:int, Value:string>
type Holder struct {
K Key
V Value
}
func (h *Holder) Set(k Key, v Value) {
h.K = k
h.V = v
}
func main() {
v:= IntStringHolder{}
v.Set(7,"Lucky")
}
-
antoniomo:ドラフトでは、なぜ
F<T>
、F[T]
、および非ASCII(ここでは入力できません)F<<T>>
が破棄されたのかが明確に説明されていますが、F{T}
は、時々3つ続く()
の組み合わせよりも人間が読みやすく、かつ、そのような状況でブロックを開くことができないため、無限先読みによってパーサーを複雑にすることもないように感じます。 -
aprice2704:通常の括弧
(
を使用するという考えは本当に好きではありません。2文字のシーケンスは、無限先読みによるコンパイラのオーバーヘッドを引き起こすでしょうか? <| と |> はどうでしょうか? これらは機能するでしょうか? これらは(
とは非常に異なり、ASCIIで視覚的に意味があり、「Fira Code」フォント(強く推奨)でVSCodeで使用している場合、これらの記号を小さな右または左を指す三角形としてレンダリングする合字があります。 -
leaxoy:まず、ページフッターを編集して申し訳ありませんが、フッターコンテンツを削除できません。これは私の意見です。たくさんの
(
と)
はGoを非常に乱雑に見せます。他の言語のような<
と>
の方が優れており、他の言語から来た人にとってより親切です。 -
星 肇:私はaprice2704さんの構文に関する懸念に完全に同意します。たとえば、
[[
/]]
は機能しませんか?
このコンテンツはGo Wikiの一部です。