LINUX.ORG.RU

Зачем нужна статическая типизация?, или Вы всё врете!

 ,


1

4

В теме "Питонячьи радости " на последних страницах между мной и @rtxtxtrx внезапно разгорелся спор, из которого я понял, что есть еще люди, которые не считают динамическую типизацию (в том виде, в котором она представлена в Питоне, а именно строгая динамическая типизация) серьезным недостатком при работе с большим объемом кода, особенно при рефакторинге. Вообще изначально разговор завязался вокруг назначения type hints введенных в Питон 3: я утверждал, что они нужны для создания семантических связей в коде, которые будут препятствовать внесению деструктивных изменений в код в результате опечатки или иной ошибки кодера (изменил код, в результате которого какое-либо выражение получило некорректное значение, которое тем не менее обладает схожим с корректным значением типовым контрактом, поэтому при запуске код не «упадет» сразу, указав на проблему); оппонент заявил, что они нужны для (само)документации и не более того.
Но потом выяснилось, что и царь-то ненастоящий (читай, статическая типизация). Не нужна она, просто именуй сущности понятно и уповай на строгую типизацию. А если типизация не строгая, то сами виноваты, у нас в Питоне всё ОК.
Поскольку тема большая и вкусная, я предлагаю всем обсудить этот очень важный вопрос в меру скромных сил и познаний каждого желающего. Обсуждение вторичных вопросов, как-то «статическая типизация нужна для генерации эффективного кода», «при динамической типизации тип только один, object» etc. не предусмотрено — спорим только о том, дает ли статическая типизация выигрыш, если надо перекраивать несметные тыщи kloc. Если есть вообще о чем спорить 😅.

★★★★★
Ответ на: комментарий от monk

add_tooltip(add_border(button)) != add_border(add_tooltip(button))

Так и в Си++ смена последовательности наследования даёт разный результат.

Более того. Наследование является лишь одним из способов порождения пользовательских типов.

«Заданные пользователем ЯП правила порождения типов» - это ничто иное как шаблоны.

Так что мы приходим к: AddTooltip<AddBorder<Button>>.

А ещё можно делать … И получить кнопку с интегрированным изображением.

А в этом примере вообще не очевидно, почему это нужно делать на уровне класса, а не экземпляра класса. Никакой видимой выгоды в этом нет.

В Racket активно используется для обработки событий. Чтобы наследник не мог выкинуть обязательную часть алгоритма (проверку масок и всё такое). В Java часто эмулируют двумя связанными методами.

Да, это стандартный способ решения таких ситуаций. В Си++ это будет пара из невиртуального и виртуального метода.

При этом способ «решить проблему при помощи двух простых концептов» выглядит архитектурно привлекательнее, чем «изобрести специальный сложный неочевидный концепт».

Чтобы код был прозрачным, сложные взаимодействия желательно раскладывать на общеизвестные шаблоны проектирования.

wandrien ★★
()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от ugoday

со СтруктурнымПрограммированием(СП) - тож примечательно

оно(СП) было в тренде лет 20 - за этот период каких только СП то не выдумывали

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

а так и то и то как инструмент это одно - а как религия совсем иное

всех благ

qulinxao3 ★☆
()
Ответ на: комментарий от wandrien

А в этом примере вообще не очевидно, почему это нужно делать на уровне класса, а не экземпляра класса.

А как ты на уровне экземпляра переопределишь метод onPaint?

При этом способ «решить проблему при помощи двух простых концептов» выглядит архитектурно привлекательнее, чем «изобрести специальный сложный неочевидный концепт».

Гм… Получить два сильно связанных якобы независимых объекта всё-таки заметно хуже.

ООП ведь тоже родилось из идеи, что отдельно структуры и функции хуже, чем «специальный сложный неочевидный концепт» из структуры с функциями вместе.

monk ★★★★★
()
Ответ на: комментарий от wandrien

а потом иду читать непонятные для вас книжки.

святая простота

qulinxao3 ★☆
()
Ответ на: комментарий от monk

Исключение - это по смыслу неявный Optional. (Частности, в Крестах, где оно не видно в сигнатуре типа.)

И этим оно плохо.

Явно использование Optional соответствует духу статического типирования.

Но чем наш пример с Not0 отличается от примера с CorrectURL, который обсуждался выше - это тем, что над числами обычно всё-таки требуется делать какую-то арифметику. И обычно намного чаще, чем порождать новые URL и удостоверяться в их корректности.

Поэтому хотя пример с Not0 концептуально идентичен, но практически скорее всего будет бесполезен.

wandrien ★★
()
Ответ на: комментарий от wandrien

что превратило ADT из мутной математической концепции

и это от лица пытающегося унизить «гуманитаришек»

лолкек поцтол

qulinxao3 ★☆
()
Ответ на: комментарий от monk

А как ты на уровне экземпляра переопределишь метод onPaint?

Не нужно переопределять onPaint. Нужно, чтобы кнопка представляла собой контейнер. Внутрь кладём хоть картинки, хоть текстовые метки, хоть видеоролики.

Гм… Получить два сильно связанных якобы независимых объекта всё-таки заметно хуже.

Хороший аргумент.

Проблема в том, что я действительно не могу удержать в голове конструкцию из переплетения super и inner, которая там описана.

Но если представить это как отдельный механизм порождения связанных пар сущностей - например, в виде декоратора в Питоне или метода наподобие attr_accessor в Руби, то да, это выглядит хорошей идеей.

На Си++ такое, вроде бы, не описать.

wandrien ★★
()
Ответ на: комментарий от wandrien

если на полном серьёзе:

до сих пор актуально и по мере реальной «деградации масс» вовлечённых в индустрию всё более ценно:

https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf

ру: http://hosting.vspu.ac.ru/~chul/dijkstra/goto/goto.htm

статья(первоисточник) лишь буквально о гоуто - в целом оно в том числе что же не так в ООП

qulinxao3 ★☆
()
Ответ на: комментарий от qulinxao3

Самоцитирование глупых мантр это полный кринж. Ты можешь просто показать, кто и в каких книгах/статьях говорил, что ООП позволяет легко переиспользовать компоненты? Потому что я про переиспользование ничего не встречал. Это всё что я спрашивал в этом треде.

И без глубокомысленной шизофазии, пожалуйста, а нормальным русским языком.

alex1101
()
Ответ на: комментарий от qulinxao3

статья(первоисточник) лишь буквально о гоуто - в целом оно в том числе что же не так в ООП

Шизофрения - удручающая штука.

alex1101
()
Ответ на: комментарий от alex1101

И без глубокомысленной шизофазии

Это ж qulinxao. Всё равно что попросить Эдди сохранять текстовые файлики в юникоде.

wandrien ★★
()
Ответ на: комментарий от Forum0888

Ещё не много об ООП.

Пусть у нас имеется две struct.

typedef struct Heap__ {

BYTE *pHeap; ULONG SizeHeap;

} Heap_;

и

typedef struct NameHeap__ {

Heap_ *pHeap; TCHAR *pNameHeap;

} NameHeap_;

И функция.

Heap * GetHeap( Heap_ *ItemHeap }

Как использовать функцию GetHeap для получения pHeap из объекта NameHeap_ *pItemNameHeap; ?

ООП как раз о том, что можно создать иерархию объектов (имеющих некоторый набор функций) и
как-то дать понять компилятору типа вот смотри у этого сына папа вот этот класс.

По существу всю эту премудрость можно заменить использованием обычных struct.
При этом правда синтаксис кода будет «менее красив».

ООП C++ в какой-то мере, это просто синтаксический сахар для использования некой иерархии объектов.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 6)
Ответ на: комментарий от wandrien

Поэтому хотя пример с Not0 концептуально идентичен, но практически скорее всего будет бесполезен.

Практически полезен. Полезен даже не только с «не 0», но и с «больше 0» для температуры, «рабочий диапазон» для «ускорения» и так далее.

monk ★★★★★
()
Ответ на: комментарий от wandrien

публике с попкорном примечательно как вы в очередной раз признали правоту стороны которой вы оппонируете переходом на обсуждение одного из оппонентов

повторюсь

https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf

http://hosting.vspu.ac.ru/~chul/dijkstra/goto/goto.htm

Дейстра и о вреде ООП(на тот момент термина не было явление уже) в вышеприведённой двухстраничной заметке

ну и так и быть после признания оппами своего гопничества:

https://harmful.cat-v.org/software/OO_programming/

qulinxao3 ★☆
()
Ответ на: комментарий от monk

Так смысл примера в том, что мы просто переложили обработку Optional из более очевидного места в менее очевидное место =)

Хотя казалось бы, вот вам умозрительный div: (int, int) -> Optional int, пожалуйста.

Но «делало функцию сложной» по условию поставленной задачи.

Мы просто переложили сложность в другое место.

wandrien ★★
()
Ответ на: комментарий от qulinxao3

https://harmful.cat-v.org/software/OO_programming/

Юникс-вытираны идут в бой.

Роберт Пайк, печально известный тем, что после участия в разработке Юникса (ставшего раком IT), отметился в Plan 9, Inferno и Go - тупиковых ветвях IT-эволюции.

wandrien ★★
()
Ответ на: комментарий от Forum0888

ООП C++ в какой-то мере, это просто синтаксический сахар для использования некой иерархии объектов.

Вот поэтому-то многие популярные проекты написаны на Си.
Ведь какое основное предназначение компилятора?
Дать возможность программисту написать алгоритм.
Си с этой задачей прекрасно справляется.

Forum0888
()
Ответ на: комментарий от qulinxao3

Я не котирую рассуждения о сферических конях в вакууме. Про недостатки ООП я знал и до этой статьи.

alex1101
()
Ответ на: комментарий от Forum0888

Глубочайшая мысль, достойная занесения в аналы.

На других-то языках программирования, видимо, стихи пишут, а не алгоритмы.

alex1101
()
Ответ на: комментарий от alex1101

Дружище, не претендую на то, что мои суждения «панацея».
Просто у меня отношение к ООП C++ простое - «Это синтаксический сахарок, который в борщ лучше не ложить».

Forum0888
()
Ответ на: комментарий от Forum0888

Это синтаксический сахарок

Сишку тоже можно назвать синтаксическим сахаром над ассемблером.

который в борщ лучше не ложить

Тогда объясни создание GObject сишниками.

alex1101
()
Ответ на: комментарий от alex1101

Всё проще. Начальство не велит:

Существует несколько дополнительных компонентов, расширяющих основные классы, их свободное добавление и изменение; фирмой-разработчиком они не рекомендованы к использованию. Это означает, что фирма 1С и её франчайзи отказываются от какой-либо технической поддержки конфигураций, использующих такие компоненты.

wandrien ★★
()
Ответ на: комментарий от wandrien

весь смысл которой в том

это реально слишком буквальное утверждение как правило характерное для лиц либо не знакомых с статьёй Дейкстры - либо не осмысливших при чтение статьи в чём реальная проблема тех инструментов частным случаем которых и есть goto

в условно «до интернетные » времена в текстах методичек и прочих вторичных(третичных) источников о структурном программирование вот это вот буквальное «без гоуто счастье,молодость,зашибись» - было одним из признаков что текст не о реальном применении структурного программирования - а чисто публикация ради .

qulinxao3 ★☆
()
Ответ на: комментарий от alex1101

Сишку тоже можно назвать синтаксическим сахаром над ассемблером.

Не являюсь ярым противником ООП C++.
Нравится и хотят использовать - non problem.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 1)
Ответ на: комментарий от alex1101

Тогда объясни создание GObject сишниками.

Ещё раз - назначение Си в том, чтобы дать возможность написать алгоритм.
Всё!

Остальные все прения касаются лишь синтаксиса Си.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 1)
Ответ на: комментарий от wandrien

Мы просто переложили сложность в другое место.

А в этом и есть суть системы типов. Если у нас всего одна функция, вызывающая div, и она может корректно обработать пришедший 0, то лучше просто сделать контракт в этой функции и тип нам не нужен.

Если же у нас есть некое k и куча кода по всей программе вида

y = x / k;
z = (a + b * c) / k

то имеет смысл сделать k Not0 вместо того, чтобы проверять в каждом месте её применения.

P. S. К рассуждениям про CorrectIP выше это тоже относится.

monk ★★★★★
()
Ответ на: комментарий от monk

А как ты на уровне экземпляра переопределишь метод onPaint?

Кстати, это ещё одно расширение ООП, возможное в JS. Чтобы у экземпляра класса можно было переопределить метод при этом не создавая новый класс.

monk ★★★★★
()
Ответ на: комментарий от monk

Если порассуждать еще на тему того, чего еще могло бы хотеться, то можно задаться вопросом, а нужен ли нам в нашем умозрительном блоке

y = x / k;
z = (a + b * c) / k

в явном виде тип Not0, или более уместно представить это как вычисление монады, где автоматически выводится тип результата а ля ({int y, int z} OR DivideByZero).

…и мы снова приходим к концепции исключений =)

wandrien ★★
()
Ответ на: комментарий от wandrien

в явном виде тип Not0, или более уместно представить это как вычисление монады, где автоматически выводится тип результата а ля ({int y, int z} OR DivideByZero).

И этот DivideByZero придётся обрабатывать после каждого деления. Если делитель один, логичнее проверять, что туда 0 не попадает.

monk ★★★★★
()
Ответ на: комментарий от monk

Кстати, это ещё одно расширение ООП, возможное в JS. Чтобы у экземпляра класса можно было переопределить метод при этом не создавая новый класс.

Так разница ст. и дин. подхода именно в том, что ст. позволяет накладывать и гарантировать ограничения на вариабельность семантики и поведения. Это фича.

Если переопределение метода на уровне экземпляра требуется, то это должно быть явно описано на языке типов.

wandrien ★★
()
Ответ на: комментарий от wandrien

В смысле?

y = x / k;
y2 = y + 2;

Как здесь сделать следующее вычисление не обработав ошибку в первой строке? Можно, конечно, как в монаде Either пробрасывать ошибку, но это ещё хуже, чем исключения: получаешь только код ошибки, но без стека.

monk ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)