LINUX.ORG.RU

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

 ,


1

4

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

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

Мда… аргумент. Сам выбрал 8 бит, сам знаешь что 8 бит не хватит для результата, и сам негодуешь :-)

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

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

Ну и так пишут на Си специально, что бы 100 + 200 = 44.

А вы на языке, за который топите, так сможете?

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

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

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

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

Ну во первых в случае известных на этапе компиляции значений это в принципе реализуемо, а в случае, когда значения слагаемых будут известны только в момент выполнения? Что тогда по твоему должно быть? Может компилятор должен встроить проверку результата для всех цифровых типов в арифметические операторы и например бросать исключение, если результат выходит за границу типа? Так что ли? А что делать в случаях, когда мне не нужна эта проверка? Когда я хочу выжить максимальную производительность и оверхэд мне не нужен? Например в случае реализации какого нибудь алгоритма хэширования, где постоянно результат выходит за границу типа, но согласно стандарту компилятора С++ результат берется по модулю числа, которое на единицу больше, чем наибольшее значение, которое может быть представлено результирующим целочисленным типом без знака. Сюда тоже встроить проверку на каждой итерации? Чтобы все тормозило как этот ваш js ?

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

Welcome to the magical world of Turbo Pascal/Delphi

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

{$R+}, {$Q+}

А что делать в случаях, когда мне не нужна эта проверка?

{$R-}, {$Q-}

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

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

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

Система типов должна бить по рукам, а не втыкать нож в спину. С тем же успехом она может позволять складывать числа со строками, а потом усмехаться: „Ну, а фигли ты хотел, лопушок?“. Любой ответ на вопрос: „Сколько будет 100 + 200?“, кроме «300» является грубой арифметической ошибкой. Любая успешная попытка положить в переменную типа «число от 0 до 255» любое число вне этого диапазона является грубой ошибкой типизации. Люди, которые связывают себя типами по рукам и ногам, чтобы надёжно было, а потом легко принимают, что это их вообще не защитило от ошибки — странные люди, я вас не понимаю.

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

Си максимально близок к логике работы процессора, а там такие операции допустимы

А в чём тогда претензии к складыванию числа со строкой? У PHP тоже есть причины так делать и там такие операции допустимы.

44 это абсолютно правильный и единственный ответ.

Надеюсь у вашей учительницы математики нет пользователя на лоре.

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

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

???

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

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

а в случае, когда значения слагаемых будут известны только в момент выполнения?

Думайте. Защита статической типизации — ваша тема, не собираюсь вас никак ограничивать в возможных решениях.

Может компилятор должен встроить проверку результата

Может быть. А может — исходя из кода вывести систему ограничений на допустимые значения, так, что если есть c=a+b и a=200, то должно бытьb<55 или ошибка. Варианты есть.

но согласно стандарту компилятора С++

Жалкая отмазка. Все претензии к $ПлохойЯзык, тоже можно снимать возражением, что согласно его стандарту всё так и должно работать?

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

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

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

А вы на языке, за который топите, так сможете?

Вроде что-то можно было в типизированных массивах. Только зачем, хз.

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

Жалкая отмазка. Все претензии к $ПлохойЯзык, тоже можно снимать возражением, что согласно его стандарту всё так и должно работать?

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

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

Ну это ваши проблемы, что вы не можете выдержать изначального тезиса: „В случае СТ компилятор может проверить всё на этапе компиляции и избавить от ошибок“ и начинаете вилять тем местом, где спина утрачивает своё благородное название.

скорость некоторых алгоритмов ухудшится

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

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

Ну это ваши проблемы, что вы не можете выдержать изначального тезиса: «В случае СТ компилятор может проверить всё на этапе компиляции и избавить от ошибок»

а можно ссылку на мое сообщение, где я писал «ВСЕ ОШИБКИ».

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

Ты рассматриваешь 100u8 и 200u8 как целые числа, я их рассматриваю как числа из поля по модулю 256. А теперь обоснуй, почему твоя позиция единственно правильная. И ещё, действильно ли только динамическая типизация позволяет при возведении 2 в сотую степень получить 1267650600228229401496703205376.

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

Оки-доки. Пока зафиксируем:

  1. Сложные типы вроде «корректный IP» ваша система типов в принципе не способно описать.
  2. На простых численных типах она тоже лажает.
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Сложные типы вроде «корректный IP» ваша система типов в принципе не способно описать. На простых численных типах она тоже лажает.

Ну это, я бы сказал, не совсем объективные факты, это твое отношение к объективным фактам.

ip адрес вообще я бы представлял в виде класса, т.к. там постоянно нужно в/из строку/и перегонять и всякие проверки на принадлежность к подсети, например, и т.п. Но если ты хочешь простой тип (фундаметальный), ок, можешь взять uint32_t (елси мы про ipv4).

Ты сейчас тоже про невозможность представления результата сложения двух ip адресов скажешь? Только вот при маршрутизации арифметическая операция сложения не применяется, там битовые операции используют. И вот бы лепота какая была бы, если бы там на каждую операцию проверки были, ой, как бы быстро все работало-то.

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

Сложные типы вроде «корректный IP» ваша система типов в принципе не способно описать.

Я так и не понял, откуда взялось это утверждение. К примеру, я сейчас использую математическую библиотеку, и у неё есть не менее сложный тип Unit<Vector3>, для которого есть гарантия нормальности. Что с этим типом не так?

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

А вы на языке, за который топите, так сможете?

Вроде что-то можно было в типизированных массивах. Только зачем, хз.

Это сложение по модулю, (100+200) mod 256 = 44

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

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

«ВСЕ ОШИБКИ».

Далее, логика «все ошибки не находит, но некоторые находит и это лучше, чем ничего» в принципе имеет право на жизнь. Однако хотелось бы, чтобы области, где мне компилятор помогает и где он самоустраняется были строго очерчены. Вот, как в русте сделали. Здесь у нас футбольное поле, бегай где хочешь, borrow checker всё проверил. А здесь, видишь знак unsafe — это минное поле, ходи осторожно. У вас же минные и футбольные поля плавно перетекают одно в другое и неудивительно, что везде оторванные ноги валяются.

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

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

Спасибо, братан!!! За еще одно обесценивание.

Вот, как в русте

Легким движением руки спор из «динамик типы vs статик типы» превращается в «C++ vs Rust». Ай молодца :-)

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

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

Кроме того, если мы возьмём выражения

100+200=44
"2"+2=22
2+"2"=4

то совершенно непонятно, почему мы должны считать одни из них ложными, а другие истинными. Мы точно так же можем сказать, что число это не число, строка это не строка, сложение это не сложение, а всё это некие сущности, которые сочетаются по формальным правилам, описанным в спецификации. И если ты не понимаешь, почему "2" + 2 != 2 + "2", то это твои и только твои проблемы, простофиля. В следующий раз будь пособраннее.

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

помнить где я считаю в натуральных числах, а где в кольце вычетов

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

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

Повышенная по сравнению с программированием на чём? Любом языке с динамической типизацией?

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

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

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

И если ты не понимаешь, почему "2" + 2 != 2 + "2"

А зачем это понимать? На С++ - это не валидная конструкция (в смысле такое не будет компилироваться). С другой стороны:

'2' + 2 != 2 + '2' // - это false
// т.е.
'2' + 2 == 2 + '2' // - это true

потому что '2' - это тип char, т.е. целочисленный и имеет право учавствовать в арифметических выражениях.

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

Ты написал:

100+200=44
"2"+2=22
2+"2"=4

Проверяю код:

let a = 100 + 200
let b = "2" + 2
let c = 2 + "2"

console.log(a, typeof(a), b, typeof(b), c, typeof(c));

На Google Chrome Version 119.0.6045.202 (Official Build) (64-bit) вывод такой:

300 'number' '22' 'string' '22' 'string'

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

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

Ой. Тссссссс. Ну да, все правильно, арифметика указателей.

Тупанул. Я быстро в ide проверил в текущем проекте. А там стоит флаг: -Wstring-plus-int

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

Ну вообще-то в C++ «2» – это не строка :)

PS. Хотя что в C++ строка – это вообще большой вопрос. Не все согласны с тем, что строка – это только std::basic_string.

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

Аааа. Ну это я знаю. Но я все равно считаю это строкой, что не противоречит утверждению о том, что это const char[2]

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

Но я все равно считаю это строкой

Ну вот я к тому, что в C++ нет консенсуса о том, что считать строкой.

Поскольку строковый литерал, по сути, массив. А к массиву применяются определенные правила. Так, имя массива – есть указатель на первый элемент. А раз это указатель, то к указателю применимы некоторые действия, типа сложения с целочисленным скаляром, проверка на равенство/неравенство.

Но это именно что к указателю, а не к содержимому.

Тогда как под строкой в языке высокого уровня все-таки принято понимать что-то другое.

Однако, поскольку в C++ сильно историческое наследие (до C++98 в языке std::basic_string не было) и наследие чистого Си, то многие продолжают считать строковые литералы и строки в стиле Си строками.

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

Ну вот я к тому, что в C++ нет консенсуса о том, что считать строкой.

А не задавались вопросом «почему» до сих пор нет? Не интересно узнать?

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

Неправда. Легко проверяется при помощи sizeof.

Из того, что sizeof правильно вычисляет размер массива фиксированного размера (да еще и чей размер известен компилятору) не следует отрицание того, что имя массива при этом является еще и указателем на первый элемент этого массива.

Ну вот такие массивы были унаследованы из Си.

https://godbolt.org/z/bx4KnzEhG

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

Еще многие путают «адрес» и «указатель» в программе.

Адрес – это номер байта в памяти, доступной процессору.

Указатель – это переменная в памяти, хранящая адрес.

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

"2" + 2 == 2 + "2"

в йобаскрипте - это верно, а в питоне не «скомпилится»

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

Вот, как в русте сделали. Здесь у нас футбольное поле, бегай где хочешь, borrow checker всё проверил. А здесь, видишь знак unsafe — это минное поле, ходи осторожно.

Это очень распространенное заблуждение, но борроу чекер не отключается в unsafe блоках, его вообще нельзя отключить никак 😊.

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