paint-brush
Ваш первый язык программирования сильно влияет на то, как вы думаете о кодек@nfrankel
317 чтения
317 чтения

Ваш первый язык программирования сильно влияет на то, как вы думаете о коде

к 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 : он наследует поведение.


Из-за этого вы можете передать экземпляр Rabbit , когда метод вызывает параметр Mammal , или вернуть экземпляр Rabbit , когда тип возвращаемого значения метода — Mammal . Если вы изучали Java, .Net или что-то отдаленно похожее, то именно так вы видите наследование, и оно становится новой нормой.


Это явное наследование .


 class Animal { void feed(); } class Rabbit extends Animal { //1 }
  1. Поскольку Rabbit IS A Animal , его можно feed()

Наследование в Go

Когда я впервые посмотрел на Go, я был поражен тем, что в нем нет подтипов, но при этом есть наследование. Go использует утиную типизацию:


Если что-то выглядит как утка, плавает как утка и крякает как утка, то, скорее всего, так оно и есть.


Если struct Go реализует те же функции, что и интерфейс, она неявно реализует интерфейс.


 type Animal interface { feed() //1 } type Rabbit struct { } func (rabbit Rabbit) feed() { //2 // feeds }
  1. Animal может кормить
  2. Поскольку существует функция feed() , которая принимает Rabbit в качестве параметра, 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 IS A Animal , его можно 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 , к нашему большому огорчению. Введите PEP 544 под названием Protocols: Structural subtyping (static duck typing). PEP решает невозможность определения магических методов для наших классов. Он определяет простой класс Protocol : как только вы наследуете от него, методы, определенные в классе, становятся доступными для duck typing, отсюда и название — 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 не является объектно-ориентированным языком, но он все еще предлагает подтипирование с помощью утиной типизации. Python предлагает как явное, так и неявное наследование, но не имеет интерфейсов.


Вы изучаете новый язык программирования, сравнивая его с тем(ами), которые вы уже знаете. Знание особенностей языка является ключом к написанию идиоматического кода на вашем целевом языке. Ознакомьтесь с особенностями, которых нет в известных вам языках: они расширят ваше понимание программирования в целом.


Идем дальше:




Первоначально опубликовано в A Java Geek 26 января 2025 г.