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

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

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

После этого не читал, очевидно что это исповедь идиота.

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

Подозреваю, что человек тупо не заморачивается на чтение спецификаций на язык программирования с которым он работает, а что касается конкретно этого утверждения, то так можно любой язык признать плохим:
— Лисп — убейте, слишком много скобок
— PHP — убейте, от знаков доллара рябит в глазах
— ASM — убейте, классов нет
НЛО прилетело и опубликовало эту надпись здесь

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

Стесняюсь спросить, а как себя поведет в такой ситуации gcc в си?
Спойлер: проглотит не подавившись.
Хотя бы тип результата не зависит от арифметической операции)
НЛО прилетело и опубликовало эту надпись здесь
То что Вы озвучили — это придирки к синтаксису, а отсутствие хоть какого-то type-checking — это уже семантическое свойство, приводящее к огромному количеству ошибок, которые никто не отлавливает ( в JavaScript ).
То, что я озвучил это то как оно написано и работает. Мне тоже многие вещи не нравятся, к примеру логика работы указателей в си подобных языках является для меня весьма сложной для понимания, но было бы в высшей степени глупо с моей стороны написать что нибудь типа: Убейте C++, работа с памятью и указатели там — это просто бред, думаю C++ не подходит для написания приложений, он слишком сложный. И ладно бы если бы я прокодил бы на сях лет 20 и пришел бы к этому мнению написав миллион вещей, но нет, мой путь Arduino -> QT -> C#
Логика работы указателей на С++ — сложно? А вылавливание в JavaScript ошибок, которые в С++ выскакивают на этапе компиляции — очень простая и, главное, полезная работа? Логичненько.
Основной посыл был не про то, что одно де сложно а второе вот не сложно, а про то, что в каждой вещи есть свои подводные камни, возможности отстрелить себе ногу и прочие фишки. Пример: Ну не умеешь / не хочешь ты разбираться с принципами выделения / освобождения памяти в сях, ну программируй на чем нибудь другом, но если ты не разобрался в этом, этож не значит что они плохие верно?
Применительно к ситуации: не умеешь / не хочешь контролировать то, что тебе приходит на вход — сам виноват, винить в этом «кривость» языка — неправильно.
А то получается какая то подростковая логика вроде как РЭП — это кал, а почему? А потому что он мне не нравится и слушаю я Курта Кобэйна.
Ну так работа с памятью в С — это важный его атрибут, как языка, ориентированного на высокую производительность. А отсутствие type-checking в JavaScript какую пользу приносит? Дело ведь не в том, что я хочу type-checking, дело в том, что я мог бы безболезненно его получить ( как минимум я не вижу препятствий ). По мне так это просто самый лютый факап разработчиков языка))
Ну так работа с памятью в С — это важный его атрибут, как языка, ориентированного на высокую производительность.
Именно! Это не баг, не странный баг, не недокументированная особенность — это просто то как оно есть, а вот вопрос нравится это вам или нет — это уже дело сугубо личное. Не думаю, что человека, который позиционирует себя как разработчика на C, при приеме на работу оценили бы по достоинству если бы он назвал работу с памятью — лишним не нужным никому геммороем.

А отсутствие type-checking в JavaScript какую пользу приносит? Дело ведь не в том, что я хочу type-checking, дело в том, что я мог бы безболезненно его получить ( как минимум я не вижу препятствий ). По мне так это просто самый лютый факап разработчиков языка))

Изначально ES задумывался как интерпретируемый язык программирования (не берем в учет то как его обрабатывают современные JS движки c их JIT'ами и оптимизациями), так вот при такой схеме, иногда бывает весьма сложно (если не невозможно) понять какого конкретно типа значение является операндом того же арифметического выражения. 1 + '1' это очень простой пример, возьмем ситуацию когда вместо литералов у нас переменные:

var left = 1;
var right = '1';
var result = left + right;

Тут нужно уже прогнать весь код через проверку типов для того чтобы понять что за тип у left и right, для того чтобы в итоге проверить существует ли возможность применить оператор "+" к данным типам данных. А что если одна из переменных объявлена за пределами модуля в котором выполняется выражение? Прогнать и этот модуль, а что если этот модуль загружен извне? Загрузить его и прогнать? А что если этот модуль нами не управляется? Благодаря всем этим «а что» и «а если», мы получаем существенный удар по производительности (если говорим о проверке типов в рантайме), если же такую проверку производить до рантайма, то нам нужно скачивать вообще все что имеет отношение к нашему приложению, что в свою очередь не есть плохо или хорошо, просто это уже превращается в другой язык программирования.
Вот видите, Вы отлично понимаете эту проблему JavaScript'а. Предложение автора было как раз отказаться от этого дерьма. Так в чем же идиотизм такого предложения?
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Что ну вот? А если модуль без аннотаций? Аннотировать? Или искать модули только с аннотациями, либо же железный аргумент из коммерческой брошюры: «На TypeScript портировано уже все что возможно и даже некоторое из того что в принципе еще не написано а будет написано только через 3 — 4 года».
НЛО прилетело и опубликовало эту надпись здесь
Да, но это уже другой язык получается! Нафига наворачивать эти костыли там где их изначально не планировалось. Вот если бы это в стандарт языка включили и было бы что то типа: на те типизацию, хошь пользуйся хошь не пользуйся, тогда другое дело.
НЛО прилетело и опубликовало эту надпись здесь
Вот это вот хуже всего, на самом деле, потому что это очень сложно сделать правильно.

Ну вы то надеюсь поможете сделать правильно, если понадобится?
НЛО прилетело и опубликовало эту надпись здесь
У меня есть впечатление, что правильно — это через зависимый тип-сумму вида (a: Type ** a)

Зачем здесь зависимый тип? :hz:


С хошь пользуйся хошь не пользуйся проблема в границах между типизированным и нетипизированным кодом, не совсем понятно, что там делать.
В Racket пытались, но там очень мощная система контрактов, которая позволяет автоматически заменять аннотации типов в типизированном коде при импорте в нетипизированный на контракты, с-но soundness остается просто на уровне рантайма и по крайней мере мы получаем блейм контракта по типу в том месте, где типы не совпали, а не черт знает где, что сохраняет корректность в итоге. Только для этого надо уметь делать контракты на ФВП и на параметрически полиморфные ф-и, чего я больше-то нигде и не видел, плюс в определенных случаях это приводит к существенной деградации производительности.
Альтернативный вариант — просто тупо типы забывать, но в этом случае гарантированно корректный код перестает быть корректным и зашкваривается об границу.

НЛО прилетело и опубликовало эту надпись здесь
А вот еще вопрос возник в связи с этими опусами, а что вообще вы собрались писать с использованием данных хитроумных типов данных на джаваскрипте? Есть пример может какой нибудь. А то что то у меня есть большие сомнения насчет того, что это все кому нибудь пригодиться и это все не прикручивание костылей ради процесса прикручивания.
НЛО прилетело и опубликовало эту надпись здесь
Ясно.
Потом, в принципе, никто не мешает заматчить на первый (или даже на второй) элемент пары, кроме криво реализованной проверки на parametricity в идрисе.

А чем это отличается от:


const lst1 = [42, 'meh'];
const lst2 = ['wuh', 13.0];
const lst3 = [42, 13.0];
const lst4 = ['meh', 'wuh'];

const zip = <A, B>(l1: A[], l2: B[]) => l1.map((a, b) => [a, l2[b]] as [A, B]);

const res = zip(lst1, lst2); // [string | number, string | number]
const res2 = zip(lst3, lst4); // [number, string][]
const res3 = res2.map(x => x[1]); // string[]

?

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

Ну в примере выше то же самое. В третьем кейзе (res3) статически понятно что первый элемент — точно строка, а в первом — мы этого не знаем, с-но надо поставить на тип string | number гвард:


const x = res[0][0];
x.length; // error
if (typeof x === 'string') {
    x.length; // ok
}
НЛО прилетело и опубликовало эту надпись здесь

Тайпчекер напомнит. Вторая строчка не компилируется без гварда, ошибка типов там, т.к. у типа number нету свойства length.

НЛО прилетело и опубликовало эту надпись здесь
Так, стоп, а это какой язык? Я чё-т думал, что всё ещё JS.

Typescript, так что почти верно :)


Если там есть статические типы, то какой тип в общем виде выводится у списка? Variant из всех имеющихся в нём?

у res1 будет тип [string | number, string | number][].
A[] — список из А,
[A, B] — пара из типов А и В (списки из конкретного конечного числа элементов вместо таплов выступают)
string | number — объединение (неразмеченное!) типов А и В.
С-но, получаем список из пар, элементы которых — строка или число.


Что будет, если я добавлю туда ещё какой-нибудь объект типа person?

будет [string | number | Person, string | number | Person][].
Списки и таплы там базовые типы (ну, стоит оговориться сразу, что списков в тс нет, т.к. тс — это просто js с типами, с-но список там это тот же массив, он же хеш, он же Гога, он же Жора...), [A, B] — подтип для [A | B][].
rest generics пока не завезли, так что руками такой полиморфный конс написать не выйдет, можно сказать что для каждого конечного числа там свой предефайненный конс.


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

readFileSync возвращает string либо Buffer (в зависимости от перегрузки), Buffer в свою очередь имеет ф-и для чтения чисел разного формата, наследует Uint8Array, и, кроме прочего:
toJSON(): { type: 'Buffer', data: any[] };
с-но тут зашквар, потому что any — это тип который assignable to и assignable from для любого типа. То есть универсальный подтип и супертип. С-но, на нем можно вызывать любые операции без гвардов (нужен этот тип
в основном для использования библиотек js, окторые не имеют нормальных тайпингов, просто можно поставить классу any и вызывать на нем любые методы, которые будут возвращать, в свою очередь, тоже any).
Правда, сейчас (в 3.0) добавили тип unknown — это классический Top и по идее типизировать такие вещи надо будет через него.

НЛО прилетело и опубликовало эту надпись здесь
Ну вот в этом и разница. С List Dyna не нужно никаких полиморфных консов, все такие списки имеют один и тот же тип.

List Dyna этот в данном случае тот же unknown[], так что разницы нет. Просто тайпчекер сразу сузил тип с any[] до [(number | string), (number | string)][].
Не забывайте, что при сабтапинге тип любого значения не только самый узкий, но и любой его надтип.


А так-то я и на С++ вам с std::variant могу наваять, чтобы проверки обязательно были нужны

Не получится, т.к. в сишке гвардов нет. То есть вам компилятор не гарантирует, что в вашем variant останется то что нужно, а не бяка, и не сузить тип когда гвард есть, а в этом ведь с-но вся суть.


Ух, наркомания какая.

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


Например, я выше приводил пример с проверкой того, что при запросе на сервер мы не попросим несуществующих полей — соответствующий инвариант на типах фиксируется одной строчкой. А есть эта возможность в типах благодаря тому, что надо было умять типизировать код вида getProperty(object, "propertyName").

НЛО прилетело и опубликовало эту надпись здесь
Именно! Это и есть полностью динамический список, в этом и смысл!
При этом, в очень жёстко типизированном языке.

Ну вот тайпскрипт — жестко типизированный язык (если any убрать, но в теории с-но any и нет, это вполне конкретный костыль для вполне конкретных кейзов, по-этому можно его не учитывать), в нем это все есть и не требует всякого рокетсаенса в виде зависимых типов :)
Вы просто про зт в качестве решения упомянули — и я привел это дело все в качестве примера того, что зт тут явный оверхед и из пушки по воробьям. Вообще говоря, для зт трудно привести пример задач, где они не оверхед — это слишком универсальный инструмент, и потому крайней неудобный.


Это удобно до первой неконсистентности.

Во-первых, все, что выше описано — полностью консистентно, в смысле существования soundness варианта (именно такой вариант реализован в Racket, ну оно и понятно, академический язык все же).
Во-вторых, в случае тайпскрипта консистентность намеренно нарушена в некоторых случаях (наличие any и косяки с вариантностью) — и как раз для удобства. Так что в общем случае это консистентность противоречит удобству, а не ее отсутствие…
Ну с-но вы сами дальше про хаскель пишите, где так же консистентность приносится местами в угоду удобству :)
К слову вот в flow (типизированный js от фейсбука) тоже угарали по soundness, "более лучшему" выводу типов и другим вещам, которые любям теоретики. И нафиг никому не нужен теперь этот flow, в отличии от тс.

Ну вы полностью правильно сказали, большой UI проект на С++ это как опера, написанная под одного выдающегося исполнителя — она красива, когда есть достойный певец, но абсолютно провальна во всех остальных случаях. Для примера можно почитать про Simon Boccanegra. Естественно, могут быть исключения, в основном за счет соблюдения идеальной дисциплины и единого стиля в команде.

P.S. Кучу лет жизни я отдал работе с MMC оснастками, поддерживая и развивая воотчину лапшекода. Но потом в момент появления MMC 3.0 с поддержкой .Net, мой скилл очень быстро стал не нужен — новый инструментарий позволил молодым разрабам писать красивый код, использовать сторонние библиотеки, а не мучаться на C++ с встроенным IE 6 движком и передачей данных COM-объектами а-ля `COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)`. Так что, мало ли, может и JS в вебе что-то рано или поздно заменит. Ну или все привыкнут и будут работать как есть :)
Простите, есть разница между тем, чтобы знать спецификации и считать их хорошими, последовательными, логичными и пр.
Это бесспорно, разница есть, но в случае если бы интервьюируемый ее понимал, то фраза начинающаяся со слов «И там очень странные баги», начиналась бы как нибудь иначе.
Просто не стоит воспринимать слово «баг» буквально. Он мог бы сказать «необычная фигня» или что-то подобное.
НЛО прилетело и опубликовало эту надпись здесь
А мне слишком много табов.

Переходите на пробелы!

Но их будет в 4 раза больше!
НЛО прилетело и опубликовало эту надпись здесь
Обмазать тестами и проблем не будет.

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

Нет ничего страшного в том, что 1 + '1' — 1 = 10.

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

Да блин, нет у JS никакого компилятора, он интерпретируемый!

Ну, признаться, в большинстве популярных реализаций JIT всё же есть. А это почти что нормальный (кейворд — "почти").

Да вы что) У TS он есть. А в JS-моей-мечты можно было бы запилить рантаймовые проверки, вместо интегрированного похренизма с приведениями. Вышел бы не(такой)плохой тулчейн.
Так и запилите! Соберите в кучу все, что вы хотели бы реализовать и создайте на основе своих желаний новый язык программирования, который решал бы кажущиеся вам и другим разработчикам, критичными проблемы. Будет круто!
У меня вот к примеру мечта это что нибудь настолько близкое к железу как си но без ручного управления памяти и без сборки мусора, да все чот времени не хватает сделать, а то бы я уже давно )
C++ с RAII же)
А вот ребята чот нашли время и сделали Rust
А Rust вам чем не угодил?

А касательно дискуссии выше, то на JS гонят справедливо, как справедливо гонят на PHP, C++ (ооо, там вообще эпичные баталии) и чуть ли не каждый первый язык. Все они не без недостатков; и хорошо что есть недовольные, иногда настолько, чтобы что-то менять к лучшему. Я сейчас выскажу крайне непрофессиональное и сугубо субьективное: JS легче убить, чем починить (мечты-мечты). Но я-то знаю, что это моя личная заморочка, которую, похоже, разделяет немало других людей, но менее заморочкой от этого она не становится. Но и выгораживать откровенно контринтуитивное поведение спецификациями — это точно такая же заморочка, только вида «прощу всё потому что этот язык мне нравится».
НЛО прилетело и опубликовало эту надпись здесь
Это ещё хорошо, что 1 + '1' — 1 = 10, а не, например, 10.00000000000000004
Да нееее, запретить делать 1 + '1' в этом вообще никакой проблемы нет, такое можно выловить еще на этапе парсинга, это все фигня, проблемы начинаются когда у нас вместо 1 — переменная уходящая в кусок кода подгруженный хз откуда, а вместо '1' вызов пользовательской функции которая в зависимости от фазы луны может выдать или строку или булеан.
НЛО прилетело и опубликовало эту надпись здесь
Давайте вы такие вопросы будете своей девушке задавать, скорее всего в ее глазах это покажется умным. Если же вам реально интересно знать, как он работает, то не поленитесь открыть www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf, домотать до 257ой страницы и почитать.
А если вкратце, почему оно в тот момент, когда определяет какой оператор выполнить не может просто падать с ошибкой?
Кто определяет какой оператор выполнить? typeof?
Ядро интерпретатора или что там у него.
Очевидно, что в
var a = 42;
var b = '42';
var c = a + b;

и
var a = 42;
var b = 42;
var c = a + b;


Будут выполнены разные операторы, в первом случае — конкатенация, во втором — сложение.
Т.е. тут уже интерпретатор в курсе, что различие есть и типы известны. Почему не упасть с ошибкой вместо этого?
До буквы не скажу, но близко к тексту могу пересказать: в случае если один из операндов оператора "+" является строкой, второй операнд приводится к строке и выполняется конкатенация двух строк. Это написано в стандарте, поэтому мне не понятно зачем ему падать с ошибкой, тогда как в стандарте написано иначе.
Собственно многие, как и я, не понимают зачем стандарты которые такое позволяют.
Блииин:
— ну а зачем в питоне код индентируется табами? Ну неудобно же пипец просто
— зачем в Паскале оператор присваивания ":=", два символа вместо одного?
— почему в джаве нет беззнакового целого (uint)?
— зачем в php строке конкатенируются через точку? странно и непривычно же.

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

Но вы ведь не такой да? Вы ведь нам напишете язык программирования лишенный абсолютно всех недостатков? Идеальный, абсолютный, такой чтоб и через 300 лет никто не нашел бы в нем ни единого изъяна.
Зачем что то писать когда хороших языков уже достаточно? Dart, C#, Kotlin, да даже python, там типизация хоть динамическая но строгая, да и прикручиваются проверки типов.
Наличие или отсутствие типизации не делает язык хорошим или плохим. Это дело вкуса / привычки / потребностей. Это как коробка автомат vs механика. Кому то нафиг не нужно за палку дергать и они вообще не понимают адептов механики, а те наоборот считают что автомат не позволяет им получить полное управление над автомобилем. Но несмотря на это и то и другое вполне себе ездит.
Disclaimer: Я не пытаюсь доказать, что ЖС — уебанский язык и он должен немениуемо сгинуть прям вот сейчас. Более того, я считаю, что если его что-то и должно заменить, то это должно быть некое его развитие, чтобы переход был безболезненным. Хотя лично мне ЖС — не нравится, но это вкусовщина и я не навязывают своей ТЗ.


>Это написано в стандарте, поэтому мне не понятно зачем ему падать с ошибкой, тогда как в стандарте написано иначе.

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

А когда появились классы пришлось вместо this.value писать $this->value, так как точка была уже занята. При этом использований -> наверное в десятки раз больше, чем использований точки. Но исторически так сложилось, от этого уже не уйти.
А мне это всегда нравилось:
+ '1' + 1 == 2
Запретить делать 1 + '1'? Это странно, ибо интерпретатор/компилятор тогда должен парсить каждую строку


Нет ничего страшного в том, что 1 + '1' — 1 = 10.


Думается мне, мнение 0xd34df00d по поводу этих предположений было бы интересно послушать.
Я бы лучше Никлауса Вирта на эту тему послушал, да врядли он присоединится к дискуссии.
НЛО прилетело и опубликовало эту надпись здесь
Я не настолько увлечен этой темой мой друк.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Это не конструктивно.
Какой контроль нужен? Запретить делать 1 + '1'?

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

А до TypeScriptа были (и есть) гугловые type — annotations и GCC эту тему тоже решал. А что если я хочу чтобы функция принимала аргументы двух различных типов? Писать две функции с одинаковым именем и перегрузкой по типу аргументов? А что если я хочу чтобы моя функция принимала на вход в качестве аргумента массив массивов — элементами которых являются лишь объекты содержащие в себе строго определенный набор полей? Это тип или еще не тип?

В Typescript для этого есть Union-типы и compile-time-интерфейсы.

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

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

Но это же не от того, что его хотели выкинуть, это просто развитие. Как в C# добавили когда-то dynamic.
Динамическая типизация имеет свои плюсы и минусы, как и строгая. И писать, что JS говно и не подходит к веб из-за динамической типизации, как минимум странно.

Типизация у JS не просто динамическая, а еще и слабая (в отличии, скажем, от Python).
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Ошибки типизации ну так редко случаются, что я даже не помню когда последний раз у меня это было. Тем не менее, если вы пишете код, который будет использовать кто то другой, кто может ошибиться и хотите явную ошибку то проверьте тип руками
if(typeof param1 !== 'string') { throw new Error('string expected'); }
if(!Number.isFinite(param2)) { throw new Error('not a number'); }
if(!Number.isInteger(param3)) { throw new Error('int expected'); }
НЛО прилетело и опубликовало эту надпись здесь
Как и любой другой код. Но он и не должен выглядеть прекрасно, прекрасно должен выглядеть конечный продукт. Это не только про программы, любой красивый продукт состоит из деталек разной степени уродливости.
НЛО прилетело и опубликовало эту надпись здесь
Если вы пишете конечный продукт, то да, это лишнее, но если фреймворк или полуфабрикат, то очень даже заморачиваются, я часто вижу, как делается проверка типов присланных аргументов, но хорошей практикой считается не выбросить исключение, как можно быстрее, а если это возможно, корректно обработать с учетом типов.
typescript хорош и я бы на него с удовольствием перешел, даже не столько из за типов, но всю контору не пересадишь, было много попыток не только с моей стороны, а мы стараемся использовать тот же стек технологий в разных проектах.
НЛО прилетело и опубликовало эту надпись здесь
При чем тут фреймворк?

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

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

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

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

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

Линтер вам покроет едва ли единицы процентов от всех кейзов

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

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

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

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


уже сколько лет, ни разу не было проблем с типизацией в рантайм

Они были, просто вы не считаете эти проблемы проблемами типизации. Хотя нормально написанные типы эти проблемы бы отловили.


Изменение апи между отдельными модулями это всегда и везде проблема

В описанной мной схеме никаких проблем нет.


сервер может добавить от себя немного мусора.

Не может. Сервер возвращает ровно то, что указано в типе соответствующего контроллера, иначе не скомпилируется.

D Python может благодаря аннотациям.
Эти проверки выполняются только в рантайме.
НЛО прилетело и опубликовало эту надпись здесь
Пишите сигнатуры через которые можно понять тип, используйте JSDoc там где нельзя, Idea умеет проверять типы и работает интелисенс, основываясь на этом
/**
 * @param {Date} date
 * @param {Number} days
 * @returns Date
 */
function addDays(date, days){} // даже без JSDoc понятно какие типы присылать, нет?

function addUser(user){} // речь о типе User

function addUser({firstName, lastName}){} // еще вариант сразу видеть, что функция ожидает

function setName(name){} // типов в js немного, очевидно name это строка, а не число

fuction setCounter(counter){} // counter - очевидно число

Я много лет писал на строго типизированных языках и поначалу мне было очень неуютно без типов, но сейчас я считаю, что без них лучше, меньше мусора. Но привыкание берет время.
НЛО прилетело и опубликовало эту надпись здесь
function addUser(user){}
function addUser(User user){}
function addUser(user: User){}

Первый вариант короче, это особенно заметно, когда параметров больше.
НЛО прилетело и опубликовало эту надпись здесь
fuction setCounter(counter){} // counter - очевидно число

Ну да, вам очевидно, ведь вы только что написали это! А мне вот совсем не очевидно. Может, это функция, которая возвращает число:
function createCounter () {
  let i = 0;
  return () => ++i;
}


А может инстанс специального класса? Про User для вас ведь почему-то очевидно, что это тип, а не строка, к примеру.

Да, пока у вас три строчки кода — оно всё очевидно.

function setName(name){} // типов в js немного, очевидно name это строка, а не число

Опс, а когда появился тип User в JS? Может name — это boxed-значение из какого-то реактивного фреймворка вообще?

function addUser(user){} // речь о типе User

Ну вот мне дали задание дописать какую-то фичу в эту (ну или похожую функцию). И как я буду знать, какие поля есть в user? Мне передадут нормальный объект или какой-то любитель динамической типизации решит: «а, пофиг, firstName и lastName будет достаточно, больше там ничего не нужно!». А если это вообще не инстанс класса, а какой-то hash, как сейчас модно (классы ведь пишут только задроты, сейчас у хипстоты в моде «недо-фп»). И ты никогда точно не знаешь, что можешь использовать там. Потому что даже если ты поставил бряку и посмотрел, что тебе прилетел объект, а в нем есть поле id, то в другом месте какой-то сторонник прогрессивного подхода решил, что id тут не нужен.

Проблема вашего примера в том, что он абсолютно стерилен. Пока это что-то простое из разряда «setName» — может оно и работает немного. Но возьмите любой говнокод на редаксе и чтобы понять, что вошло в функцию — необходимо поставить брейкпоинт, запустить браузер и посмотреть, что же туда приходит и какие поля есть у этого объекта. И именно в такие моменты начинаешь ненавидеть динамическую типизацию.

Но если сложность вашего кода уровня ваших примеров, то понятно, почему её вам достаточно
Кстати, вот пример из реальной жизни. Есть библиотека react-rnd и одна функция принимает параметр enableResizing. Как думаете, какой тип этого параметра? «В JS не так много типов, так что однозначно boolean», скажете вы? Счасливой отладки! Это хеш!
Хороший пример плохого нейминга, не стоит так делать даже в языках со строгой типизацией.
Вот только я живу в реальном мире, где есть библиотеки со всяким неймингом и тайпчекин в таких случаях очень помогает.
Если вы даете названия которые не отражают суть, то и типы вам не помогут, там тоже можно написать в названии одно, а по факту там будет другое и такое встречается, надо так:
function createCounterFactory () {
  let i = 0;
  return () => ++i;
}


И как я буду знать, какие поля есть в user?

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

А если это вообще не инстанс класса, а какой-то hash, как сейчас модно

Тогда напишите в сигнатуре
function addUser(userHash){}

так же как в java
void addUser(Hash userHash){}


Проблема вашего примера в том, что он абсолютно стерилен

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

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

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

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

Не, если вы в типах что-то написали, то то самое там и будет. В этом и есть смысл статической типизации.


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

В случае с типами я могу одной кнопкой переместиться к объявлению типа. В случае динамики — как это сделать, тип переменной ведь неизвестен? Что это за User? Где определен список его полей и вообще определен ли? Насколько документация соответствует коду? Точно никто в ней ничего не напутал или не забыл изменить?


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


Тогда напишите в сигнатуре… userHash

А зачем, если можно написать с типами "user: Hash", но при этом еще компилятор проверит, что там действительно хеш а не что-то другое, да еще и автокомплит будет нормальный для user._ внутри метода?

Если вы даете названия которые не отражают суть, то и типы вам не помогут, там тоже можно написать в названии одно, а по факту там будет другое и такое встречается, надо так: createCounterFactory

Э нет! Это нифига не фактори. Это у вас нейминг неправильный. Counter — этот тот, кто считает. Вот такая штука:

Не цифры на нём, а именно сам счетчик. Так что counterFactory — это что-то, что создает такие счетчики, которые возвращают цифры. Так что под вашим очень правильным неймингом я представляю что-то такое:

function createCounterFactory (startingValue) {
  return {
    createCounter: function () {
      let i = startingValue;
      return { next: () => ++i; }
    }
  };
}

const counterFactory1000 = createCounterFactory(1000);
const counterA = counterFactory1000.createCounter();
count value1 = counterA.next();
count value2 = counterA.next();
count value3 = counterA.next();


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

Ага. Документацию. Хорошо, если она есть и вообще прекрасно, если она актуальная. Вот только вы прочитали мое сообщение через строчку. Как я могу быть уверен, что во всех местах, которые вызывают эту функцию передаются все поля? Какие ещё поля могут передаваться? А если этот кусок приходит с API сервера, то в клиентском коде вообще не будет этих данных. И вот зачем трахать себе мозг такими сложностями, если можно просто иметь тип и посмотреть всё необходимое одним кликом мышки?

Тогда напишите в сигнатуре userHash

О! Класс! А давайте тогда во всех названиях переменной писать её тип! userHash, counterNumber, lastNameString! Я прям захотел сразу отказаться от мусора статической типизации и внять вашим гениальным советам! А какие там поля userHash должен принимать, кстати?

Код в продакшен такой же, я стараюсь делать его очевидным и простым

Предполагаю, что ничего сложнее CRUD вы не писали.

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

Абсолютно согласен. Человек, который не думает не сможет построить дом с самыми крутыми инструментами. Но зачем забивать гвозди камнями, если можно взять молоток?
НЛО прилетело и опубликовало эту надпись здесь
В таком чистом очевидном представлении выглядит глупо, но ведь такая лояльность к ошибкам типов позволяет багам «уплывать» в далекие дали от места возникновения, что никак не облегчает отладку.
Опыт подсказывает, что наличие или отсутствие типизации в языке программирования никак не отражается на качестве выходного продукта, а вот умение думать, что ты делаешь и к чему это может привести напротив.
Чудес не бывает, ваше противопоставление указывает на увеличение трудозатрат/порога вхождения. Что с учетом средней по больнице квалификации не может не отразиться на качестве ПО.
Приведу слайд с недавнего доклада Романа Елизарова на тему языков программирования, где проводился анализ 20 наиболее популярных и используемых языков. На слайде чертой отделены языки, вышедшие в 20-м и 21-м веках. Как можно увидеть, за последние 20 лет не вышло ни одного языка, который имел бы динамическую типизацию (кроме Groovy, там есть и то, и то) и пробился в топы. Учтем еще быстрый рост популярности TypeScript, а также тот факт, что в php пытаются натянуть типы и ООП, и в итоге получаем прекрасную иллюстрацию того, что строгая статическая типизация наиболее удобна для разработки. Иначе на практике мы бы видели иную ситуацию.
image
Интересно! А что является критерием нахождения языка в топе? Количество софта который на нем написан? Количество программистов пишущих на нем или же общее значение той или иной разработки (имею ввиду разницу между переключалкой раскладкой клавиатуры на WinAPI и каким нибудь банковским ПО на фортране))?
Для отбора языков использовались 3 критерия: TIOBE (насколько часто язык гуглят) + PYPL (рейтинг поисковых запросов типа %language% tutorial) + RedMonk (проекты на github + теги на stackoverflow).
Будущее за статическими языками?
Так получается я зря начал учить Python?
Вот блин :(
Так и думал, что надо Java брать.
Плюс там типизация изначально строгая, «1» +1 -1 не пройдет.
Тонкий троллинг.
Мне кажется Джава с таким напором Майкрософта и Гугла, тоже вскоре отдаст свои лавры в пользу какой нибудь из более перспективных разработок.
Пусть меня заклюют, но начинать обучаться с не строго типизированных языков — заведомо фэйловая ситуация, тем более выбирать для этого академический язык, который стал популярным лишь из-за низкого порога вхождения, как и множество других не строго типизированных.
Да какая разница с чего начинать, я вообще с Бэйсика на ZX — Спектруме начинал, так там вообще трэш был с типизацией.
Да как бы без понимания структур данных далеко не уехать…
Далеко не уехать без желания учиться и постигать что — то новое, а все остальное приложится.
И то верно :)
48 килобайт ОЗУ, и 16323 байт ПЗУ, с 16384 начиналась «экранная память». А трэш с типизацией как был, так и никуда не делся!
Воу воу палехче.
Я закончил ВУЗ. По специальности инженер-программист.
В процессе обучения было около 10 ЯП. Разных. C, C++, Java, JavaScript, PHP, Verilog, VHDL и т.д. Это из того, что сходу вспомнил.
На данный момент я пишу на PL/SQL. Он со статической типизацией.
Я решил выучить язык по-полуряней. Что-то из списка: C#, Java, Python.
Java как-то в университете не зашла. С# отпугнул своей заточкой под Windows. В итоге остался Python.
Походу придётся засунуть подальше свои «хотелки» и взять или C# или Java.
ИМХО, берите шарп, он в последние 3 года развивается просто стремительным домкратом.
С# отпугнул своей заточкой под Windows

Сейчас это уже не так, есть кроссплатформенный .NET Core. Если есть принципиальная нелюбовь к .NET, то можно взять Kotlin — это новейший язык под JVM, созданный для потенциальной замены Java.
Kotlin — это новейший язык под JVM, созданный для потенциальной замены Java.


Задумал муравей Фудзияму сдвинуть… Пока усердно создаваемый хайп вокруг этого языка говорит только об его сугубо маркетинговых целях.

Зачем заклёвывать? Я просто напомню, что курс SICP использует в качестве основного языка динамически типизированный Scheme.

Сейчас в IT практически по всем направлениям и по всем языкам достаточно вакансий. Поэтому в любом случае работу можно найти и лучше выбирать то, что нравится, а не пытаться угнаться за модой. Кроме того, почти все современные языки сейчас неплохо развиты, те же php и javascript вон как вылизывают. Так что не стоит бояться, что останешься где-то обочине.

Мне понравилось, как он про Хаскелл сказал, комментируя этот слайд, что если бы для него использовалась плоская шкала масштаба, то Хаскелл бы сюда не поместился, а уехал бы далеко вправо )
НЛО прилетело и опубликовало эту надпись здесь
Учился на Немецком факультете экономики и права в Грузии. увлекся Flash — дальше не читал
+1
Какие странные дороги у нас делают с канавами по бокам. Постоянно там в говно вляпываюсь
А где третий выпуск?
<сарказм>
Третий выпуск назывался «Думаю атомы могли бы быть и побольше, а то их сложно заметить в микроскопе, 10 вопросов физику Карлсбадского технологического университета», но рукопись потерялась.
</сарказм>
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Как и PHP, собственно.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

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

Нормальный проект*

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
запустил бизнес и особо не лез в него — молодые лучше знают свое дело. А я бы занимался цветочками.

Но это же так не работает) Ничего плохого про героя интервью не считаю, но это звучит, как-будто человек вообще не имеет представления о предпринимательстве, однако делает на это ставку в будущем. В общем, как-то наивно звучит.
Я бы не стал связываться с Java, Spring Boot. Но Kotlin, да — это круто.

Пошло-поехало, "крутой" разраб.

Не просто крутой разраб, а крутой разраб из берлинской конторы (которая жмётся купить нормальные мониторы и ноутбук). Вангую стартап.
В свое время на Flash я успел наговнокодить. Так получилось, что игрок делал двойную ставку: он видел одну фишку, а по факту ставил две.

То есть был ActionScript со статическими типами и классами, но все равно там тоже были баги?


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

У нас коллеги-индусы (реально индусы), на C# умудрились написать в цикле не i=i+1, а i=i+i.
И ничего, месяц ошибку искали. Простая опечатка. Строго типизированный язык, или нет, руки не выпрямляет, немного отводит дуло от ноги когда целишься и не более того.

Вопросы, конечно, вы меня извините.
Ответы на четвертый и шестой могут быть полезны широкой аудитории. А остальные — зачем? Какая разница, какие мониторы, ЯПы и книги предпочитает отдельно взятый дядька, будь этим дядькой хоть Алан Тьюринг?

  • JavaScript, чтобы вы изменили или улучшили в индустрии?
  • Господи! Программиста! Убейте его! Он складывает строки с числами и ждет непойми чего! Он ведет себя непредсказуемо!
В принципе нормальная реакция на работу с JS :-)
Все правильно, только где вы там программиста увидели?
«JavaScript! Убейте его.… Там нет обычных классов. » — Всегда забавляют такие фразочки. Убейте это, потому что оно не похоже на то, к чему я привык… ну да
Вот блин и меня это зацепило, причем если бы человек я не знаю был светочем в программировании, еслиб он этот JS слева направо, сверху вниз, да его разбуди в 4 утра он тебе исходники V8 начнет по памяти читать. Ан нет, сначала Flash, потом Ангуляр!!! и Kotlin, и перед нами эксперт по JS.
Учился на Немецком факультете экономики и права в Грузии.

несколько раз перечитал
Знаменитый Грузинский Немецкий факультет.
Объясните мне, что у вас там у всех все безбожно устаревает что вы книжки читать отказываетесь?
Алгоритмы устарели? Паттерны у вас там все устарели? Что? Сахар какой-то новый завезли для вашего языка? Фреймворк ваш обновился? Евангелисты блин
А это называется поверхностное восприятие, нахватать инфы на стэковерфлоу и гитхабе (в репах где обязательно много звездочек), а книжки читать, это слишком напряжно. А потом когда начинает что — то не получаться, кто виноват? Язык программирования. Еще очень часто слышу такую позицию про проги на Java, якобы это не они сильно много памяти жрут, а это у меня памяти в компе просто мало установлено.
Хорошо вбросил по поводу JS :) Согласен с автором. Сам предпочитаю статическую сильную типизацию. Delphi. Незачем за компилятор делать его работу.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации