Как стать автором
Обновить

Комментарии 111

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

Думаю со временем вся эта шелуха отомрёт.
Простите, а что за «аффинные типы»? Я что-то пропустил?

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

>Когда вы проверяете введённые пользователем данные, выясняя, могут ли они рассматриваться как число — вы выполняете динамическую проверку типа.

Вообще-то нет. Мне кажется, автора тут заклинило по полной.

А почему нет?


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

На входе у нас не неопределенные данные, а значение вполне конкретного типа — строка (или, в зависимости от реализации, последовательность байт, unicode codepoints и т.п.). Если бы на входе было динамически типизированное значение, вот тогда бы имело смысл говорить о проверке его типа.

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

С какой стати вы определяете их тип, применяя скажем регулярное выражение \d+?

Тип – это понятие расплывчатое.


Есть int, а есть unsigned int. Есть произвольная строка, а есть enum. То есть при помощи проверок можно сузить тип значения до более узкого.

>Тип – это понятие расплывчатое.

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

Ну вот что-то вроде


function isNumberLikeString(value: unknown): value is NumberLikeString {
  return type of value === 'string'  && /\d+/.test(value);
}

function StringToNumber(value: NumberLikeString): number {
  parseInt(value, 10);
}

let input = "123";

if (isNumberLikeString(input)) {
  const number: number = StringToNumber(input);
  console.log('Number',  number);
} else {
  throw Error("TypeError")
}

разве не будет динамической проверкой типа?

Ответьте для себя — динамической проверкой типа чего? Тип какой переменной вы тут проверяете? Становится ли строка числом от того, что ее содержимое соответствует регулярному выражению? Будет ли number когда-нибудь какого-то разного типа, или всегда одного?

Тип переменной input проверяю на предмет совместимости по типу с аргументом функции StringToNumber, можно ли эту переменную "скастовать" в число в терминах предметной области.

Берем скажем, js, и будет там примерно так:

x= '123' // тип переменной строковый
x= parseInt('123') // тип переменной становится числовым, и нет никакой проверки на совместимость в момент собственно присваивания.

То есть, из всех проверок именно при вводе есть только проверка, что строка в нужном нам формате. А проверки типа просто не будет — он станет таким, какой вернет функция конвертации.

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

Ну то есть, ввод данных — это не тот случай, на котором обычно иллюстрируют проверки типов. Более типичный был бы например x= y+z, где в зависимости от текущих типов y и z может происходить много чего интересного, и операция + будет интерпретироваться сильно по-разному.

Ввод данных часто как раз становится ахилессовой пятой при внедрение строгой типизации, например при переходе с JS на TS. Субъективно именно ввод-вывод часто становится либо причиной отказа от перехода, либо константации постфактум, что переход ожидаемого снижения количества багов не принёс.

Когда вы проверяете введённые пользователем данные, выясняя, могут ли они рассматриваться как число — вы выполняете динамическую проверку типа.

Это проеобразование из одного типа в другой. Динамическая проверка типа происходит когда мы кастим переменную типа IFigure в Trigngle.
Технически компилятор или среда исполнения могут начать с преобразования, но это не значит, что здесь нет проверки на тип данных. Потому что проверка — логическая. То есть программист мог попробовать распасить строку и ожидает получить либо эксепшн, либо число — вот это и есть логическая проверка, которую вы проигнорировали от отсутствия опыта. Ну а «когда мы кастим» — это уже не логическая, а чисто техническая реализация алгоритма проверки соответствия узким техническим возможностям (а не высокоуровневое выявления истинного типа).
Потому что проверка — логическая.

Это — проверка, но не проверка типов. Тип строка ни в каком случае не равен типу числу. Но некоторые значения типа строка могут быть преобразованы (разными способами) в тип число.

Тип «строка» может содержать информацию типа «число». И может не содержать. Отсюда — необходимость проверки типа данных в строке.

Что является, а что не является строковым представлением числа — внеязыковая информация. А вот, например, правила работы isinstance(obj, str) определёны в языке.


Так можно дойти до того, что if i > 5 {} — тоже проверка типа, как уже отмечали в обсуждении.

>> Так можно дойти до…

Это называется — повышение уровня абстракции. Оно полезно. Поэтому так доходить — можно.

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


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

>> А мы обсуждаем типы, а не абстракции.

Я говорил про «повышение уровня абстракции».
НЛО прилетело и опубликовало эту надпись здесь
Э, тайпчекинг разрешим

Как раз и тайпчекинг для ЗТ неразрешим, т.к. эквивалентен доказательству произвольных теорем.


"Разрешимым" он становится только тогда, когда вы руками доказываете компилятору, что не верблюд :)


Тут надо еще отметить, что есть неразрешимость теоретическая, а есть практическая. Например тайпчек для зт неразрешим практически — ну то есть вы по факту будете постоянно сталкиваться на практике с ситуациями, когда тайпчекер — дурак. С другой стороны, неразрешимость вывода SystemF — теоретическая. Т.е. вы моджете годами писать на ЯП с SystemF и никогда не написать тот самый специфический терм, для которого тип не будет выведен. И важно, что потенциально любая теоретически неразрешимая задача является разрешимой практически.

НЛО прилетело и опубликовало эту надпись здесь
Так что тайпчекинг эквивалентен проверке доказательства произвольных теорем.

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


Я относительно регулярно утыкаюсь в то, что ghc не поддерживает импредикативный полиморфизм

Как не поддерживает? Это же system f

НЛО прилетело и опубликовало эту надпись здесь

А чем именно обкостылевание не устраивает?

НЛО прилетело и опубликовало эту надпись здесь

Ну я имею ввиду, с точки зрения выразительности системы, это же одно и то же? Т.е. импредикативный полиморфизм как бы есть, но для не запилили сахару? :)

НЛО прилетело и опубликовало эту надпись здесь

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

НЛО прилетело и опубликовало эту надпись здесь

Зашел прочитать этот комментарий.

Достала это тупая пропаганда typescript, языки которые созданы с динамический типизацией должны использоваться по назначению, так же как и языки со строгой типизацией. А не так, чтобы пихать везде и всегда типизацию. Залог успеха это только отличная архитектура проекта, а типизирована она или нет, особого значения уже не играет. Если не уметь проектировать архитектуру, то вас никакие фреймворки и никакие типы не спасут, и уж тем более никакие статейки из интернета с «best practice» я смотрю на код нынешних проектов, даже тех которые начали писаться не позднее полу года назад и аж плакать хочется… Они способные к масштабированию и развитию только тем человеком, который их написал, для остальных гораздо быстрее и проще все с нуля переписать нежели сбоку лепить ещё говна на эту кучу говна. Лучше бы пропаганду по тому что надо учиться правильную архитектуру закладывать в приложения устроили и тогда бы и жить всем стало легче.
НЛО прилетело и опубликовало эту надпись здесь
А это уже напрямую зависит от уровня разработчика, я например таких ошибок уже года 4 точно не совершал, т.к. если я вызываю ту или иную функцию я и так знаю чего она ждет в аргументах, а если не знаю и/или забываю, то просто нажимаю ctrl+на нее и сразу же вижу, что она принимает и как именно работает. Типизация не освобождает от того, что ты должен знать что ты делаешь и чего ты хочешь от той или иной функции или класса. Если такие ошибки у вас в обыденности, то это печальные новости, а вообще я такие ошибки видел с 2015 года вообще в единичных случаях, т.к. как раз начиная с этого периода у меня ни разу в команде джунов не попадалось. Так что если от совершения таких ошибок вас спасает только типизация, то что я могу сказать, значит именно вам она действительно необходима, а мне например по барабану есть она или нет. Я умею извлекать из ее отсутствия максимальную пользу в плане скорости разработки. Но опять же, это все фигня, главное это грамотная архитектура! В реальной жизни web приложения работаю с данными которые приходят из API, а то и из разных API сразу, вот где могут крыться реальные потенциальные проблемы, пришли данные не в том формате и всё, приплыли, а тут уже есть типизация или нету роли никакой не играет. Моя мораль такова, хочешь типизировать всё — пожалуйста, не хочешь — пожалуйста. Это чисто опциональный выбор, а не так как щас многие малюют что мол без TS вообще нереально ничто разработать, якобы большие и сложные проекты без TS не напишешь и т.д. и т.п..., так вот я реализовал и участвовал во многих сложных и огромных проектах, вообще без намека на типизацию, как на фронте, так и на бэке, и только с теми проектами где была нормальная архитектура можно было успешно работать и масштабировать до бесконечности, а остальные пиши пропало, на них благополучно п сей день бешеная текучка кадров, потому что очень мало мазохистов готовы работать с кучкой гуано. Если оверхед по кол-ву кода и по кол-ву затраченного времени возбуждает, то вы созданы чтобы типизировать всё и покрывать тестами каждую строчку кода да ещё и все возможные кейсы описывать в тестах. А я лично ценю своё время, его увы нельзя вернуть и купить за деньги, поэтому мой выбор это не типизировать и не писать unit тесты, благо от проектов где нету денег на тестировщиков в штате я отказываюсь просто, и получается все очень даже шикарно, быстро, просто, надежно и протестировано самым надежным инструментом (ручными тестировщиками)
НЛО прилетело и опубликовало эту надпись здесь
Ну и где же тут скорость разработки? Чтобы понять что принимает и возвращает функция нужно полностью её прочитать и вникнуть в логику работы

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

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

Так как параметры-то названы?)

Обычно все функции называю по принципу f1,f2,f3,..., все переменные var1,var2,var3,..., все классы C1,C2,C3,..., аргументы у функций arg1,arg2,arg3,… И т.п., это же общепризнанное соглашение в сообществе…

Я вам почему-то верю

НЛО прилетело и опубликовало эту надпись здесь
В проектах с грамотной архитектурой рефакторинг как правило не требуется, а если он все таки случается, то мелкий и локальный, поэтому тут просто нереально накосячить. Тем более если ты берешься за рефакторинг, то ты знаешь что делаешь, что изменяешь и проверяешь за собой естественно.
P.S. на трату/не трату денег мне наплевать, мне лишь не наплевать на своё время, которое нельзя вернуть и нельзя купить за деньги. Торчать целыми сутками в мониторе описывая типы и тесты, это не для всех. Кто-то ещё хочет и потратить время с пользой для себя, один раз живём как никак.
НЛО прилетело и опубликовало эту надпись здесь
А вы, ради интереса просто, какими проектами обычно занимаетесь? А то я вот глупый, выстраивание правильной грамотной™ архитектуры у меня займёт сильно больше времени, чем быстрое прототипирование.

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

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

Так это только при условии что весь ваш рефакторинг это просто переименование переменных, а не оптимизация кода в целом
Расскажите, что это за архитектура?
Моя собственная, которую с годами я усовершенствовал и усовершенствую по сей день. Конкретно в моем случае у меня есть архитектура для Web Front-end с React.js, и архитектура для бэкенда (для REST API) на Node.js и на бэке я кстати Typescript использую, он там реально полезен на мой взгляд (но в основном для продвинутого автокомплита в IDE конечно), а вот на фронте не использую осознанно.
На бэке значит просто MVC?
Не совсем, на rest api MVC не особо ложиться, т.к весь view это просто `JSON.stringify(resultResponseObject)`, так что это ближе к MC, но там где нету какой-то большой логики у меня сразу все в контроллере(запросы в базу и бизнес логика), а там где уже приличная логика, то уже разбиваю ее конечно. Если можно что-то вынести в функции или классы для переиспользования в других местах это разумеется тоже делаю. А в плане архитектуры кода и структуры файлов и папок тоже у всех все по разному.
НЛО прилетело и опубликовало эту надпись здесь
Эх, а у меня что-то так не получается, чтобы одна архитектура на все проекты.

Не знаю конечно что у вас за проекты, но у меня как для бэка есть одна на основе которой я разрабатываю все проекта, так же и для фронта. При чем на бэке она подготовлена и под монолит, так и под работу с сервисами(есть обертка для RPC через RabbitMQ), плюс обертки для Postgres, Mysql, redis и т.п. И на бэке у меня есть типизация, но она там ради продвинутого автокомплита.
НЛО прилетело и опубликовало эту надпись здесь
>А вы, ради интереса просто, какими проектами обычно занимаетесь?
Да понятно же. Веб. Это довольно типичная манера обобщать то, что имеет место у тебя, на все остальные проекты — даже если их никогда не видел.
если я вызываю ту или иную функцию я и так знаю чего она ждет в аргументах, а если не знаю и/или забываю, то просто нажимаю ctrl+на нее и сразу же вижу, что она принимает и как именно работает:

Чтобы «ctrl+на неё» работал нормально, нужно описывать аргументы в JSDoc-комментариях вида


/**
 * @typedef {{}} Options
 * @prop {string} color
 * @prop {number} [size]
 */

/**
 * @param {string} foo
 * @param {Options[]} bar
 */
function demo(foo, bar) {}

Иначе «ctrl+на неё» не будет «просто». Вместо JSDoc можно писать TS-аннотации, тратя на них столько же времени и сил, но в замен вы получите автоматическую проверку этих типов:


interface Options {
  color: string;
  size?: number;
}

function demo(foo: string, bar: Options[]) {}

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


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

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

Везде так работает. JSDoc нужен не для этого. Он нужен для того, чтобы описать сигнатуру функции (типы аргументов и возвращаемого значения), чтобы не приходилось переходить к исходному коду функции и изучать его. Если функция описана с помощью JSDoc или TS, вы можете зажать Ctrl, навести курсор на вызов функции и получить её описание.


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

Не надо ничего изучать, ведь название функции говорит о том, что она делает это раз, названия аргументов говорят о том, что именно эта функция принимает это два, и это в 99% случаев более чем достаточно, но опять же если страдает архитектура и код в целом, то приходится писать явно че к чему и зачем

Допустим вы пришли на проект, и там есть вот такой кусок кода:


class Client
{
    public function __construct($kernel, $server, $history, $cookieJar)
    {
        $this->kernel = $kernel;
        parent::__construct($server, $history, $cookieJar);
    }

    ...
}

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

У меня подход к проектам с таким кодом простой, либо переписывать с нуля такую дичь, либо просто ищу другой проект. Потому что я знаю что меня будет тошнить от этого кода и этого прототипа(потому что врятли это можно назвать спроектированным с архитектурной точки зрения) и задача которая при нормальном коде и архитектуре занимает условно час, тут будет занимать минимум х5 по времени + over риски что-то отвалится сбоку. Я не спорю что для таких вот тяп ляп проектов типизация полезна, да. Но для проектов с нормальной архитектурой можно без нее обходится вообще без напрягов.

Так я потому и спросил — что конкретно вы бы изменили в этом коде? Это вообще-то просто конструктор с параметрами, он в принципе не может быть написан неправильно, потому что по-другому его написать нельзя.

Это не просто конструктор с параметрами, этот конструктор вызывает ещё один конструктор. Я не знаю какую именно задачу решает этот класс, но я бы однозначно написал бы по другому, чтобы было все очевидно, просто и понятно.

По названиям переменных можно предположить, что это класс, который имитирует поведение браузера. Код из фреймворка Symfony.


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


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

Если вы используете код сторонних библиотек/фреймворков, то у него есть документация как правило, а когда вы сами пишете код, то будьте добры писать его так, что он был очевидным, простым и наглядным, чтобы можно было читая его сверху вниз сразу понять что происходит. И опять же если класс или функция очень замудрены, то можно элеметарно оставить комментарий в котором можно описать что делает эта функция и какие аргументы для чего используются. А для всех остальных(самых частых случаев) и так всё ясно исходя из названия функции и названий аргументов. Суть такая, да, бывают редкие случаи где необходимо оставлять комментарии, где одного названия не достаточно, а если проект состоит из целой кучи не очевидных и сложных классов/функций, то их все нужно описывать, PHPDoc, JSDoc, StoryBook, да как душе угодно вообще, то что для них буду объявлены типы не освобождает от того, что если вы не знаете для чего вообще эта функция служит, надо где-то это вычитать, у кого-то спросить или просмотреть код этой функции.

А вообще я стараюсь придерживаться принципа Kepp It Simple, и делать все просто и очевидно, дабы минимизировать кол-во функций которые требуют того чтобы прочитали их описание или изучили код новые разработчики, то что они будут типизированы в этом им никак не помогут, ну да они узнают на 1 секунду быстрее что аргумент X ждёт integer, а аргумент Y float, но того, что именно она сделает с этим аргументами они и не узнают пока не посмотрят код.

Так разговор был не о том, для чего функция служит, а о том, что туда надо передавать и оттуда принимать. Для чего она служит как раз должно быть понятно из названия. "Функция, вызывающая другую функцию" это и есть все остальные самые частые случаи.


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

Ещё раз, типизация не дает понимаю что конкретно делает та или иная сложная или запутанная функция, она лишь дает понимает вернет ли эта функция bool, строку, какой-то объект и т.п. и что она в себя принимает, но зная это, вы не будете знать все равно что конкретно она вернет и для чего конкретно она служит, коли она сложная и запутанная и все придется посмотреть и разобраться в ее коде, и тут вам типизация мало чем поможет, она просто дополнительный помощник, а не серебряная пуля. Просто если взвесить кол-во времени и дополнительную награможденность кода, то далеко не для всех проектов она реально нужна, более того она зачастую становится вредна т.к бюджеты у бизнеса не всегда резиновые и поэтому продукт стараются вывести в продакшен быстрее. А дальше 2 пути развития:
1) Если изначально было заложена хорошая архитектура, то проект замечательно продолжает развиваться и без разницы типизирован или нет;
2) Архитектура не было заложен, а было тяп ляп (в основном от не опытности и недостаточной квалификации, слишком велик соблазн нанять разработчиков подешевле) и тут самое интересное, надо делать фичи, фиксить баги и т.п., но с текущим прототипом этом просто боль и страдания и тут происходит ещё одно ветвление:
— Проект переписывается по нормальному с нуля и продолжает развиваться (разработчики рады);
— Разработчики не рады и ищут новые нормальные проекты, и тут идет постоянная текучка кадров и гуано код разрастается в геометрической прогрессии, а тут уже чтобы удержать хоть как-то разрабов приходится предлагать зарплаты сильно выше рынка, но равно или поздно не остается другого выхода кроме как написать все с нуля;

Пъедистал значимости:
1) Архитектура (требуются реально сильные разработчики)
2) Качество кода (требуются реально сильные разработчики)
— это 95% успеха и безпроблемного развития проекта — Далее все остальное, по желанию, бюджету, времени, типизация, тесты, шместы.

Учитывая то, что рынок разработчиков перенасыщен новичками и среднечками порой выдающими себя за ведущих специалистов они начинают проект с нуля, понимают что тут уже труба, уходят в другой проект, а остальным потом разгребать за ними. И то что такой типичный проект будет весть протипизирован снизит боль и страдания на 10% и то не факт, может и усугубит их, кривая архитектура + так себе качество кода + нагромождения с описаниями типов = бум, комбо, само счастье вливаться в такой проект.

И ещё, если речь о JS, то проектов с TS до сих пор крайне мало и это не спроста.
Ещё раз, типизация не дает понимаю что конкретно делает та или иная сложная или запутанная функция

Еще раз, нам не надо понимать, что конкретно делает та или иная сложная или запутанная функция. Надо понимать, какие конкретно переменные надо создать в месте ее вызова. Чтобы оно потом не упало с ошибкой типа "Unknown method" или "Cannot convert array to string", особенно если это происходит внутри какого-нибудь if только при определенных значениях. И лучше это не вручную контролировать, а компилятором.


Для понимания алгоритма впрочем типизация тоже полезна, но используют ее не за этим.

А вы вызываете функции не зная что они делают и для чего они?

Когда я вызываю (new Client(...))->request(...) или там calculateOrderPrice(...), я знаю, что они делают и для чего они, но мне совершенно неважно, насколько они сложные и запутанные внутри. Но при этом мне важно знать, какие переменные надо создать до этих вызовов, чтобы их туда передать.

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

P.S. Вообще тут идет о Typescript, в PHP я знаю что можно опционально типизировать, а в Typescript нельзя (костыли в виде any для всего не в счет, т.к засоряют код). Поэтому сравнение не особо корректное
Противоречите сами себе, если вы знаете что это за функции и как они работают, значит вы знаете какие аргументы и какого типа в них надо передавать.

Нет, не значит. Первая функция делает запрос к определенному URL, вторая делает расчет цены заказа. Это описание работы функций, и оно понятно из их названия. Зачем мне изучать их алгоритм? Мне надо просто передать данные и получить результат.


В противном случае вы не знаете или до конца не знаете как работает функция/класс и типы не освободят от незнания.

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

Так если вам все и так понятно из названия, какие могут быть проблемы с типами?) Вы же и так знаете из названия как именно работает функция и что именно она принимает) Это же и есть абстракция от реального мира)
Так если вам все и так понятно из названия, какие могут быть проблемы с типами?)

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


Вы же и так знаете из названия как именно работает функция и что именно она принимает

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

Вот смотрите, какая разница между этими вариантами, чтобы просто брать и пользоваться ей:
1) Она типизирована;
2) Она описана в документации;
3) Она описана в PHPDoc;
Если для самого первого использования вам так или иначе надо посмотреть что она делает, и какие аргументы и опции у нее есть. Если она типизирована, то вы видите только типы без описания и ничего более, возникает проблема, вы не знаете на 100% предназначение каждого аргумента и каждой опции. А если она описана (и при это уже без разницы типизирована она или нет), то в чем проблема ей пользоваться то? Варианты в стиле «А в друг я передам ей не тот тип в аргументе» не прокатывают, т.к это разряд единичных ошибок(которые отлавливаются сразу же когда вы выполняете код который только что написали) или ошибок начинающих разработчиков.
Напоминаю речь именно о плюс/минус сложных функциях, а не о простых, где названия самой функции и названия аргументов достаточно и они сами по себе являются описанием и документацией.
Если для самого первого использования вам так или иначе надо посмотреть что она делает, и какие аргументы и опции у нее есть.

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


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

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


А если она описана (и при это уже без разницы типизирована она или нет), то в чем проблема ей пользоваться то?

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


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


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


"Calling unknown method calculate()" — как исправить эту ошибку? А если ошибка будет "Argument 1 must be instance of DiscountCalculator"? Есть разница?)


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

Не сразу. Потому что есть такая штука как оператор "if", и часть кода выполняется только при определенных условиях. Есть вызовы в разных местах, и можно поменять саму функцию и код выполнится без ошибок, зато перестанет работать другой код, который не выполняли, но который тоже вызывает эту функцию. Есть передача результатов одних функций в аргументы других, и можно поменять обработку во всех местах вызова, но не поменять в функциях, куда результат вызова передается. С типами ошибка возникает сразу при первом несоответствии, или даже еще до выполнения в подсказке IDE.


Напоминаю речь именно о плюс/минус сложных функциях

Именно поэтому я привел в пример выполнение URL-запроса, где аспектов настолько много, что сделан отдельный класс, и часть из них передается в конструктор. Вы по названиям аргументов и без изучения исходного кода функции ответить на вопрос о типах аргументов не смогли.

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

Так никакой типизации в таком решении и не будет подавно, и вообще в таком случае не стоит использовать это стороннее решение и написать всё самому. Так что, аргумент не засчитан.

Подводим итог, типизация выигрывает у сложных функций/классов которые больше вообще нигде и никак не описаны — факт. Но, если сложные функции/классы вообще не протипизированы, но описаны, то увы и ах этого более чем достаточно. Если все так просто и лазурно было, то все бы писали код без багов со времен C, но реальность совсем другая, поэтому типизация это так, просто небольшой помощник для продвинутого автокомплита в IDE, а так же помощник для начинающих разработчиков, которые постоянно пытаются запихнуть в функции совсем не то, что требуется.
У динамической типзации свои плюсы/минусы
У статической типизации свои плюсы/минусы
Победителя НЕТ и быть НЕ МОЖЕТ. Кто хочет тратить гораздо меньше времени на клациние по клавиатуре выбирает динамическую типизацию и сосредотачивается на задачах для бизнеса и архитектуре проекта, кому в кайф написать как можно больше символов в коде, ну и для тех есть выход — статическая типизация.
Так никакой типизации в таком решении и не будет подавно, и вообще в таком случае не стоит использовать это стороннее решение и написать всё самому.

Какое стороннее решение? Я не говорил ни про какие сторонние решения, только про ваши примеры. Если в документации типы не описаны то проблема что туда передавать остается, если описаны, то лучше их написать в коде.


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

Выигрывает даже если написаны. Потому что документация написана где-то там и читает ее только человек, а типы написаны в коде, и читает их в том числе и компилятор.


Но, если сложные функции/классы вообще не протипизированы, но описаны, то увы и ах этого более чем достаточно

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


Если все так просто и лазурно было, то все бы писали код без багов со времен C

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


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

Я вам в предыдущем комментарии привел пример, который от опыта разработчика не зависит. Это изменение требований и связанные с ним изменения в коде. В одном месте поменяли, в другом нет. Ни компилятор ни IDE же не подсказывают. А если вы здесь решили возразить в стиле "вам лишь бы кто-то подсказывал", значит не работали с достаточно большими проектами, где один человек не может знать всё.


свои плюсы/минусы. Победителя НЕТ и быть НЕ МОЖЕТ

Верно. И это сильно отличается от вашего изначального категоричного высказывания "Залог успеха это только отличная архитектура проекта, а типизирована она или нет, особого значения уже не играет".


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

Неверно. Для одноразового "тяп-ляп и в продакшн" возможно да. Для постоянной поддержки и сложных проектов нет. Без типизации вы потратите гораздо больше времени на поиск причин ошибок при изменениях.

надо, просто, человеку написать, какое-нибудь среднее приложение на elm-е. Да, еще, проводя в малые сроки refactoring, в связи с изменением требований. Может тогда поймет, про что речь идет.
При этом, с одной стороны, часто можно и не писать типы — сами определятся компилятором, с другой стороны, в стиле ФП, как правило, код получается гораздо компактнее.

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

Т.е если все типы совпали это означает, что код будет работать именно так, как ожидается, и разумеется нет нужды его проверять верно?
НЛО прилетело и опубликовало эту надпись здесь
Мне кажется, что, все же, цель абстракции не в том, чтобы не было необходимости разбираться, как оно работает, а, чтобы была возможность сделать общее решение задачи для различных частных случаев. Т.е., абстракция — обобщение решения.

Та же инкапсуляция и сокрытие, не для того, чтобы не лесть в реализацию. Может в ряде случаев и надо залесть в реализацию. Инкапсуляция — для того, чтобы в коде, который использует конструкцию, пользовался только интерфейсам, чтобы можно было безболезненно изменять код.
В том то и дело, michael_vostrikov говорит, что если применить теплое к мягкому, то вообще всё в шоколаде и думать ни о чем не надо и знать тем более.
для того, чтобы в коде, который использует конструкцию, пользовался только интерфейсам

Это и есть "для того, чтобы не лесть в реализацию".

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

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

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Если вы используете код сторонних библиотек/фреймворков, то у него есть документация как правило, а когда вы сами пишете код, то будьте добры писать его так, что он был очевидным, простым и наглядным

Так вы продемонстрируйте, как этот код написать так, чтобы он был очевидным, простым и наглядным, в чем проблема?

Плюс того же JSDoc'a ещё в том, что ты можешь описывать только реально сложные функции и классы, а все очевидные явные и так нету смысла описывать, там и так все понятно как 2+2

TS тоже не обязывает описывать всё. Можно даже смешивать JS и TS в одном проекте.

Да, но тогда смысла вообще нету тащить TS в проект, если тащить TS, то чтобы без единого any все было, а иначе это просто очередная полумера как и почти везде «у нас же TS в проекте, мы же все такие крутые». Я использую TS но только на бэкенде, а не на фронтэнде и мне он нужен реально только для продвинутого автокомплита, а не для проверки типов, поэтому у меня там есть any да, но я и не обманываю сам себя, я честно и прямо говорю что в моем случае это только для продвинутого автокомплита и не более.

А на фронте вам автокомплит не нужен?

Конечно такие ошибки возможны, но при нормальной архитектуре и коде их процент исчезающе мал, я вот не припоминаю что-то таких случаев ставших реальной проблемой, хотя всегда работал на языках с динамической типизацией.
Фух, а я то уж думал, что кроме меня никто не придает архитектуре самую высокую степень важности
Я считаю, что в критичных сферах мы должны использовать все доступные инструменты обеспечения надёжности, и статическая надёжная система типов один из них, но во-первых, не во всех сферах это важно, а во-вторых, это далеко не самый главный инструмент, ибо типизация умеет ловить самые простые, очевидные ошибки, а вот хорошая архитектура просто реально уменьшает число ошибок, ибо когда архитектура и код устроены просто и понятно ошибаться просто негде, а случайные ошибки легко находятся.
А при плохой архитектуре и коде можно понаделать ошибок при полной корректности всех типов.
Именно
НЛО прилетело и опубликовало эту надпись здесь
Ну если речь про ошибки синтаксиса, то опять же это не является реальной проблемой для абсолютного большинства приложений т.к. самое примитивное тестирование их выявит.
А вот обнаружить ошибку в запутанной логике спагетти-кода система типов не может.
НЛО прилетело и опубликовало эту надпись здесь
Это конечно достаточно продвинутые проверки, но во-первых, они попадают в ту же категорию достаточно простых (ибо их отсутствие не означает правильности кода), а во-вторых, они скорее про теоретические возможности продвинутых систем типов, на практике мы имеем языки где нельзя складывать строку с числом и на этом вся типизация закачивается.
НЛО прилетело и опубликовало эту надпись здесь
Конечно это разные вещи, но все они верные и в пользу того, что архитектура важнее в массовых случаях т.е. того, что не нужно преувеличивать важность типизации в создании качественного софта. Пока формальные методы не в ходу качественный софт создаётся не на языках с самой сильной типизацией, а умными людьми на любом языке.
Конечно статическая типизация лучше чем динамическая — просто потому, что статическая типизация может включать в себя динамическую как частный случай (а вот наоборот не получится). Достаточно ввести какой-то тип «dynamic» или «any», для объектов которого будут применяться правила динамической типизации (в том числе с поддержкой со стороны компилятора). Если вы любите динамическую типизацию — просто объявляйте ВСЕ объекты этого типа, и будет как в JS или PHP. Но зато тем, кто предпочитает статическую, не придется плакать горючими слезами при попытках повторного использования такого кода: достаточно будет уяснить по смыслу программы, какого конкретно типа должна быть переменная — заменить в объявлении «any» на этот конкретный тип… и возможно увидеть предупреждения и ошибки компиляции при попытке использовать эту переменную как объект другого типа:)
Нетипизированные языки — программы просто исполняются
Отличная фраза в статье про типизацию.
Когда вы проверяете введённые пользователем данные, выясняя, могут ли они рассматриваться как число — вы выполняете динамическую проверку типа.
То есть нет никакой разницы между проверкой типа и проверкой что строка является валидной репрезентацией числа, да? В статье про типизацию.
в результате разбора может быть выдано исключение или возвращено нечто вроде NaN
Ну да, например когда мы парсим целое число, это же так удобно. NaN – это валидный экземпляр типа float. Он не может быть ошибкой парсинга ни целых чисел, ни даже типа float.
Означает ли применение статических типов знание типов во время компиляции программы? Нет. Оказывается, что парсер знает о том, что”test”— это строка. Делает ли это JavaScript языком со статической типизацией? Нет, не делает.
Просто отвал башки. Автор задал вопрос и тут же ответил на него, спутав причину и следствие.
Видите его? По экрану движется «планер». Правда? А теперь давайте немного притормозим. Существует ли этот «планер» на самом деле? Это — просто отдельные квадраты, которые появляются и исчезают. Но наш мозг может воспринимать эту структуру как нечто, объективно существующее.
Видите текст? Он состоит из осмысленных предложений. Правда? А теперь давайте немного притормозим. Сущевствует ли здесь смысл на самом деле? Или это просто отдельные буквы, которые святятся на экране, а наш мозг воспринимает их как нечто осмысленное?
Дополню чуток на пальцах про:
Означает ли применение статических типов знание типов во время компиляции программы

может это проблема перевода, но понятнго, что ответ положительный, видимо имелось ввиду «Означает ли знание типов на стадии компиляции статичность типизации?» вот того ответ нет.
Да, вы правы, в оригинале было: Isn't static types is when you know types at compile time?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий