paint-brush
最初のプログラミング言語はコードに対する考え方に大きな影響を与えます@nfrankel
308 測定値
308 測定値

最初のプログラミング言語はコードに対する考え方に大きな影響を与えます

Nicolas Fränkel6m2025/02/02
Read on Terminal Reader

長すぎる; 読むには

オブジェクト指向プログラミング、継承、サブタイプ化は、最初に学習する言語によっては、他の言語には翻訳できない特定の意味を持つ場合があります。
featured image - 最初のプログラミング言語はコードに対する考え方に大きな影響を与えます
Nicolas Fränkel HackerNoon profile picture


Java は、私がキャリアの中で最初に学んだ言語です。その構造は、プログラミングの概念を理解し始めた初期の頃の基礎となりました。まったく異なるアプローチを持つ他のいくつかの言語を経験したことで、私の視点は広がりました。今日は、継承の考え方について考えてみたいと思います。

Java における継承

Java では、継承の考え方はサブタイプ化の概念と密接に結びついています。サブタイプ化はIS A関係の実装です。たとえば、 RabbitクラスはMammalクラスのサブタイプです。したがって、 RabbitインスタンスはMammalのすべての動作を持ちます。つまり、動作を継承します。


このため、メソッドがMammalパラメータを呼び出すときにRabbitインスタンスを渡したり、メソッドの戻り値の型がMammalときにRabbitインスタンスを返したりできます。Java、.Net、またはそれに似たものを学習したことがあるなら、継承をこのように捉えており、それが新しい標準になります。


明示的な継承です。


 class Animal { void feed(); } class Rabbit extends Animal { //1 }
  1. Rabbit Animal IS Aので、 feed()

Goにおける継承

初めて Go を見たとき、継承を提供しながらサブタイプがないことに驚きました。Go はダックタイピングを使用します。


もしそれがアヒルのように見え、アヒルのように泳ぎ、アヒルのように鳴くなら、それはおそらくアヒルでしょう。


Go structインターフェースと同じ関数を実装する場合、暗黙的にインターフェースを実装します


 type Animal interface { feed() //1 } type Rabbit struct { } func (rabbit Rabbit) feed() { //2 // feeds }
  1. Animal餌を与えることができる
  2. Rabbitパラメータとして受け取るfeed()関数が存在するため、 Rabbit Animal実装します。


私は Go のエラー処理アプローチが嫌いですが、暗黙的な実装については二つの考えがありました。一方では、それが新しい概念であることを理解し、偏見を持たないように努めました。他方では、ソフトウェア開発でも実生活でも、物事は常に暗黙的よりも明示的である方が良いと考えています。

Python における継承

Python は、継承に関して私が知る限り最も興味深い言語です。


サブタイプと型ベースの継承は、Python の誕生当初から存在しています。


 class Animal: def feed(self): #1 pass #2 class Rabbit(Animal): #3 pass
  1. Animal餌を与えることができる
  2. Pythonには抽象クラスもインターフェースもなく、クラスのみである。
  3. Rabbit Animal IS Aので、 feed()


この点では、継承に関しては Python は Java と同じように動作します。Python はダックタイピングも提供しており、これをマジックメソッドと呼んでいます。たとえば、反復可能(イテレータを返すことができる) なものを作成するには、 __iter__()__next__()を実装するだけで済みます。


 class SingleValueIterable(): done = False def __init__(self, value): self.value = value def __iter__(self): #1 return self def __next__(self): #1 if self.done: raise StopIteration else: self.done = True return self.value svi = SingleValueIterable(5) sviter = iter(svi) #2 for x in sviter: print(x) #3
  1. ダックタイピング法
  2. Iteratorを作成する - Pythonは上記のメソッドを実装しているので、その方法を知っています
  3. 印刷5


このダックタイピングのアプローチの問題は、Python の定義済みマジックメソッドに対してのみ機能することです。サードパーティが暗黙的に継承できるクラスを提供したい場合はどうすればよいでしょうか。


 class Animal: def feed(): pass class Rabbit: def feed(): pass


上記のスニペットでは、残念なことにRabbit Animalはありません。そこで、Protocols: Structural subtyping (static duck Typing) というタイトルのPEP 544が登場します。この PEP は、クラスにマジック メソッドを定義することの不可能性を解決します。この PEP は、単純なProtocolクラスを定義します。このクラスを継承すると、クラスで定義されたメソッドはダック タイピングの対象となり、これが static duck Typing という名前につながっています。


 from typing import Protocol class Animal(Protocol): #1 def feed(): #2 pass class Rabbit: def feed(): #2 pass class VenusFlytrap: def feed(): #2 pass
  1. Protocolから継承
  2. Animal Protocolなので、 feed()を定義するクラスは良くも悪くもAnimalになります。

結論

オブジェクト指向プログラミング、継承、サブタイプ化は、最初に学ぶ言語によっては、他の言語には当てはまらない特定の意味を持つ場合があります。Java はオブジェクト指向言語であると自称しており、完全なパッケージを提供しています。Go は OO 言語ではありませんが、ダックタイピングによるサブタイプ化を提供しています。Python は明示的継承と暗黙的継承の両方を提供していますが、インターフェースは提供していません。


新しいプログラミング言語を学ぶには、すでに知っている言語と比較します。言語の機能を知ることは、ターゲット言語で慣用的なコードを書くための鍵となります。知っている言語にはない機能に慣れておくと、プログラミング全体に対する理解が広がります。


さらに詳しく:




2025年1月26日にA Java Geekで最初に公開されました