LINUX.ORG.RU

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

 ,


1

4

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

★★★★★

Если есть вообще о чем спорить

Ой, да ладно. По-моему скромному мнению, корректное аннотирование всего кода примерно эквивалентно времени, которое придётся потратить на исправление опечаток без него.

И, наверное, про нюансы рефакторинга большого объема кода мало кто здесь расскажет. Мне не сильно много приходится в чужом коде разбираться, и, кмк, если бы он был аннотирован, то легче бы мне не стало.

Даже, когда заглядываю в хорошо документированный код, type hints бывают полезны, но не так, чтобы играть ключевую роль в понимании например логики.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)

что они нужны для (само)документации и не более того

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

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

По-моему скромному мнению, корректное аннотирование всего кода примерно эквивалентно времени, которое придётся потратить на исправление опечаток.

Так аннотировать надо во время написания кода. Если не писать код на скорость, то эта работа сильно не затруднит. И, как указано в ОП, опечатки это только самая очевидная проблема, но не самая большая.

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

Rationale and Goals

This PEP aims to provide a standard syntax for type annotations, opening up Python code to easier static analysis and refactoring, potential runtime type checking, and (perhaps, in some contexts) code generation utilizing type information.

Of these goals, static analysis is the most important. This includes support for off-line type checkers such as mypy, as well as providing a standard notation that can be used by IDEs for code completion and refactoring.

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

Покажите какому-нибудь неофиту «type hints» дженерики и спросите, затруднит его или нет?

Недавно пришлось копаться в коде react + ts довольно известного в узких кругах продукта, обилие any впечатляет, вот во что это превращается )

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

Ну это уже история на тему того, что человек слаб. Хотелось бы как-то всё же концепции пообсуждать 🙂.

Virtuos86 ★★★★★
() автор топика

Нихера ст толком не даёт для прикладника. Ну написано, что str : string или i : int и что? Кроме этого надо знать что из себя представляет значение, какие у него ограничения и прочее. Так что т.н. «строгие» языки они нихера не «строгие», а так, ни туда, ни сюда.

По аргументу, что хинты тебе чем-то помогут, ну да, помогут, если нет никакой другой документации, а если она есть, то проблем чтобы правильно вызвать/заюзать ответ нет. То, что написал типы и ничего больше делать не надо - это так не работает, надо писать документацию в любом случае.

Насчёт «потратишь больше времени разгребать потом без хинтов, чем расставляя хинты» - больше времени ты потратишь на типы говна и чтобы сделать какие-то абстрактные вещи в тех рамах, которые ты сам себя загнал. Сколько раз тебе придётся при этом рефакторить я вообще молчу. Любое key[value] даёт на порядок больше возможностей, чем все эти обосранные оопэ паттерны вместе взятые.

crutch_master ★★★★★
()

Спорить лениво. Добавят аффтары питона опционально такую аннотацию - ладно хорошо спасибо. Не добавят - ну что ж

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от crutch_master

Ну написано, что str : string или i : int и что?

ну и плохо написано. Должно быть externalMapTileId: string и currentTemperatureReading: int.

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

arkhnchul ★★
()

Подозреваю, что статическая дает прирост в производительности. Общее предположение, которое не относится конкретно к питону.

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

Хотелось бы как-то всё же концепции пообсуждать

Еще немножко отвлекусь )

Так получилось, что у меня недавно было несколько интервью на позицию python-разработчика, после многолетнего перерыва.

И вот, ваша тема подтолкнула к такому осмыслению, что ни на одном не было вопросов про тайп хинтинг, как и про тестирование, хотя вопросы про опыт разработки в команде были на каждом.

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

Это так, ремарка, про востребованность.

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

И вот, ваша тема подтолкнула к такому осмыслению, что ни на одном не было вопросов про тайп хинтинг, как и про тестирование, хотя вопросы про опыт разработки в команде были на каждом.

Надеюсь, вы воспользовались советом Гэндальфа разработчикам, что делать из таких мест, где видимо не задумываются о таких бренных вещах, как рефакторинг и поддержка кода: «Бегите, глупцы!»

Virtuos86 ★★★★★
() автор топика

поэтому при запуске код не «упадет» сразу, указав на проблему

Дядя, для этого есть тесты. Они позволяют гораздо точнее и тщательнее установить контракт. Статическая типизация как контракт нормально работает только в ФП языках с алгебраическими типами, вроде хаскеля. В динамических языках типа питона хинты полезны разве что для DI, ну и в инструментальных целях (доки, автодополнение).

no-such-file ★★★★★
()
Ответ на: комментарий от vvn_black

обилие any впечатляет, вот во что это превращается

Ясен пень. Потому что те кто рассказывает, что типы отлавливают какие-то там ошибки при рефакторинге не понимают, что в 10 раз чаще происходит наоборот: все отлично работало бы без хинтов, но формально тип не совпадает. Через некоторое количество итераций всех задалбывает эта история и вкорячивается any.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

поэтому при запуске код не «упадет» сразу, указав на проблему

Дядя, для этого есть тесты. Они позволяют гораздо точнее и тщательнее установить контракт.

Если покрывают весь код, ага. Но не поспоришь. Правда разговор идет о случае, когда о тестах нет ни одного слова в условии задачи.

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

ну и плохо написано. Должно быть externalMapTileId: string и currentTemperatureReading: int.

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

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

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

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

Если покрывают весь код, ага.

Зачем они нужны тогда, если нихрена не покрывают? Так-то в идеальном мире стшников типы вообще должны всё-всё-всё покрывать и ты пукнуть не должен мочь куда-то мимо. Любое невменяемое действие, логика работы вне кейсов, гипотетический выход за любые допустимые значения должен отлавливаться компилятором и жестоко караться. Но что-то я ни одного такого языка не вижу в мейнстриме. Все к этому пытаются идти, но дойти не могут, так и остаются дырявыми.

crutch_master ★★★★★
()

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

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

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

да, тогда иди и разберись, типизация не решает все косяки за тебя. Но тебе не придется разбираться, почему TileId = -834 или температура = «asdffsdf».

Проблема будет, когда начнешь пытаться их соблюдать.

мсье, вы это говорите человеку, бОльшую часть кода пишущему на яве) Нет проблем соблюдать типы, если компилятор/среда тычет носом в попытки их нарушения.

arkhnchul ★★
()

есть еще люди, которые не считают динамическую типизацию (в том виде, в котором она представлена в Питоне, а именно строгая динамическая типизация) серьезным недостатком при работе с большим объемом кода

Ну это скорее не заслуга динамической типизации, а недоработка мейнстримной статической. Если сравнивать строгую динамическую типизацию в питоне с какой-нибудь слабой статической типизацией навроде крестов, то действительно неочевидно, чем первая сильно хуже второй. В мейнстриме статическая типизация как правило унылая и ограниченная, ADT и HKT нет, слишком много церемоний, все равно остается масса способов выстрелить в ногу например через неявные преобразования типов, о принципах вроде make illegal states unrepresentable среднестатистические разработчики и не слышали. А на рефакторинг может вообще никогда ни времени, ни денег не будет, а будет только запиливание новых фич и обвешивание легаси кода костылями и подпорками. К тому же многие проблемы динамической типизации частично нивелируются тестами. Вот и получается, что на практике динамическая типизация не выглядит серьезным недостатком. По крайней мере не во всех проектах. Вот если в мейнстрим когда-нибудь завезут более-менее приличную систему типов, хотя бы с выводом типов по Хиндли-Милнеру, думаю вопрос с динамической типизацией можно будет закрывать.

дает ли статическая типизация выигрыш, если надо перекраивать несметные тыщи kloc

Да здесь и спорить не о чем. Очевидно даже самые слабые гарантии от компилятора при рефакторинге все равно лучше, чем их отсутствие. Вопрос скорее в том, а какого размера проект, а будут ли в нем эти самые несметные тыщщи kloc, а дойдет ли вообще дело до рефакторинга. А если не дойдет, то так ли уж нужны многословные типизированные портянки в джава-стайле вместо идиоматичного и компактного питона.

archie
()
Последнее исправление: archie (всего исправлений: 1)

Наброшу =)

Типы нужны там где ты с ними реально работаешь, сишечка и её друзья, а там где их можно опустить, то можно опустить как бы в том и смысл =) и лишь проверить в начале функции валидные ли данные пришли, если да то ок, если нет то всё должно упасть. Ну пришла строка вместо числа, или массив вместо функции (замыкания например) что делать? Падать на месте или вызываться через pcall как в lua.

Когда типы это чисто синтаксическая подсказка и ругалка при компилялке/интерпреталке то в чём проблема писать так

---------------------------------------
---------  Сам себе помошник  ---------
---------------------------------------
function sum(number_x) 
    assert(type(number_x) == 'number') 
    assert(type(number_x) == 'number')
    ... 
end

function dump(table_value)
    assert(type(table_value) == 'table') 
    ... 
end

local int_a = 1;
local int_b = 2;
local int_c = sum(int_a,int_b);

local table_x = {int_x = a, int_y = b};
dump(tabl_x);

Вместо так

--------------------------------------
------------  из коробки  ------------
--------------------------------------
function sum(x: number) -> number 
    assert(type(number_x) == 'number') 
    assert(type(number_x) == 'number')
    ... 
end

function dump(value: table) -> nil
    assert(type(table_value) == 'table')
    ... 
end

local a: number = 1;
local b: number = 2;
local c: number = sum(a,b);

local table_x = {x:number = a, y:number = b};
dump(x);

Статическая типизация тоже не так прост, если не строгая то только ты знаешь в ней

uint8_t  a = 0;
uint16_t b = 3840;

....

a=b; //Это нормально вообще или нет? Кроме тебя никто не знает. 
b=a; //Это ты так ошибся и теряешь данные или обнуляешь старшие 8 бит из 16?

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

Шутки юмором, но всему своё место, поэтому можно и нужно и статическая и динамическая типизация и строгая и нет. Можно на любом варианте сделать всё что нужно и угодно, просто в некоторых случаях одно будет лучше/удобнее/проще/надёжнее и даже не явно порой, а в косвенных эффектах работы с языком.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от vvn_black

Ой, да ладно. По-моему скромному мнению, корректное аннотирование всего кода примерно эквивалентно времени, которое придётся потратить на исправление опечаток без него.

А ты пробовал или просто теоретизируешь? Я тут решил новые библиотеки с аннотациями писать, потому что к старым типы приписать вообще анриал, решил, мол, буду писать под mypy. Сначала я mypy просто сегфолтил, оказалось, баг чиненый, а релиза они не сделали. Потом он у меня на любую штуку сложнее «мама мыла раму» выдавал Generic[<nothing>] expected, пока mypy-разрабы надо мной не сжалились и не показали секретный флаг --infer-types-harder. И только после этого процесс потихоньку пошёл. Со временем покрытия кода на 100% и исправления всех опечаток абсолютно несопоставимо.

t184256 ★★★★★
()
Последнее исправление: t184256 (всего исправлений: 1)

Сам факт того, что в объектно ориентированном языке используется нестрогая типизация вызывает некоторое недоумение, переходящее в гомерический хохот.

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

В общем, эта ваша статическая типизация в прикладных программах —это просто недодокументация и недотесты. Внушает своим адептам неоправданное чувство безопасности, что можно расслабиться и подзабить на реальную документацию и тесты. До кучи ещё довольно назойливая. Ничего не забыл?

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

a=b; //Это нормально вообще или нет? Кроме тебя никто не знает.

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

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

currentTemperatureReading: int.

А потом ракета за полмиллиарда баксов летит на Венеру вместо Марса, потому что учёные посчитали модель для Кельвинов, европейские инженеры записали в int градусы Цельсия, а американские прочитали оттуда — Фаренгейта.

ugoday ★★★★★
()
Ответ на: комментарий от no-such-file

все отлично работало бы без хинтов, но формально тип не совпадает.

Так и есть. Сообщения вида «Ошибка типа: модуль.длинный.предлинный.путь.к.типу не сооответствут модуль.ещё.один.другой.длинный.путь.к.типу» дичайше демотивируют. Мне вообще-то работу работать надо, а не компилятор ублажать. Если он сам не может понять, что это один и тот же тип, то и пошёл он тогда такой тупой в жопу …

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

И ещё в этом идеальном мире физические единицы измерения вшиты в язык со всеми вытекающими. Кажись такое в F# (но не уверен), но где он, этот F#? А в этом Пайтон дюжина библиотек разной степени упоротости, аж воротит.

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

Хз о чем тут спорить. Очень помогает от тупых распространены ошибок типа не ту переменную указал, написал передачу аргументом объекта вместо поля этого объекта. И ide подсвечивает и линтер с компилятором матюгнутся. Насчет того что часто используется инт там где не совсем инт, ну так на этот счет давно придуманы языки типа Ada, да и тот же паскаль где можно писать диапазон допустимых значений

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

языки типа Ada, да и тот же паскаль

Их востребованность как бы намекает … К слову, а покажите как на паскале реализовать какое-нибудь примитивное ограничение на значения переменный. Например, как реализовать тип «число Фибоначчи».

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

В первую очередь типизация нужна для тулинга

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

upcFrost ★★★★★
()

Когда полей в объекте много, а сделать нужно завтра, то без хотя бы подсказок типов это превращается в кашу или ограниченный TDD. Другое дело, что не нужно городить тысячи абстракций и 50-уровневое наследование.

ac130kz ★★
()

Даёт конечно типизация статическая, и не обязательно все ломать в процессе рефакторинга - достаточно просто что то где то недодумать.

Причём аннотирования типов в заголовках ф-й недостаточно - в теле функции тоже что то может пойти не так.

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

Имаюенуй-не именуй сущности,
Все равно получишь эксепшн
Таков путь питониста.

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

Тут нужно выбрать что-то одно:

Или код пишется неофитом.

Или есть хоть какая-то ненулевая вероятность, что код пишется качественно.

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

нормальный человеческий автокомплит забыл.

А что, питонистов не устраивает их автокомплит? Ради какой такой выгоды им тащить этот чемодан статической типизации без ручки?

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

некоторых не устраивает. Меня вот тоже не устраивает, я и послаще редьки с хреном едывал.

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

Покажите какому-нибудь неофиту «type hints» дженерики и спросите, затруднит его или нет?

Почему это должно кого-то волновать? Или вы свои процессы исключительно на не очень одаренных школьниках выстраиваете?

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

какой-нибудь слабой статической типизацией навроде крестов

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

Все кроме примитивных типов в С и С++ типизируется строго.

Siborgium ★★★★★
()
Ответ на: комментарий от no-such-file

В динамических языках типа питона хинты полезны разве что для DI, ну и в инструментальных целях (доки, автодополнение).

В Typed Racket успешно работает. Правда там система типов намного мощнее, чем у питона.

monk ★★★★★
()

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

ИМХО динамическую типизацию приемлемо использовать для разработки обобщённых алгоритмов.

Приведу маленький пример.
Как-то написал скрипт на PHP, который позволял выгрузить данные всех
объектов 1С 7.7 в MySQL с использованием динамической типизации.
Скрипт содержал где-то 200 строк (не помню точно).
В данном случае использование динамической типизации «самое то».

--------------------------------------------------------------
Ныне процессора весьма шустрые и если алгоритм не сильно нагружен, то всё будет быстро работать с использованием любой типизации.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 2)

Статическая типизация позволяет упростить тестирование. Но заметно усложняет само проектирование кода, потому что всё, что сложно типизируется, автоматически отбрасывается.

И вместо того, чтобы получить из JSON объект с произвольными полями, получаем доступ по ключам-строкам ассоциативного массива. Потому что тип «ассоциативный массив с произвольными ключами-строками» есть, а типа «объект с классом, прочитанным из JSON» нет.

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

выгрузить данные всех объектов 1С 7.7 в MySQL

Подскажу: если после каждой строчки вставлять sleep(100), то разницы и вовсе никакой не будет.

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

Все кроме примитивных типов в С и С++ типизируется строго.

Не совсем. Наличие для класса А конструктора с единственным аргументом типа Б позволяет всюду вместо объектов типа А ставить объекты типа Б.

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