プログラミング言語での継承の省略


10

私は自分のプログラミング言語を開発しています。これint x = 1;は、クラウド向けではない汎用言語(デスクトップ用の静的型付けPythonなど)です。

継承やMixinsを許可しないことは問題ないと思いますか?(ユーザーが少なくともインターフェースを持っている場合)

例: Google Go、継承を許可しないことでプログラミングコミュニティに衝撃を与えたシステム言語。

回答:


4

実際、継承の使用は(とりわけ)密結合につながるため、次善の策は次善策であることがますますわかります。

実装の継承は、常にインターフェイスの継承と構成で置き換えることができます。より最近のソフトウェア設計では、構成を優先して、継承を使用する方向が次第に少なくなる傾向があります。

そのため、はい、特に継承を提供しないことは完全に有効であり、流行の設計決定において非常に重要です。

ミックスインは、他の一方で、(まだ)でも主流の言語機能はなく、言語「ミックスイン」と呼ばれる機能を提供は、多くの場合、それによって非常に異なるものを理解しています。それを提供するかどうかはお気軽に。個人的にはとても便利だと思いますが、正しく実装するのはとても難しいかもしれません。


13

言語のセマンティクスの残りの部分も無意味であることを考慮せずに、継承(または実際には単一の機能)が必要かどうかについての推論。あなたは真空で議論しています。

必要なのは、一貫した言語設計哲学です。言語は、設計された問題をエレガントに解決できる必要があります。これを達成するためのモデルは、継承を必要とする場合と必要としない場合がありますが、全体像がないとこれを判断するのは困難です。

たとえば、言語にファーストクラスの関数、部分的な関数の適用、ポリモーフィックなデータ型、型変数、ジェネリック型がある場合、従来のOOP継承と同じ基本をカバーしていますが、異なるパラダイムを使用しています。

レイトバインディング、動的型付け、プロパティとしてのメソッド、柔軟な関数引数、およびファーストクラスの関数がある場合も、同じ根拠をカバーしますが、ここでも、異なるパラダイムを使用します。

(概説されている2つのパラダイムの例は、読者のための演習として残しています。)

だから、あなたが望む意味論の種類について考え、それらをいじって、継承なしでそれらが十分かどうか確かめてください。そうでない場合は、継承をミックスに投入するか、他に何かが欠けていると判断する可能性があります。


9

はい。

特に言語が動的に型付けされている場合は、継承を許可しないことは問題ないと思います。委任や構成などにより、同様のコードの再利用を実現できます。例えば、私はいくつかの適度に複雑なプログラムを書かれている-大丈夫、ではないという複雑な:) - JavaScriptで任意の継承なし。基本的に、オブジェクトを代数的データ構造として使用し、いくつかの関数をメソッドとして付加しました。これらのオブジェクトを操作するメソッドではない関数もたくさんありました。

動的な型付けがある場合(私がそうしていると仮定しています)、継承なしで多態性を持つこともできます。また、実行時にオブジェクトに任意のメソッドを追加することを許可する場合、ミックスインなどはそれほど必要ありません。

別のオプション-私は良いと思います-はJavaScriptをエミュレートしてプロトタイプを使用することです。これらはクラスよりも単純ですが、非常に柔軟です。考慮すべきことだけです。

だから、すべて言った、私はそれのために行きます。


2
継承で通常処理される種類のタスクを達成するための合理的な方法がある限り、先に進んでください。確認するために、いくつかの使用例を試してみてください(おそらく、他の人から問題の例を求めて、自己偏見を避けるためにさえ進んでいます...)
comestorm 2012年

いいえそれは静的かつ強く型付けされています。
クリストファー

静的に型付けされているため、実行時にランダムなメソッドをオブジェクトに追加することはできません。ただし、引き続きダックタイピングを行うことができます。例としてGosuプロトコルを確認してください。私は夏の間少しプロトコルを使用しました、そしてそれらは本当に役に立ちました。Gosuには、「機能強化」もあります。これは、事後にクラスにメソッドを追加する方法です。そのようなものを追加することも検討できます。
Tikhon Jelvis 2012年

2
どうぞ、お願いします。継承とコードの再利用の関連付けをやめてください。継承はコードの再利用にとって本当に悪いツールであることは長い間知られています。
Jan Hudec

3
継承は、コードを再利用するための1つのツールにすぎません。多くの場合、それは非常に優れたツールであり、他の場合には恐ろしいです。継承よりも構成を優先しても、継承をまったく使用しないという意味ではありません。
Michael K

8

はい、継承を省略することは完全に合理的な設計上の決定です。

実装の継承を削除するのには非常に良い理由があります。非常に複雑でコードの保守が困難になる可能性があるためです。私は、継承は(通常、ほとんどのOOP言語で実装されているため)継承を誤った機能であると見なすこともできます。

たとえば、Clojureは実装の継承を提供せず、同じ結果をよりきれいに達成するために使用できる直交機能(プロトコル、データ、関数、マクロ)のセットを提供することを好みます。

ここで私は非常にリッチヒッキーは(継承を含む)プログラミング言語での複雑さの根本的な原因を特定し、この一般的なトピック、上の啓発およびそれぞれの提示する代替案発見したビデオだ:シンプルで簡単に作られました


多くの場合、インターフェースの継承がより適切です。しかし、適度に使用する場合、インプリメンテーション継承は多くの定型コードを削除できるため、最もエレガントなソリューションです。それは、平均的なPython / JavaScriptモンキーよりもインテリジェントで注意深いプログラマーを必要とするだけです。
ErikAlapää2016

4

VB6クラスが継承(インターフェイスのみ)をサポートしていないという事実に初めて遭遇したとき、それは本当に私を苛立たせました(そして今でもサポートしています)。

ただし、これが非常に悪い理由は、コンストラクターパラメーターもなかったため、通常の依存性注入(DI)を実行できなかったためです。DIがある場合、継承よりも構成を優先するという原則に従うことができるため、継承よりも重要です。それはとにかくコードを再利用するためのより良い方法です。

でも、Mixinsを持っていないのですか?インターフェースを実装し、そのインターフェースのすべての作業を依存性注入を通じてオブジェクトセットに委任する場合は、Mixinsが理想的です。それ以外の場合は、すべてのボイラープレートコードを記述して、すべてのメソッドやプロパティを子オブジェクトに委任する必要があります。私はそれを(C#のおかげで)たくさんやっていました。


この質問のきっかけとなったのは、コードの再利用が非常に有益なSVG DOMの実装です。
クリストファー

2

別の答えに同意しない場合:いいえ、必要な機能と互換性がない場合は機能を破棄します。Java(およびその他のGCで使用されている言語)は、型の安全性をさらに必要としていたため、明示的なメモリ管理を廃止しました。Haskellは、方程式の推論と派手なタイプをもっと必要としていたので、突然変異を捨てました。Cでさえ、コンパイラの最適化をもっと必要としていたため、特定の種類のエイリアシングやその他の動作を破棄(または違法と宣言)しました。

だから問題は:継承以上のものは何ですか?


1
明示的なメモリ管理とタイプセーフのみが完全に無関係であり、互換性がないことは間違いありません。同じことが突然変異と「ファンシータイプ」にも当てはまります。私は一般的な推論に同意しますが、あなたの例はかなりひどく選ばれています。
Konrad Rudolph

@KonradRudolph、メモリ管理、およびタイプセーフは密接に関連しています。A free/ delete操作はあなたに無効参照する機能を提供します。型システムが影響を受けるすべての参照を追跡できない限り、その言語は安全ではありません。特に、CもC ++もタイプセーフではありません。どちらかを妥協して(線形型や割り当て制限など)、同意させることができるのは事実です。正確には、Javaは特定の単純な型システムと無制限の割り当てを伴う型安全性求めていたと私は言ったはずです。
ライアンカルペッパー2012年

それはむしろ、タイプセーフの定義方法に依存します。あなたはコンパイル時の型の安全性(完全に合理的な)定義を取り、場合たとえば、および参照整合性は、あなたのタイプのシステムの一部になりたい、そしてJavaは(それができますので、いずれかのタイプセーフされていないnull参照を)。禁止freeかなり任意の追加の制限です。要約すると、言語がタイプセーフかどうかは、言語よりもタイプセーフの定義に依存します。
Konrad Rudolph

1
@ライアン:ポインターは完全にタイプセーフです。彼らは常に彼らの定義に従って行動します。それはあなたが彼らが好きな方法ではないかもしれませんが、それは常に彼らがどのように定義されているかに応じてです。あなたは彼らをそうでないものに伸ばそうとしています。スマートポインターは、C ++ではかなり安全なメモリの安全性を保証できます。
DeadMG 2012年

@KonradRudolph:Javaでは、すべてのT参照はnull、拡張するクラスのオブジェクトまたはオブジェクトのいずれかを参照しますTnull醜いですが、上の操作は、null上記の型不変式を壊すのではなく、明確に定義された例外をスローします。C ++とのコントラスト:を呼び出した後deleteT*ポインタは、もはやが保持していないことをメモリを指してTオブジェクトを。さらに悪いことに、割り当てでそのポインターを使用してフィールド割り当てを行う場合、たまたま近くのアドレスに配置されただけの場合、別のクラスのオブジェクトのフィールドを完全に更新する可能性があります。これは、用語の有用な定義によるタイプセーフではありません。
ライアンカルペッパー2012年

1

番号。

基本言語機能を削除したい場合は、その機能が絶対に必要ではない(または不当に実装が難しく、ここでは適用されない)ことを普遍的に宣言しています。そして、「決して」はソフトウェア工学における強い言葉です。そのような発言を行うには、非常に強力な正当化が必要になります。


8
それはほとんど真実ではありません:Javaの全体的な設計は、演算子のオーバーロード、多重継承、手動のメモリ管理などの機能を削除することでした。さらに、言語機能を「神聖な」ものとして扱うのは間違っていると思います。機能を削除することを正当化するのではなく、機能を追加することを正当化する必要があります。すべての言語に必要な機能は考えられません。
Tikhon Jelvis 2012年

6
@TikhonJelvis:Javaがひどい言語であるのはそのためであり、「ゴミ収集の継承を使用する」以外は何もないことが最大の理由です。言語機能は正当化する必要があるはずですが、これは基本言語機能です。これには多くの有用なアプリケーションがあり、DRYに違反することなくプログラマが複製することはできません。
DeadMG 2012年

1
@DeadMGすごい!かなり強い言葉。
クリストファー

@DeadMG:コメントとして反論を書き始めましたが、それを回答(qv)に変えました。
ライアンカルペッパー2012年

1
「完成するのは、追加するものが残っているときではなく、削除するものが残っているときです」(q)
9000

1

厳密にC ++の観点から言えば、継承は主に2つの目的で役立ちます。

  1. コードの再利用が可能
  2. 子クラスでのオーバーライドと組み合わせると、基本クラスポインターを使用して、その型を知らなくても子クラスオブジェクトを処理できます。

要点1については、あまりアクロバットにふ​​けることなくコードを共有する方法がある限り、継承は不要です。ポイント2については、Javaの方法を使用して、この機能を実装するためのインターフェースを要求できます。

継承を削除する利点は

  1. 長い階層とそれに関連する問題を防ぎます。あなたのコード共有メカニズムはそのために十分なはずです。
  2. 親クラスの変更が子クラスを壊さないようにします。

このトレードオフは、主に「Dont Repeat Yourself」と柔軟性と、もう一方の問題回避との間で生じます。個人的には、他の開発者が問題を予測するのに十分なほど賢くないかもしれないので、継承がC ++から移行するのを嫌うでしょう。


1

継承やMixinsを許可しないことは問題ないと思いますか?(ユーザーが少なくともインターフェースを持っている場合)

実装の継承やミックスインなしで多くの非常に便利な作業を実行できますが、ある種のインターフェイスの継承、つまりオブジェクトがインターフェイスAを実装するかどうかを宣言し、それからBもインターフェイスする必要があることを宣言する必要があるかどうか疑問に思います(つまり、 AはBの特殊化であるため、型の関係があります)。一方、結果のオブジェクトは、両方のインターフェースを実装していることを記録するだけでよいので、それほど複雑ではありません。すべて完全に実行可能です。

ただし、実装の継承がないことには明らかな欠点が1つあります。クラスの数値インデックス付きvtableを構築できなくなるため、すべてのメソッド呼び出しに対してハッシュ検索を実行する必要があります(またはそれらを回避するための賢い方法を見つけ出す必要があります)。このメカニズムを通じて基本的な値(たとえば、数値)をルーティングする場合、これは困難な場合があります。非常に優れたハッシュの実装でさえ、すべての内部ループで複数回ヒットする場合、高額になる可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.