Pull to refresh
5
0.3
Send message

Даже если мы вызовем эту функцию со всеми возможными комбинациями типов, у нас переменная a сравнивается с 0, поэтому должна иметь тип int.

Не должна. Проверка условия [3, "tree", []] == 0 в Python вполне корректна, условие не выполнено.

И, например, мы можем проверять типы и вызывать всё необходимое перед вызовом функции sum.

Можете, но как только вы перетащили работу с типами во время исполнения - код от компилятора C++ весело помахал вам ручкой и скрылся в голубой дали.

def surprise(a):

if a==0:

return 42

elif a==1:

return "48"

elif a==2:

return [4, 2]

def sum(a, b):

return a + b

Вызов должен сделать Int+Int, либо String+String, либо T1+T1, либо T2+T2, либо T3+T3, либо ..., либо T10+T10. Двенадцать разных вариантов (для типов T1-T10 результат вычисляется операциями над полями с разными смещениями, поэтому код заведомо не взаимозаменяем).

def foo(a, b, c):

if a == 0 :

return sum(b, c)

return sum(b, a), c

Совместное распределение типов имеет 155 разных вариантов. Отдельно обращает на себя внимание вариант (Int, Int, Int), потому что он возвращает то ли Int, то ли Tuple[Int, Int], и как прикажете компилировать код возврата из этой функции?

Ну так прикол в том, что я могу написать десяток-другой своих типов с перегруженным +. Что ещё хуже, к моменту когда компилятор добрался до sum , эти типы ещё могут быть не объявлены. Это примерно как требовать сразу инстанцировать шаблонные функции в C++ для всех наборов параметров, которые могут иметь смысл: комбинаторный взрыв плюс невозможность компилировать программу по частям плюс потенциальные бесконечности (a может быть функцией int->int, int->(int->int), int->(int->(int->int)) и так далее, множество допустимых типов бесконечно):

def foo(a) :

def bar(b) :

return a(b)

return bar

Тесты вообще сами по себе верифицируют примерно нифига. Они осмысленны только в сочетании с какими-то ожиданиями о реализации, иначе для проверки целочисленного сложения пришлось бы писать отдельно тест sum(2,3) == 5, отдельно тест sum(2,4) == 6 и далее ad nauseam.

Мгм.

def caller(a, b, c, d):

print sum(a, c)

print sum(d, b)

Если у нас... ну пусть пять типов, то предлагаете компилятору сразу генерировать 625 вариантов функции caller? А если типов 50 (в Python вообще-то свои классы можно создавать)?..

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

def sum(a, b):

return a+b

И во что прикажете это компилировать? В add eax, ebx, в call string_concat или во что-то третье?

При массовом засилии всех этих типов, разве Вы редко видите надписи "случилось неожиданное"?

Я несколько раз пробовал что-то писать на JavaScript, в разных контекстах и по разным поводам. Каждый, каждый раз по достижении пары тысяч строк у меня начинались ошибки "тут integer интерпретируется как массив" (или наоборот). После того как освоил TypeScript, жить стало проще, даже с добавленным геморроем "напиши заголовки для этих пяти библиотек". Поэтому я довольно сильно уверен что если бы у меня не было этой страховки, я бы такой хрени в кодовых базах на сотни тысяч строк видел бы намного больше, чем вижу сейчас.

а что если пришедшая строка прошла валидацию через jsonschema/иной вариант валидаторов входных данных?

Тогда price должен быть уже int. Иначе откуда я знаю, что она действительно прошла, а не свалилась с другого логического пути, на который программа попадает при вот такой уникальной комбинации условий? (И такие баги я ловил - когда автор кода почему-то посчитал, что строка прошла через операцию экранирования, а она в каком-то случае нет, и оп-паньки, получился невалидный JSON. Замечу что разделение типа "строка" на типы "экранированная строка" и "неэкранированная строка" позволило бы поймать баг до коммита в main.)

или другой вопрос: а что если этот код упадёт, и пользователь получит "случилось нечто неожиданное". Пожмёт плечами и сделает рефреш.

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

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

То есть математику можно так же программировать, как и торговлю. А можно программировать, например, игры в покер.

Я не говорю о предметной области. Я говорю о том, почему я, написав программу, считаю что она будет делать то, что я задумал. "Мне кажется" - не аргумент (людям кажутся верными очень бредовые вещи, я человек, следовательно то что мне кажется верным может быть бредом). Доказательство - это как раз и есть способ быть более уверенным в том, что ненадёжный ты сделал более надёжную конструкцию. Математика просто учит бить себя по рукам при попытке написать менее надёжно, чем мог бы. Компилятор железный, если он способен поймать мои ошибки - я хочу чтобы он это сделал.

Будь то игра в покер или автовзвешиватель рыбы, вопрос один и тот же: почему я считаю, что моя программа корректна? Доказательство - это способ строить глобально корректную конструкцию, удостоверяясь в локальной корректности шагов.

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

Возможно я не вижу цены. Всякое конкретное имя в программе - это конкретный символ в доказательстве, он в любом случае имеет конкретный смысл. Обычно этот смысл может быть выражен типом. Если я не вижу чётких границ этого смысла - это не потому что их нет, это потому что у меня хреновое зрение. В функцию может быть передан неожиданный объект? Значит я тупой, "неожиданный" - это не кодовое слово для имманентно загадочного внешнего мира, это недостаточно строгое моё собственное мышление, которое не учло логически возможный вариант.

price.parse::<f64>()

Если price - строка, то в ней может быть "сюрприз" . Я обязан чётко видеть, что именно должна сделать моя функция со строкой такого содержания. (А что если в ней -500? А если произведение приводит к целочисленному переполнению?)
Здесь можно задать архитектурный вопрос, а не надо ли вынести санацию значений куда-нибудь в район их получения, но локально обязанность ясно понимать поведение функции при каждом физически возможном входе - это самый минимум для того, чтобы хотя бы начинать надеяться, что итоговая программа не является полным, абсолютным барахлом.

Программирование — это искусство. А искусство не терпит правил.

Контр-тезис: программирование - это овеществлённая математика. Код всякой функции должен одновременно читаться как доказательство того, что эта функция корректна. А доказательства не бывают "на вайбах", "без правил" и тому подобной мутью. "Ну ты же понял что я имел в виду" - это не доказательство, это барахло.

Статическая типизация не спасает от дурака.

Меня она от себя спасала много раз (следует ли это считать подтверждением что я не дурак?..). От банального "присвоить ID типа A переменной, которая во всём остальном коде интерпретируется как ID типа Б" до "заметить что я использую координаты в неверной проекции" или "это не переведённая текстовая строка, пользователю её показывать не надо".
И мне чаще приходится сталкиваться с логическими ошибками именно потому, что в функции передаются структуры с типизированными полями, а не массивы "третий компонент обозначает время по Дубаю, четвёртый - число снегоуборочных машин, пятый - бинарное представление PNG с номерным знаком автомобиля".

У Лукьяненко был рассказ, "Временная суета". Субъективно, я не нашёл его хорошим самим по себе (скажем, в сравнении с "Поездом в тёплый край") и не нашёл его ухватывающим дух "Понедельника".

Хороший вопрос. Я изначально думал что это из каких-то кавказских легенд. Поисковик напомнил что есть и русскоязычное ("Мастер и Маргарита"):

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

Но утверждается что на МиМ.

Начало: верить собственным глазам.

Шаг вперёд: верить собственному тщательному изучению.

Шаг назад: верить тому кто тщательно изучил.

Шаг вперёд: верить тому кто тщательно изучил и не обруган другими кто тщательно изучил.

Шаг назад: верить пересказу мнения тех кто тщательно изучил и не обруган другими кто тщательно изучил.

...

Заблудиться: потерять связь, восходящую к "тщательно изучить", и считать что есть только равноправные мнения людей и собственные глаза. Нет, не равноправные. "Может быть неправдой" подразумевает вероятность, она может быть сильно разной на основе чего-то изученного.

На практике большинство бредовых идей в нашем меметическом пространстве бредовы очевидно. Даже без каких-то сложных социальных графов: опровергатели теории относительности путаются в школьной физике, носители грандиозных идей о возникновении человека не знают анатомии, etc.

На вопрос "чем вы верующие безусловно в круглость земли отличаетесь от тех, кто верит в то, что она плоская" в основном обижаются. Говорят, что они верят в правильное, а плоскоземельцы в неправильное...

И таки-правы, нет? У стратегии "сразу (a priori) иметь правильные убеждения и не заниматься обработкой свидетельств" есть плюсы, особенно по сравнению со стратегией "начать с правильных убеждений, налажать в анализе свидетельств и придти к неправильным".

Даже "классические" курсы со временем меняются (скажем, определение предела через фильтры). А есть ещё приоритеты: что программистам неплохо бы прочитать основы квантовой механики, что численная оптимизация где-то стала важнее дифуров, etc.
Скажем, мне в своё время читали отдельную лекцию про углы Эйлера. Сама теория, абстрактно, осталась, но её актуальность для программистов заметно снизилась.

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

За лож гражданам. Должен быть смертная казнь как при Сталине!

То есть просто лжи вам мало, хотите добавить ещё и ложь о том что Х "казнён за лож гражданам"?

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

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

отсутствуют макросы: упрощение синтаксиса и устранение ошибок, связанных с их использованием;

Замена того что делалось макросами на примерно эквивалентные им шаблоны упростит синтаксис? Ну-ну.

Но (код) сохраняет высокую производительность благодаря оптимизации работы компилятора.

Какой-то словесный салат. Работающий эффективно компилятор и компилятор, порождающий эффективный код - это очевидно разные вещи. "Автоматически освобождает память" - программа/среда исполнения, а не компилятор. Если компилятор вставил в код проверку, а не надо ли "автоматически" освободить память - эта проверка съела минимум одну ассемблерную инструкцию, чудес не будет. (А в многопоточной программе такие проверки на произвольную память делать больно, многопоточные структуры стараются разнести во времени работу с данными и выделение памяти.)

При каких-то условиях (не знаю могу хорошо сформулировать каких, не тестировщик) ссылка на комментарии/comments/) не позволяет видеть текст поста, в то время как ссылка на пост при прокрутке вниз отображает комментарии.

Желание получить 99/100% времени и что-нибудь хорошее по памяти понятно, но не должно быть частью использования LeetCode как инструмента отбора кандидатов. Если вас мало интересует оптимизация - потому что интересует мало и нефиг отбирать людей по тому что вас интересует мало, если вас сильно интересует оптимизация - потому что нормальная оптимизация делается профилировщиком, а не на глаз. Опять же, результаты LeetCode не отличаются хорошей повторяемостью, особенно по памяти.

Information

Rating
2,582-nd
Registered
Activity