Pull to refresh

Comments 157

А чем Nullish Coalescing отличается от varName == null?
UFO just landed and posted this here

Тем, что сразу возвращает значение из правой части:


foo ?? bar
// Эквивалентно
foo == null ? bar : foo

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

кроме null ещё проверяется на undefined

Проверка == null как раз и проверяет на null или undefined.

Согласен ) Но нужно быть при этом внимательным с нестрогим сравнением. Т.к., если поставить на одно равно больше, то уже не будет работать ) Да и не все знают, что при нестрогом сравнении null и undefined равны друг другу и ничему больше.
function func(variable) {
  if (variable === null) {
    console.log(42);
  } else {
    console.log(13);
  }
}
func(undefined); // 13
func(null); // 42

function func2(variable) {
  console.log(variable ?? 42);
}
func2(undefined); // 42
func2(null); // 42

У вас один знак = в сравнении лишний.

Да, я уже понял и изменил коммент )

ой ну прям с C# и элвиса взяли и чек налреф :)

а мне python. Еще и импорты внутри процедур

За которые в питоне бьют по рукам обычно :)

Питоний код лежит рядом, его можно и сразу весь импортнуть. JS надо по сети тянуть. Если соберём все импорты в шапке — будем очень долго грузить страницу из-за кода, который может и не выполнится никогда.
Как вы решаете проблему циклического импорта?
После многолетней дискуссии пришли к выводу, что синтаксис как в C# является оптимальным. Поддерживаются не только объекты, но и массивы, а так же вызовы функций:
obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)

Можно я к вам в детский садик загляну с вселенским откровением?


C#, Kotlin, теперь вот, прости Дарвин, JavaScript, что там ещё. Вот этот вот elvis-operator — это вы (ну или вам, в этих ваших языках, доступных для масс) просто монады переизобрели. Только переизобрели из рук вон плохо, не композируемо, не полиморфно, однобоко, к вызову функций вон уже не применишь, и никаких вам аппликативных функторов, т.к. маленькие ещё в такое играть.


Лучше поинтересоваться откуда в C# это взяли.

к вызову функций вон уже не применишь

Вы про такой вызов?
a={b:null};
a.b?.();//undefined
----------
a={b:()=>2};
a.b?.(); //2
a.b?.()?.c; //undefined

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


В качестве примера кусочек кода на Haskell:


-- Описание типа (Maybe a) - это всё-равно что "nullable"
-- где (Just a) - это существующее значение любого типа "a",
-- а Nothing - можно воспринимать как null.
data Maybe a = Just a | Nothing

add :: Integer -> Integer -> Integer
add a b = a + b

x :: Maybe Integer
x = Just 10

y :: Maybe Integer
y = Just 20

sum = add <$> x <*> y -- Just 30
sum2 = add <$> Nothing <*> y -- Nothing
sum3 = add <$> x <*> Nothing -- Nothing
sum4 = add <$> Nothing <*> Nothing -- Nothing

-- Также сама функция может быть
-- (Maybe (Integer -> Integer -> Integer))
sum5 = Just add <*> x <*> y -- Just 30
sum6 = Nothing <*> x <*> y -- Nothing
Да, такая вещь тоже может пригодиться. А кто-то скажет, что ему нужны другие монады. Однако js не позиционируется как язык для написания в чисто функциональном стиле, и далеко не все подходы из того же хаскель нужны js разработчикам. А так, если очень хочется, все эти монады можно реализовать на js или взять уже готовые фреймворки, для написания на js в функциональном стиле.
Интересно, кто минусует оригинальный комментарий. Возможно люди, не знающие что на это ответить? Или просто не любящие слова про «детский садик»?

Напомню что этот детский садик умел делать вещи ещё в прошлом веке, которые в Haskell если и сделаешь, то с огромными ограничениями и костылями.

Что-нибудь типа такой add (раз уж мы над сложением упражняемся):
function add(x, y) {
  if (y === undefined) {
    y = 1;
  }
  return x + y;
}

add(2, 2); // 4
add(2); // 3


И да — я знаю почему это тяжело сделать в Haskell. И да — я понимаю через какие костыли, примерно, такое реализовать.

Но ситуация точь-в-точь как с элвис-оператором в C# и javaScript: разные костыли для разных целей в разных языках.

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

Такое лучше делать в TypeScript через overloads, а вот так вот, как в этом примере, обрабатывать аргументы — это что, не костыль по вашему? Особенно когда аргументы называются не x y, а там options и callback.


Но вообще я не сторонник таких подходов, т.к. они fragile в плане возможных опечаток, забытых аргументов и тому подобное. Целесообразнее на мой взгляд использовать отдельные функции, или явно передать null/Nothing/whatever.


Лично у меня в таком (в применении overloads) необходимость возникала только при эмуляции тех же аппликативных функторов и банальной point-free композиции функций на TypeScript. Т.е. чтобы реализовать подобие отсутствующих в языке конструкций.

Такое лучше делать в TypeScript через overloads, а вот так вот, как в этом примере, обрабатывать аргументы — это что, не костыль по вашему?
Костыль, конечно. Но разумный и удобный. Представьте себе что у вас какая-нибудь Web-страничка в духе godbolt. И вы её «запилили» так, что у вас там один компилятор. Соответственно все функции просто работают с глобалом (да-да, я знаю что «так не надо делать»… просто не видел ни одного человека, который бы все эти «так не надо делать» всегда и безусловно соблюлал бы).

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

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

Ну и какое решение проще «продать»?

Целесообразнее на мой взгляд использовать отдельные функции, или явно передать null/Nothing/whatever.
Это замечательно, но что вам делать, если вы уже получили такой вот код? И хотите постепенно добавлять вот этот вот параметр в ваш проект?

Да, я прекрасно знаю что вы сделаете: поставите всех раком. Пример. Вы — такой новичёк, решили изучить Хаскелль. Берёте вот этот вот пример:
import Data.Monoid

newtype Writer w a = Writer { runWriter :: (a, w) }

instance (Monoid w) => Monad (Writer w) where
    return x = Writer (x, mempty)
    (Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v')


И… оп-па:
test.hs:5:10: error:
    • Could not deduce (Applicative (Writer w))
        arising from the superclasses of an instance declaration
      from the context: Monoid w
        bound by the instance declaration at test.hs:5:10-39
    • In the instance declaration for ‘Monad (Writer w)’
  |
5 | instance (Monoid w) => Monad (Writer w) where  
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.


Прелестно? А я, между прочим, новичёк, я только начал книжку читать, ещё даже до Hello, World не добрался, возможно (взависимости от того, как книжка структурирована).

Лично у меня в таком (в применении overloads) необходимость возникала только при эмуляции тех же аппликативных функторов и банальной point-free композиции функций на TypeScript. Т.е. чтобы реализовать подобие отсутствующих в языке конструкций.
А необходимость переделывать что-то — возникала? Нет? Я раз за вас.

Вот у разработчиков GHCi она таки возникла и они с ней не справились. Может вы им поможите?
просто не видел ни одного человека, который бы все эти «так не надо делать» всегда и безусловно соблюлал бы.

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

А в Haskell это чем вызвано извините? Зачем код из тьюториала нужно было ломать?

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


В том же Monad не так давно были изменения. Из определения Monad вынесли определение fail (который математически не является частью Monad) в отдельный тайпкласс MonadFail. Точнее происходило это поэтапно, сначала сделали MonadFail, задепрекейтили Monad.fail предлагая использовать MonadFail, дав время начать его использовать. А потом удалили из определения Monad.


  1. было
  2. стало

И лично меня это изменение не может не радовать, язык стал более стройный, более правильный и безопасный (т.к. зависимость от Monad в полиморфной функции больше не предполагает имплицитно возможность падения с ошибкой), т.е. улучшился контроль эффектов. Если бы fail остался в Monad я бы меньше любил Haskell, мне всегда это не нравилось.


А если где-то что-то "сломалось", то комплиятор вам заботливо об этом сообщит, потому что сильная статическая типизация. И даже предложит просто заимпортировать Control.Monad.Fail в качестве решения. По-моему это то, как должен развиваться хороший язык.


А теперь давайте вернёмся к JavaScript (и UB), о котором речь шла изначально, а мы зачем-то перешли к обсуждению к Haskell. Помним правило ассоциативности же? Ну со школы же знаем что (a + b) + c всё-равно что a + (b + c), но не когда мы говорим о JavaScript.


{} + {} + {} // "NaN[object Object]"
{} + ({} + {}) // NaN
({} + {}) + {} // "[object Object][object Object][object Object]"

А главное, что JavaScript — платформонезависимый! Пример выше — Firefox. Ниже Chromium:


{} + {} + {} // "[object Object][object Object][object Object]"
{} + ({} + {}) // NaN
({} + {}) + {} // "[object Object][object Object][object Object]"

Вот это я понимаю дизайн и соответствие стандарту. Понятно, что данный пример в вакууме — это не реальный юзкейс. Но что из себя представляет стандарт JavaScript, вопрос о его "стройности" и стабильности, — вполне себе показывает. Я честно говоря и не в курсе, UB это, или кто-то из браузерных движков фундаментально не прав. Боюсь проверить данный пример в более старых реализациях. Можно посмотреть на числа:


(0.1 + 0.2) + 0.3 // 0.6000000000000001
0.1 + (0.2 + 0.3) // 0.6

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

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

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

А вот уже всё остальное — это потом.

В том же Monad не так давно были изменения. Из определения Monad вынесли определение fail (который математически не является частью Monad) в отдельный тайпкласс MonadFail. Точнее происходило это поэтапно, сначала сделали MonadFail, задепрекейтили Monad.fail предлагая использовать MonadFail, дав время начать его использовать. А потом удалили из определения Monad.
Отличный пример. А теперь, пожалуйста:
1. Ссылочки на стандарты «до» и «после».
2. Информанию о том как и где человек, не знающий о том, что происходит такое радикальное изменение и просто желающий освоить Haskell по книжке из магазина может об этом узнать.
3. Ну и, конечно, кто и как оценивал работу по переходу с Monad на MonadFail, как убедились что все проекты уже перешли и всё такое прочее.

И лично меня это изменение не может не радовать, язык стал более стройный, более правильный и безопасный (т.к. зависимость от Monad в полиморфной функции больше не предполагает имплицитно возможность падения с ошибкой), т.е. улучшился контроль эффектов. Если бы fail остался в Monad я бы меньше любил Haskell, мне всегда это не нравилось.
Это, конечно, прекрасно, но есть одна проблема: этим изменением вы порадовали людей, которые и так бы остались с вами… но убедили очередную порцию разработчиков, которых у вас не хватает и которые вам нужны как воздух, что «Haskell — это детксий сад» и сделали очередную итерацию по невыходу из своего загончика.

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

А теперь давайте вернёмся к JavaScript (и UB), о котором речь шла изначально, а мы зачем-то перешли к обсуждению к Haskell.
Мы не к обсуждению Haskell перешли, а к обсуждению «детского сада».

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

Так вот подход JavaScript — со всеми его UB у ужасами (странно, что вы вспомнили про мало кому нужную ассоциативность, но забыли про то, что у JavaScript сранения нетранзитивны — что, на практике, куда большая беда)… это язык взрослых, а Haskell… увы, нет.

Потому что используют его только люди, которые могут себе позволить писать всё с нуля. Потому что там нет базы. Вместо тех самых батареек — бесконечное перестраивание фундамента…
Ну и, конечно, кто и как оценивал работу по переходу с Monad на MonadFail, как убедились что все проекты уже перешли и всё такое прочее.

Пакеты, которые попали в Stackage снапшот гарантированно совместимы с новой стандартной библиотекой (пакет base). Ну и совместимы с другими зависимыми библиотеками из снапшота. При переезде на новый base в снапшоте все старые пакеты пробуются автоматически на предмет успешного переезда, если они ранее были добавлены в Stackage (что является таким условно одним из знаков качества и production-readyness для библиотеки). Если пакет отказывается собираться в рамках нового снапшота (который изначально выпускается как nightly), то на github-е в соответствующем треде тебе, как мейнтейнеру, отправляют меншн (там вроде и другие каналы коммуникации есть, но я точно не помню), этакий "пинок": "пожалуйста исправь, твоей пакет не собирается".

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

И эти люди что-то говорят про «детский сад»?

Так, а объясните мне как вы делаете реальную оценку в проприетарном коде, когда его никому не показывают? Гадаете на картах?

Ну вот посмотрите как это делается в случае с C++: We implemented our proposed change in Clang and ran it on the Google codebase. We observed code breakage whenever a type was aggregate-initialized that ceases to be an aggregate with the change proposed here. We found that there is about one such type per 3 MLoC. We believe that this amount of breakage is well justified by the achieved simplification and improvement over theexisting language rules.

Да, понятно, что для того, чтобы обнаружить «одну ошибку примерно на каждые 3 миллиона сток» вам нужно много кода. То есть нужны люди в компаниях, которые это вот всё реально используют. И auto_prt убрали из стандарта без такого исследования… но компиляторы пока его поддерживают — даже в C++20, так то до окончательного, реально несовместимого изменения ещё далеко…
We implemented our proposed change in Clang and ran it on the Google codebase.

Простите, целиком paper не читал. Но как они запустили это на Google codebase? Это сам гугл запустил? Или таки на каких-то открытых проектах гугла (стало быть не проприетарных)? В обоих случаях получается несостыковка. В случае крупных открытых проектов тут о проприетарном речи и не идёт. А в случае запуском самим гуглом мы говорим об репорте от самого пользователя гугла. Что мешает компании, использующей Haskell сделать совершенно аналогичный репорт для мейнтейнеров, если они в этом заинтересованы?

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

А это важно по понятной причине: проприетарный код не будет собираться на nightly и никто не будет тебе, как мейнтейнеру, отправлять меншн. Да, в идеале нужно было бы собрать информацию со многих компаний (и для более инвазивных изменений так и делают), но уж точно не «если наши „золотые“ пакеты собрались — то и ладно, можно в релиз».

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

А что — все новые библиотеки проверяются и на всех старых компиляторах тоже? Если нет (а я сильно подорзреваю, что таки нет) — то тот факт, что компилятор у вас не находится в браузере не сильно спасает.

Если компания принимает решение что она всё, вот вообще всё, будет делать сама — то ей и Haskell ни в каком виде не нужен, она может себе свой язык сделать. С блекджеком и шлюхами.
А что — все новые библиотеки проверяются и на всех старых компиляторах тоже? Если нет (а я сильно подорзреваю, что таки нет) — то тот факт, что компилятор у вас не находится в браузере не сильно спасает.

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


Если компания принимает решение что она всё, вот вообще всё, будет делать сама — то ей и Haskell ни в каком виде не нужен, она может себе свой язык сделать. С блекджеком и шлюхами.

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

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

Можно конкретизировать проблему? Может о каком-то конкретном софте речь, но вы говорите именно об Linux, и я полагаю о ядре, где Линус Торвальдс очень трепетно относится за целостность userland api, и не даёт его ломать, даже если он был неправильный.

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

но вы говорите именно об Linux, и я полагаю о ядре, где Линус Торвальдс очень трепетно относится за целостность userland api, и не даёт его ломать, даже если он был неправильный.
Нет-нет-нет. К Торвальдсу — никаких претензий. Он как раз большой молодец и ядро Linux используется, буквально, на миллиардах устройств.

Речь шла о дистибутивах Linux, которые регулярно ломают всё, что можно и чего нельзя и у которых нет даже банального SDK, позволяющего собрать программу новым компилятором под старую платформу (ну… банального такого: you can use the Visual Studio 2017 C++ compiler to create apps that target Windows XP and Windows Server 2003). Да, конечно, вы правы, совместимость нельзя тянуть вечно. И даже Microsoft отказался от поддержки Windows XP в Visual Studio 2019… ну так это сколько лет прошло!

Единственное исключение — это RHEL. Или вы думаете зря разный «серьёзный» софт под Linux только под RHEL (и, иногда, CentOS) работает?
у которых нет даже банального SDK, позволяющего собрать программу новым компилятором под старую платформу

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

Ну т.е. не факт что там есть в базе пакетов совсем старые версии, но сам подход к проблеме иной.
Это не «подход к проблеме иной». Это вообще не решение. Могу я на C++17 писать программу для Windows Vista из 2007го? Да, могу. Легко. Visual Studio это поддерживает. Могу я на C++17 писать программу для RHEL6 из 2010го? Да, могу. Для RHEL5 из 2007го не могу, но там уж ничего не попишешь — поддержка RHEL кончается быстрее, чем у Windows.

А у NixOS? Фигушки. Никак. Да даже под версию вышедшую год назад нет обновления компилятора.

Да, этот подход не так плох на серверах, где админ может новый райнтайм для новой версии GCC поставить — но для десктопа он явно не годится…
А у NixOS? Фигушки. Никак. Да даже под версию вышедшую год назад нет обновления компилятора.

Я так и не понял, почему же не могу?


Вот к примеру в базе пакетов представлены сразу несколько мажорных поколений gcc:


λ nix search 'gcc[0-9]' | grep nixpkgs | grep -v Stdenv
warning: using cached results; pass '-u' to update the cache
* nixpkgs.gcc48 (gcc-wrapper-4.8.5)
* nixpkgs.gcc49 (gcc-wrapper-4.9.4)
* nixpkgs.gcc6 (gcc-wrapper-6.5.0)
* nixpkgs.gcc7 (gcc-wrapper-7.5.0)
* nixpkgs.gcc8 (gcc-wrapper-8.3.0)
* nixpkgs.gcc9 (gcc-wrapper-9.2.0)

В unstable-ветке есть более новые версии.

Я так и не понял, почему же не могу?
Дык не запустится ж оно! В C++17 новые функции в стандартной библиотеке появились, в libstdc++.so версии 4.4, поставляемой с RHEL6 — их нету. RedHat довольно-таки много приседаний над GCC исполняет, чтобы бинарник с фичами C++17 в такой ситуации всё-таки запустился.

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

А хочу я, в сущности, простой вещи: сегодня, сейчас, разрабывать программу с использованием сегодняшних инструментов (что довольно логично — для чего ж их делают?), а потом поставить их заказчику, который использует, разумеется, операционку развёрнутую 3-5-10 лет назад (никто ж не будет обновлять всю систему только ради того, чтобы мою приблуду запустить).

Так умеют делать: iOS/MacOS, Windows, Android… RHEL. Так не умеют — все другие дистрибутивы.

На сервере, где, зачастую, мне могут позволить и самому задеплоить то, что я наработал — это ещё не критично. На десктопе или там смартфоне… без этого, извините, никуда…

Так запустится ведь! Ведь derivation наследует всё дерево зависимостей, до корня. Если ядро совместимо (а это вероятно так и есть), то запустится. Может вы не совсем понимаете принцип работы Nix? Т.е. вам не обязательно ссылаться даже для отдельной программы на общую базу пакетов, текущей такой-то версии, вы можете на конкретный коммит этой базы сослаться для отдельной программы.


Вот я например так и делаю, только не для программы, а вообще для системы. Лично я просто предпочитаю software-defined снапшот, чем channels, чтобы иметь абсолютную гарантию reproducibility.

Может вы не совсем понимаете принцип работы Nix?
Я прекрасно понимаю принцип работы Nix. Но я боюсь вы не понимаете принципы работы пользователей.

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

Да, Nix вытащит мне все зависимости собранными под мой бинарник. Но вот я сейчас глянул на ldd /opt/google/chrome/chrome — там 98 библиотек зависимостей. Часть из них общается через dbus с разными другими частями системы (какой-нибудь /lib/x86_64-linux-gnu/libsystemd.so.0, ага) и про этом слинкован со всякими интересными штуками типа /lib/x86_64-linux-gnu/libgcrypt.so.20 (обратите внимание на номер версии)… вы уверены, что вот это вот всё взлетит, когда я захочу все зависимости обновить?

Я вот — ни разу не уверен. И чем дальше в прошлое «базовая» версия системы — тем менее уверен.

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

Так что Nix тут, увы, не поможет…
Так вот: детский сад — это такое место, где люди могут заниматься чем угодно (пока воспитательница не видит), а главное — им не нужно зарабатывать на жизнь.

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

Ну что могу сказать… Рад за то, что вам удалось достаточно безбашенного работодателя, готового вот в это вот всё ввязаться.

Остаётся только надеяться, что когда он «кончится» вам удастся найти другого (или это крупная компания, где умным людям платят зарплату только для того, чтобы они не ушли к конкуретнам и не сделали для них чего-то полезного? этим Microsoft Research одно время занимался).

Спасибо за заботу. Если волею судьбы вдруг выбросит за борт — могу пойти обратно писать "взрослый" код на JavaScript, я с ним провёл много лет, чтобы владеть им на достаточном уровне и чтобы меня от него крепко подташнивало. А статьи подобные этой читаю на всякий случай, чтобы чекнуть, что skill is still in tune.


Так или иначе мне падают периодически регулярно вакансии с Haskell/PureScript из разных стран.

Так вот подход JavaScript — со всеми его UB у ужасами (странно, что вы вспомнили про мало кому нужную ассоциативность, но забыли про то, что у JavaScript сранения нетранзитивны — что, на практике, куда большая беда)… это язык взрослых, а Haskell… увы, нет.

Мда, мы явно "взрослым" называем разные вещи, если не диаметрально-противоположные. Называть уродство, примитивность и доступность массам "взрослостью" у меня язык не повернётся. "Адаптированностью к реальности" — возможно, но эта адаптированность вовсе не говорит что это что-то хорошее.


А вообще это вы хорошо назвали — "сранения", так надеюсь в стандарте и записано, чтобы лучше отражать суть.

«Адаптированностью к реальности» — возможно, но эта адаптированность вовсе не говорит что это что-то хорошее.
Это критерий взрослости, как бы.

А вообще это вы хорошо назвали — «сранения», так надеюсь в стандарте и записано, чтобы лучше отражать суть.
О! Тоже хороший показатель: подобное ребячество — тоже ни разу не признак взрослости.

Я не знаю, почему вы, вдруг, решили что «взрослость» — это о мудрости или, там, о математической строгости.

Называть уродство, примитивность и доступность массам «взрослостью» у меня язык не повернётся.
Взросление — это обучение к тому, чтобы жить в обществе. Брать на себя отвественность, отвечать за свои поступки и так далее.

А вовсе не о красоте и элитарности.
Это критерий взрослости, как бы.

Взрослость — это осознание и ответственность, а не обязательное подстраивание под формат, диктуемый средой. Взрослость — это сформированность и самостоятельность собственного мнения/мирровозрения.

Взрослость — это осознание и ответственность, а не обязательное подстраивание под формат, диктуемый средой.
Подстраиваться — необязательно, как-то взаимодействовать — необходимо. Подход «я не хочу даже видеть идиотов неспособных проникнуться великими идеями типизации» — это ну никак не взрослость…

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


Это ведь получается всё-равно что TypeScript, который может (хоть и далеко не всё, что мне нужно), но на котором не хотят. В итоге ну какой с этого прок, если при симпатии к самому инструменту я получаю антипатию к проектам, на нём написанном? И вообще не вижу зачем эти люди себя насилуют и рожают обыкновенный JavaScript shitcode тратя свои программисто-часы на бесполезную расстановку as any? Ничего хорошего из этого не вышло, мне такой инструмент не нужен, я могу лишь, как вы ранее сказали, "свои наколенные эксперименты палочкой тыкать, пока никто не видит", а в проекты контрибьютить желания никакого нет. Получилась "мёртвая нагрузка", которую используют потому что модно и так принято в этот год.

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

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

Совершенно верно. Мир — он ни разу не чёрно-белый. И между «пишу говнокод с as any» и «пишу строго верифицируемый код с завтипами и доказательствами» — масса «оттенков серого».

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

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

А вот когда unclechu на них стал «наезжать» и требовать, чтобы они вам предоставили гарантии, которые, пока что, они предоставлять не готовы… послали уже его.

Потому что всему своё время. Будут у вас библиотеки на все распространённые случаи, будет поддерживаться нормально девелопмент на Android и GUI под Windows — можно будет «перебирать» и «закручивать гайки».

А пока, извините, у вас, у всего мирового Haskell-сообщества, нет ресурсов даже для того, чтобы банально задокументировать состояние вашего языка и приличный тьюториал к нему написать… жаловаться на то, что кто-то злоупотребляет каким-нибудь Debug.Trace, извините, рано.
Потому что используют его только люди, которые могут себе позволить писать всё с нуля. Потому что там нет базы.

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


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


В том же последнем стабильном снапшоте https://www.stackage.org/lts-15.15 2342 пакета. А на Hackage под 15 тысяч, это по-моему совсем не мало. Только не надо в пример приводить базу npm где всё заполонено "очень взрослым" совершенно лютейшим мусором.

Только не надо в пример приводить базу npm где всё заполонено «очень взрослым» совершенно лютейшим мусором.
А Hackage — это не мусор? Дизассемблер с припиской «I have tried to disassemble them properly but have been limited to the information in the docs, because I have no 64-bit machine to test on.» в 2020м году — это нормально? Отсутствие поддержки DWARFv4 (этому стандарту 10 лет скоро стукнет) — это куда?

Да, в NPM полно кривых и косых пакетов. Но там достаточно и работающих, готовых к использованию, пакетов тоже. А вот в Haskell — сплошной Жванецкий: Подшей, подгони там, воротник переставь, рукава подправь, хлястик передвинь, подкладку укрепи и носи сто лет. Ботинки — подклей, растяни, подбей и носи! Швейная машинка — подольская, новая совсем, ее только подремонтировать — и строчи!

Вечный рефрен просто не нашлось того, кто написал… так и не найдётся никогда, если вы людей, на это способных будете «в пешее эротическое» посылать.

Ну не знаю, сколько писал сам и по работе, 50 используемых библиотек — это по-моему уже показатель.
Ну да, показатель. Непонятно только чего. Сейчас глянул у нас в папку third_party… 2853 подпапки. И это, в общем, притом что каждую библиотеку нужно отделный approve получать. И да, конечно, не все они в один бинарник линкуются… но вот так. Разница даже не на один порядок, а почти на два.

И да, это C++ и Java, не JS. Там библиотеки могут и в 100 строк быть, это, конечно, немного другая ситуация…
А Hackage — это не мусор?

Далеко не в тех масштабах. Даже если пакет заброшен мейнтейнером, он таки может быть полезен и интересен, и как правило, даже если отсутствует в Stackage — вполне себе может быть использован, и при breaking changes даже такие пакеты ломаются не так уж и часто.


А Stackage — это уже фильтр чего-то реально работающего и собирающегося, совместимого с остальными зависимыми пакетами.

Даже если пакет заброшен мейнтейнером, он таки может быть полезен и интересен, и как правило, даже если отсутствует в Stackage — вполне себе может быть использован, и при breaking changes даже такие пакеты ломаются не так уж и часто.
Это, конечно, прекрасно, но что мне делать, если я смотрю на список тегов и вижу, что в Go есть AttrLoclistsBase из DWARF5, а в Haskell, увы, на DW_AT_recursive из DWARF3 — всё кончается? Дотачивать? Так на это больше времени уйдёт, чем на написание всего тула, который мне нужен, на Go!

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

А сигнатуры… это хорошо. Только сами собой они спецификации не распарсят и нужные мне структуры данных не образуют…
А вот в Haskell — сплошной Жванецкий: Подшей, подгони там, воротник переставь, рукава подправь, хлястик передвинь, подкладку укрепи и носи сто лет. Ботинки — подклей, растяни, подбей и носи! Швейная машинка — подольская, новая совсем, ее только подремонтировать — и строчи!

Такого на себе не испытывал. Напротив, впечатление от работы с базой библиотек в целом приятные. А навигация по сигнатуре типа — я даже не знаю как я без этого раньше жил. Воображаю что мне нужна такая-то функция, что у неё был бы такой-то тип, ищу hoogle-ом, и в 90% случаев такая функция уже есть в базе библиотек. Это сильно упрощает жизнь, когда тебе не нужно выдумывать поисковый запрос, описание, рыться по статьям. Просто описываешь сигнатуру типа, как если бы ты писал функцию сам — и вот, нашлось.

Вечный рефрен просто не нашлось того, кто написал… так и не найдётся никогда, если вы людей, на это способных будете «в пешее эротическое» посылать.

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

Ну да, показатель. Непонятно только чего. Сейчас глянул у нас в папку third_party… 2853 подпапки. И это, в общем, притом что каждую библиотеку нужно отделный approve получать. И да, конечно, не все они в один бинарник линкуются… но вот так. Разница даже не на один порядок, а почти на два.

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


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

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

Но да, он непрост: некоторые библиотеки ещё и внутри себя содержат дополнительние «дочерние» библиотеки, но некоторые — да, испортированы, чтобы какие-то другие библиотеки импортировать…

Мы не одни такие, кстати. Вот история про Google, вот про Microsoft.
Это замечательно, но что вам делать, если вы уже получили такой вот код? И хотите постепенно добавлять вот этот вот параметр в ваш проект?

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


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

Прелестно? А я, между прочим, новичёк, я только начал книжку читать, ещё даже до Hello, World не добрался, возможно (взависимости от того, как книжка структурирована).

Причём тут вообще сложность изучения Haskell, когда мы говорим о дет-садовском JavaScript? Я пример на Haskell привёл по двум причинам, чтобы прежде всего показать что я имею в виду, если из описания не очевидно или сложно понять (у человека не посвящённого в аппликативные функторы сама задача может плохо укладываться в голове из-за отсутствующей модели осмысления проблемы, т.к. undefined is not a function считается повседневной нормой, а не фундаментальным дефектом инструмента). А на Haskell потому, что на нём такое возможно реализовать стандартными средствами, ради наглядности. Я вам Haskell тут не пытаюсь предложить, это вы сами для себя решите, когда перерастёте JavaScript. Нечто похожее можно было бы реализовать на TypeScript, через overloads с дженериками, но путём введения кастомной функции, релизация которой была громоздкой, это было бы не интуитивно и не наглядно, понятно только опытным.


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

Причём тут вообще сложность изучения Haskell, когда мы говорим о дет-садовском JavaScript?
Притом, что я могу дет-садовских языков у нас тут в обсуждении ровно один — и это не JavaScript.

Я могу взять любую книжку про C++, вышедшую после 98го года (то есть после принятия стандарта C++98) — и спокойно использовать её для работы с Visual Studio 2019. Да, я пропущу некоторые моменты, возможно напишу код чуть сложнее, чем он мог бы быть — но всё будет более-менее работать.

Я могу тоже самое проделать с JavaScript. И, вроде бы, с TypeScript (тут правда, не проверял). Это — промышленные, «взрослые» языки.

Я не могу сделать тоже самое с Haskell. У него вообще нет ни одного компилятора совместимого со стандартом.

Что это, как не детский сад, извините?

Я вам Haskell тут не пытаюсь предложить, это вы сами для себя решите, когда перерастёте JavaScript.
Почему вы решили, что я перерасту JavaScript и с чего вы, собственно, решили, что я на нём вообще пишу?

P.S. Вам компилятор подсказал что добавить в констрейнты.
Проблема не в том, что он чего-то кому-то там подсказал. Проблема в том, что он это подсказал на код из книжки! Из тьюториала на haskell.org. Причём там ни один из тьюториалов не работает!

Причём это всё — как раз из-за невозможности разрулить эти проблемы в языке обратно-совместимым способом.

Вот это — настоящий детский сад…
Проблема не в том, что он чего-то кому-то там подсказал. Проблема в том, что он это подсказал на код из книжки! Из тьюториала на haskell.org. Причём там ни один из тьюториалов не работает!

Я не знаю как давно этот код работал, возможно когда-то у Monad из стандартной библиотеки в зависимостях не было Applicative.


Лично я не считаю что обратной совместимости нужно поклоняться и расписываться кровью в её сохранении. Тем более не с языком-однодневкой, а языком, который пережил многих (Haskell не сильно младше Си) и до сих пор считается крутым, аналогов которому почти нет. Тем не менее, я согласен что нарушать обратную совместимость слишком часто не стоит, или существенно её ломать. Но иногда без таких изменений кина не будет. Можно посмотреть на Си++, изучив все (ну или большинство) подводные грабли и прочие UB-кейсы которого можно лет спустя 10 каждодневной практики (тяжёлая ноша "обратной совместимости"). Тем не менее в Haskell прямо таких фундаментальных "поломок" было за историю на моей памяти очень мало. И это были не сколько "поломки", сколько тюнинг зависимостей тайпклассов и тому подобное.


Это раз. А два — реализация тайпкласса Monad — это не непосредственная неотъемлемая часть реализации языка в GHC, это часть стандартной библиотеки base, которая по большей части живёт на правах любой другой библиотеки. Есть даже альтернативные реализации "стандартной библиотеки" также улучшающие ситуацию с многолетним наследием той же "обратной совместимости" вроде кучки нетотальных или необоснованно мономорфных функций.


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


Я не могу сделать тоже самое с Haskell. У него вообще нет ни одного компилятора совместимого со стандартом.

Прошу пример конкретного несоответствия со стандартом, которое вам досаждает? И с каким Haskell2010? Haskell98?

Я не знаю как давно этот код работал, возможно когда-то у Monad из стандартной библиотеки в зависимостях не было Applicative.
Во всех стандартах Haskell (как в Haskell 98, так и в Haskell 2010) это так.

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

Можно посмотреть на Си++, изучив все (ну или большинство) подводные грабли и прочие UB-кейсы которого можно лет спустя 10 каждодневной практики (тяжёлая ноша «обратной совместимости»).
Вам достаточно одного «гуру C++» на команду из 10-20 человек. Он вполне сможет белго просмотреть код и в сложных случаях дать совет.

Сравните «с детским садом». Вот что написал ваш коллега когда его попросили решить простенькую задачку. Не подскажите когда в стандарт завезли вот эту вот конструкцию: [i|Хотите пригласить человека #{name}?|]? Заметьте: это специально без выпендрёжа код!

Тем более не с языком-однодневкой, а языком, который пережил многих (Haskell не сильно младше Си) и до сих пор считается крутым, аналогов которому почти нет.
Lisp вообще больше чем полвека существует… и там та же самая беда, кстати: платформы-то нету. Есть вот именно «детский сад» без нянек…

И это были не сколько «поломки», сколько тюнинг зависимостей тайпклассов и тому подобное.
Ага — именно этим оправдывается тот факт, что в языке кучи полезных вещей нету и где-то минимум ⅔ всего имеющегося Haskell-кода стандартным Haskell-кодом не является, а если учесть зависимости — то хорошо если не 99%. В любом мало-мальски осмысленном модуле — используются кучи расширений GHC — но при этом в стандерте их нет и, соотвественно, что у вас UB, а что не UB вы даже прочитав стандарт понять не можете.

Есть даже альтернативные реализации «стандартной библиотеки» также улучшающие ситуацию с многолетним наследием той же «обратной совместимости» вроде кучки нетотальных или необоснованно мономорфных функций.
О да. Это — вообще чудесная вещь. Я когда писал про «вы всё время перестраиваете фундамент у вашего дома и всё ломаете?» — имел в виду именно это. Вам примера Pascal, со своими многочисленными диалектами, ушедшего из лидеров (в 1980е) куда-то в область анекдотов мало? Или D, который, во многом, из-за подобного маразма, так и остаётся «подающим надежды»… уже скоро как 20й год.

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

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

Но когда пробовал что-то такое изобразить я как раз туда посмотрел и понял: «да, таки детский сад».

И с каким Haskell2010? Haskell98?
С любым. Хоть с Haskell 98, хоть с Haskell 2010, хоть Haskell 2020… кстати где он, этот мифический Haskell 2010-то? Обещали вроде в этом году…
А вот Perl из-за подобной попытки просто… кончился. Ну это, просто, чтобы вы понимали — как часто можно ломать совместимость и в камих масштабах.

Он не кончился. Perl 6 просто решили переименовать в Raku, чтобы исключить конфуз, т.к. там не поломка обратной совместимости, а просто новый язык, на который оказал сильное влияние Perl 5 (и Haskell, как ни странно, на котором была написана первая прототипная версия интерпретатора Perl 6).


Зависимости там ломали, если конечно чего-то не знаю, отнюдь не часто, а напротив, Perl 6 — это исключительное событие за всю историю.


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


Лично мне Raku, как язык, симпатичен, но его жирнющая VM (эталонная реализация), которая есть раму как не в себя, меня отторгает от написания чего-то, кроме небольших скриптов под задачи "быстро отработал и завершился".

Зависимости там ломали, если конечно чего-то не знаю, отнюдь не часто, а напротив, Perl 6 — это исключительное событие за всю историю.
Зависимости там ломали нечасто, так как у них огромная система тестов, которая за этим следит. Но в результате, когда всё-таки решили совместимость сломать — то «пустились во все тяжкие»… и народ новую версию языка — просто не принял.

Лично мне Raku, как язык, симпатичен, но его жирнющая VM (эталонная реализация), которая есть раму как не в себя, меня отторгает от написания чего-то, кроме небольших скриптов под задачи «быстро отработал и завершился».
Меня, в общем, результат вполне устраивает: Raku достаточно мало кем используется, чтобы его существование просто игнорировать, а то, что Perl5 не умер, а просто стал менее популярен… ну что ж, это всё-таки лучше, чем ничего…
Не подскажите когда в стандарт завезли вот эту вот конструкцию: [i|Хотите пригласить человека #{name}?|]? Заметьте: это специально без выпендрёжа код!

О, ну если вы исключительно о стандарте, то я не сторонник того, чтобы ограничиваться исключительно стандартом. Я регулярно использую обилие расширений GHC, без них жизнь была бы гораздо менее приятной. Я всегда ассоциирую Haskell со всем этим богатством расширений GHC. Конечно, это не часть стандарта (последний из которых датирован 2010 годом).

ОФигительно, да. А кто может вам гарантировать, что вот все эти бесчисленные расширения будут поддерживаться через 5, 10, 20 лет? Ну вот напишите вы для кого-то программку на Haskell — где гарантия, что она, когда нужно будет в неё внести изменения, вообще соберётся?

Гарантии вам вообще вряд ли какие-то о поддержке столь долгосрочные даст. Одни языки внезапно и скоротечно умирают, другие, вроде COBOL, могут легко, на удивление, пережить создателей, сильно не изменяя облика. Это сильно эфемернее, чем вам, вероятно, кажется. Перед вами кто-то расписался кровью, что C++ или Java скоротечно не умрут? У каких-то компаний перед вами обязательства?


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


А соберётся она точно, т.к. я использую параллельно как Stackage-снапшот, который привязан как к версии пакета, так и к GHC, в качестве эталона для сборки. А также Nix, который с ещё большей вероятностью даст собрать и запустить мою программу, как если бы она была собрана в последний раз. Гарантия reproducibility.

Перед вами кто-то расписался кровью, что C++ или Java скоротечно не умрут?
Кровью-то зачем?

У каких-то компаний перед вами обязательства?
Да, представьте себе. Как вы думаете — почему IBM поддерживала OS/2 столько, сколько она поддерживала? И в 2006м году не прекратила поддежку, как многие считают, а стала просто просить за неё денег?

А соберётся она точно, т.к. я использую параллельно как Stackage-снапшот, который привязан как к версии пакета, так и к GHC, в качестве эталона для сборки. А также Nix, который с ещё большей вероятностью даст собрать и запустить мою программу, как если бы она была собрана в последний раз. Гарантия reproducibility.
Это всё работает только в том случае, если вы эту программу регулярно собираете. А если вы её собрали сегодня, отдали какому-то магазинчику, а повторно её будет собирать кто-то другой и вообще неизвестно когда?

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

То есть Haskell, фактически, выпадает как из самых больших компаний, так и из самых маленьких… а средних компаний (да ещё и не мечтающих стать большими, ага) — в природе не так, чтобы смертельно много…
О да. Это — вообще чудесная вещь. Я когда писал про «вы всё время перестраиваете фундамент у вашего дома и всё ломаете?» — имел в виду именно это.

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

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

Мимо.
Мимо чего? Мимо взрослого мира? Да, мимо. Сплошной детский сад, куличики и смешные детские обиды.

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

Мимо чего? Мимо взрослого мира? Да, мимо. Сплошной детский сад, куличики и смешные детские обиды.

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

Я могу взять любую книжку про C++, вышедшую после 98го года (то есть после принятия стандарта C++98) — и спокойно использовать её для работы с Visual Studio 2019. Да, я пропущу некоторые моменты, возможно напишу код чуть сложнее, чем он мог бы быть — но всё будет более-менее работать.

На самом деле — нет, не можете. Там в книжке наверняка новооткрытые UB не разобраны.


Вообще, о том что в C++ есть UB, я вот к примеру узнал только на Хабре, в книжках этого не писали.

Там в книжке наверняка новооткрытые UB не разобраны.
Дык фишка в том, что никаких «новооткрытых UB» не бывает. Бывают «новооткрытые ошибки» в старых программах — это да.

Ну так это в любом языке бывает. Некоторые тоже считали, что вот это вот:

primes = sieve [2..]
sieve (p : xs) = p : sieve [x | x <− xs, x ‘mod‘ p > 0]
Является некоей аппрксимацией «Решета Эратосфена». Ан нет, нифига.

Но да, C++ — «опасный» язык, никто не спорит. Потому и вопрос о замене обсуждается…

P.S. Меня больше бесит, когда кто-то рекламирует новые фичи. У тебя текут слюни, ты уже ручки потираешь… а потом смотришь в код а там засада — нормально работает только clang. Ну и нафига мне такое счастье? Если мне на качество генерируемого кода наплевать, то у меня есть масса выбора, не только C++…

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


Повторюсь, про UB в C++ я впервые узнал на Хабре в 2014м году, хотя до того момента я успел прочитать КУЧУ книжек по программированию, получить высшее образование и даже продуть финал ACM ICPC.


Возвращаясь к вашему примеру, сейчас можно взять пример кода из старой книги, скомпилировать его и получить UB.


Как по мне — так это куда хуже чем получить ошибку компиляции.

Формально — их не бывает, но для того, чтобы писать на C++ безопасно — нужен другой уровень знания языка, отличный от даваемого в книгах 98го года.
Ну вы хоть как-то, хоть что-то писать сможете. Всё лучше, чем не смочь даже запустить примеры из учебника…

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

Гениально! Только учтите, что «подобные книжки» — это все тьюториалы на оффициальной страничке, это всё, что выдаёт Google… это вот вообще всё, на что вы имеете реальный шанс наткнутся если у вас возникнет желание изучить Haskell.

Вы всерьёз предлагаете изучать язык по обрывками документации на разных сайтах? Или по статьями на Хабре?

Ну если это «оффициальная позиция community» то неудивительно, что оно столь мало…

Да. Качество этих "обрывков" намного превосходит те книги, по которым я пытался учить программирование в 98м.

И? О чём это говорит? О том, что 90% (а может и 99%) современных программистов не смогли бы, в принципе, стать программистами, если бы пытались изучать программирование в прошлом веке?

Да, наверное — но это не повод сегодня такое устраивать.

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

У Rust, в отличие от Haskell, вообще всего один официальный учебник — но зато он всегда в актуальном состоянии и легко находится… и мне кажется — это одно из важнейших реальных отличий для разницы в популярности…

Не само наличие учебника, а вот эта вот «если „немытые массы“ не могут проникнуться нашими глубокими идеями — то они нам и не нужны»…
А необходимость переделывать что-то — возникала? Нет? Я раз за вас.

От чего же нет? Возникала, и не раз. Что это меняет?

Вот у разработчиков GHCi она таки возникла и они с ней не справились. Может вы им поможите?

Можно конкретнее, о чём идёт речь?

У них возникла проблема. Чисто теоретическая, но неприятная. С тем, что Монада — это не Аппликатив, а моноид — это не полугруппа.

И они обе проблемы исправили поломав существующий код. Что многое говорит как о языке, так и об экосистеме в целом. Сравните с подходом Rust (если вам, вдруг, ES2020 не нравится).

Вот потому Rust добрался до 20ки, а ребята из детского сада уже четверть века маются вопросом: да что ж нас не любит-то никто?

Дык за что ж вас любить, если вместо решения практических задач (решаемых тем же элвис-оператором в C# и JavaScript) вы всё время перестраиваете фундамент у вашего дома и всё ломаете?

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


Предлагаю почитать мой тред по поводу засилья fragile .unwrap()-ов:
https://mastodon.social/@unclechu/103998022358094226
Вот я рядом радовался, что из Monad в Haskell выпилили fail (теоретически где-то сломав обратную совместимость), а в Rust его применение впилили в один из самых широкоиспользуемых методов. Новый язык не должен таким образом подходить к проблемам. Это принципиально ничем не лучше, чем NullPointerException.


А вопрос участника треда:


unclechu But how do you express in the type system that Regex::new("[a-z]") can't fail?

Меня просто убил (я как его прочитал сразу прикинул реализацию на Haskell в голове на темплейтах и парсерах), и окончательно убедил, что сообщество Rust, которые повсюду пишут .unwrap() действительно технически не очень подтянуто. И сам язык, экосистема, как следствие, это отражает.


Так что нет, отсылка к Rust для меня не пример чего-то well-done.

Предлагаю почитать мой тред по поводу засилья fragile .unwrap()-ов:
https://mastodon.social/@unclechu/103998022358094226
Бегло глянул. Очень много текста. Но вот это вот ваше: But no way I'm going to participate in a project written in it, just because most of the people who use it (its community) doesn't understand and value its benefits… это вот прямо… детский сад. кучичики… штаны на лямках.

Вы записали самое важное, самое ценное, самое главное достижение языка (как у TypeScript, так и Rust, кстати)… как его недостаток.

Понимаете в чём беда: пока вы не сможете привлечь в вашу экосистему людей, которым плевать на все ваши теории типой и прочую математики… функциональной базы у вас не будет. Я когда глядел на Haskell — хотел приспособить его к генераиции C++ кода, кой-чего делающего с библиотеками. Мне и нужно-то всего ничего: код дизассемблировать, в DWARF глянуть, да C++ код сгенерить.

Что у нас там с диазссемблером? Ну, есть пакет, который прям так и называется: disassembler. Что у нас там Missing? Complete disassembly of all 64-bit instructions? Это в 2020м году?

Ладно, DWARF. Поддержка DWARFv5 уже нормальная или только DWARFv4? Parses the DWARF 2 and DWARF 3 specifications… бип… бип… бииип.

Ok. Что там с геренарацией C++? Смотрим, ищем… поддержка C99 есть, C++ нет. Вы эта… кто рассказывал про то, что Haskell отлично генераторы года пишутся?

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

Вот, собственно, и всё. Вот этим и отличаются промышленные языки от «детского сада».

Пока вы не примите как факт то, что 99% программистов (если не 99.99%) наплевать сейчас и всегда будет наплевать на математическую красоту вашего кода и не придумаете как, тем не менее, использовать их энергию «в мирных целях»… ваш язык так и останется «детским садом».

Меня просто убил (я как его прочитал сразу прикинул реализацию на Haskell в голове на темплейтах и парсерах)
То есть сразу полезли туда, куда практические разработчики меньше всего хотят лезть, да?

Так что нет, отсылка к Rust для меня не пример чего-то well-done.
Это не просто «well-done». Это круче, чем даже «excellent». Это «sublime».

Понимаете: ребята взялись решить весьма и весьма непростую задачу — сделать язык с безопасной работой с памятью без GC… то чего, не сделал даже Haskell… и остановились.

Смогли перейти из «детского сада» во взрослый мир. Перестали «перестраивать фундамент»… Привлекли людей, не интересующихся дизайном языков програмирования… Убедили людей решать на нём реальные задачи и создавать реальные проекты.

Сделали, меньше чем за 10 лет то, что Haskell не то, что не сумел сделать за 30 — на осознание самой задачи у его сторонников ушло четверть века. И как ваш же пример показывает — даже это сделали не все.

Ведь что такое вот это вот? Это — медленное и печальное движение к выходу из «детского сада».

Не знаю — сможет ли Haskell из него, когда-либо, выбраться, но пока Haskell Community не осознает, что ему нужны, как воздух нужны разрабочики, которым начхать на все эти высокоидейные построения и которые не будут радоваться удалению fail из монады… вот до тех пор — он и не перерастёт уровень «детского сада».

P.S. Это, разумеется, только необходимое условие, но не достаточное. Когда вы начинаете играть «в высшей лиге» — начинают играть, также, и многие другие соображения. Но пока вы не осознаете чем отличается «детский сад» от «взрослой жизни»… вы туда и не попадёте.
Вы записали самое важное, самое ценное, самое главное достижение языка (как у TypeScript, так и Rust, кстати)… как его недостаток.

У нас разные представления о том, что считать "достижениями". На кой мне участвовать в проекте, со сколь угодно распрекрасным инструментом, если по факту мне приходится иметь дело с самым обыкновенным среднестатистическим fragile JavaScript shitcode-ом?


TypeScript использованный не по назначению (к чему моя основная претензия аппелирует) — это не более чем time waster. Типизирование кода в TypeScript жрёт много времени, а если у вас повсюду расставлены as any и выключен strictNullChecks, то это лишнее время отправленное в мусорку. Мой поинт прозрачен. Бесполезные инструменты должны быть элиминированы.

Бесполезные инструменты должны быть элиминированы.
Согласен. Проблема в том, что в настоящее время таким инструментом как раз и является Haskell.
Ok. Что там с геренарацией C++? Смотрим, ищем… поддержка C99 есть, C++ нет. Вы эта… кто рассказывал про то, что Haskell отлично генераторы года пишутся?

Так пишутся отлично, только просто не нашлось того, кто написал.


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

Ну вот вы сами и ответили, почему дело обстоит так. И если вы спросите меня, то я для себя в целом условно "разочаровался" в перспективах человечества создания/эволюции и использования действительно хороших инструментов для программирования. Это всегда будет меньшинство, если и те не обмельчают тоже. Слишком мало умных и талантливых людей. Но лично меня в Haskell сообществе и привлекает, что туда попадают и остаются там только талантливые люди, которые чего-то стоят. А не так, что вот есть не самый плохой TypeScript, но никакого желания прикасаться к чужому коду и близко нет, т.к. порог такой низкий, что когда приходишь рандомный в проект, постояно подскальзываешься на детских обосраных памперсах.

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

А не так, что вот есть не самый плохой TypeScript, но никакого желания прикасаться к чужому коду и близко нет, т.к. порог такой низкий, что когда приходишь рандомный в проект, постояно подскальзываешься на детских обосраных памперсах.
Однако у вас есть возможность придти в рандомный проект… а в случае с Haskell — вы, в большинстве случаев, можете только в качестве хобби развлекаться или если начальство «в другую сторону смотрит».

У нас была целая истерика, когда подобных любителей отловили и заставили переписать всё на поддерживаемый язык… Но справились, как бы не бог весть какая проблема, в конечном итоге: крупных же проектов, которые реально тяжело переписать с нуля на Haskell, по обсуждавшися уже причинам, не бывает…
Однако у вас есть возможность придти в рандомный проект… а в случае с Haskell — вы, в большинстве случаев, можете только в качестве хобби развлекаться или если начальство «в другую сторону смотрит».

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

крупных же проектов, которые реально тяжело переписать с нуля на Haskell, по обсуждавшися уже причинам, не бывает…

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

Пока вы не примите как факт то, что 99% программистов (если не 99.99%) наплевать сейчас и всегда будет наплевать на математическую красоту вашего кода и не придумаете как, тем не менее, использовать их энергию «в мирных целях»… ваш язык так и останется «детским садом».

Так я ведь и не заинтересован чтобы те, которым "плевать", приходили в Haskell коммьюнити. Напротив, я рад, что их там нет, и это один из аргументов в пользу моего личного выбора. Я хочу чтобы в этом коммьюнити были только стоящие представители. И поменьше закомплексованных детей, коих достаточно как в сообществе JavaScript, так и упомянутого Rust.

Так я ведь и не заинтересован чтобы те, которым «плевать», приходили в Haskell коммьюнити.
Ну так тогда не рассказывайте другим про то, что они, дескать, в детском саду — если вы сами туда решили вернуться и делаете это сознаельно… так ради бога, но зачем же взрослых-то людей обзывать?

Некрасиво просто.

И поменьше закомплексованных детей, коих достаточно как в сообществе JavaScript, так и упомянутого Rust.
Вы вообще давно с детьми общались-то? Вот как раз у детей в детском саду нет никаких комплексов, они совершенно искренни, чисты и жаждут «изменить мир».

Комплексы и фобии — это как раз результат взросления.
Привлекли людей, не интересующихся дизайном языков програмирования… Убедили людей решать на нём реальные задачи и создавать реальные проекты.

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

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

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

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

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

По большому счёту мне было интересно увидеть — а понимают ли люди, «играющие в бисер» на Haskell, насколько тонка, на самом деле, их экосистема или нет. Вот это вот At this point, the Haskell ecosystem sits on a knife-edge: it could easily fall apart and leave behind the remains of an advanced ecosystem with no practitioners left to maintain the bit-rotted pieces ведь не на пустом месте возникло.

Видно, что некоторые фанаты начали потихоньку прозревать и осознавать, что они могут последовать за чуть более ранней группой (родившей пресловутые «40 Оберонов»… которые никому и ни для чего толком не нужны уже).

Однако разговор с вами показал, что нужно ещё несколько лет подождать (или, возможно, всерьёз посмотреть на Rust), потому что желание таки остаться с «the remains of an advanced ecosystem with no practitioners left to maintain the bit-rotted pieces» (если альтернатива — научиться-таки общаться с «немытыми массами») в сообществе явно слишком сильна.
А потом — вы решили сделать вот так, как на Godbolt: чтобы было много компиляторов и двигающиеся окошки и всё такое прочее. Ну и как вы предлагаете делать? Да, можно, конечно, взять и начать с самых низов всё переделывать. И когда, через месяц-другой кододовая база будет готова — добавить-таки первое видимое изменение.

У вас нет компилятора, который бы подсказал, где в функцию не передаётся нужный аргумент?


Да, я прекрасно знаю что вы сделаете: поставите всех раком. Пример. Вы — такой новичёк, решили изучить Хаскелль. Берёте вот этот вот пример:

Ну, да, нет реализации Applicative, который является суперклассом Monad. В этом смысле LYAH устарела. А в чём проблема-то?

Ну, да, нет реализации Applicative, который является суперклассом Monad. В этом смысле LYAH устарела. А в чём проблема-то?
У меня — вообще нет никаких проблем. Я на всё это посмотрел, посмеялся, написал программу на Go и этим всё кончилось.

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

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

Потому что моя конечнаязадача — ни разу не 'ублажить" компилятор, а что-то совсем-совсем другое. Сконвертировать файл, сделать сервис или там приблуду для работы с базой данных.

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

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

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


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

А зачем выбрасывать и то, и то?


Потому что моя конечная задача — ни разу не 'ублажить" компилятор, а что-то совсем-совсем другое. Сконвертировать файл, сделать сервис или там приблуду для работы с базой данных.

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

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


Рассмотрим следующий абстрактный пример:


// было

foo && foo.bar && foo.bar.baz

// стало

foo?.bar?.baz

// do-нотация

do { t1 <- Maybe(foo); t2 <- t1.bar; t2.baz }

// раскрытая монада

Maybe(foo).bind(t1 => t1.bar).bind(t2 => t2.baz)

// что-то haskell-подобное

(t2 => t2.baz) <$> (t1 => t1.bar) <$> Maybe $ foo

Лично я просто не вижу способа ввести в существующий язык такой синтаксис для монад, который бы обобщил выражение foo?.bar?.baz не теряя в лаконичности.


Хаскелю "повезло" в том, что имя поля в нём одновременно является функцией, и именно это делает монады такими удобными; но другие-то языки подобного бонуса к монадам не имеют!


Плюс не забывайте, в Javascript, C# и вообще всех старых объектно-ориентированных языках null добавлен в систему типов не как T + null, а как T | null, притом это объединение ещё и неотличимо от простого T. Это тоже мешает, в частности именно из-за этого мне выше пришлось явно приводить тип к Maybe.

Хаскелю «повезло» в том, что имя поля в нём одновременно является функцией, и именно это делает монады такими удобными; но другие-то языки подобного бонуса к монадам не имеют!
Это не «повезло». Это — просто изначально грамотно реализованный OOP. Тот факт, что C (и за ним C++) имеют иную форму обращения к методам и полям класса, чем к другим объектам — это просто плохой дизайн.

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

И их исправление либо ведёт к тому, что вы ломаете совместимость (и, соотвественно, повышаете «порог вхождения», так как люди даже просто примеры из учебника не могут запустить), либо у вас появляются разного рода костыли типа ?.… и ещё неизвестно что лучше.
BigInt полезен. Нулевые значения добавят новые интересные способы выстрелить в ногу.
Курица или яйцо?
Не могу сказать за все фичи, но часть из них(всех фич, а не конкретно ES2020) появилась сперва в черновиках ES, и только потом, с определенного уровня были поддержаны в TypeScript

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

Я только за совместное развитие, понимаю его, и одобряю

Просто уточняю факты для изначального комментатора — не все синтаксические элементы в TypeScript были придуманы командой TypeScript, а скорее являются реализацией и обкаткой существующих черновиков ES.
Причем часто на поздних этапах, в то время как babel начинает обкатку со stage0

Например Optional chaining был взят из stage3 — github.com/microsoft/TypeScript/issues/16
А Nullish coalescing обсуждался со stage1, а имплементирован похоже на момент stage3 — github.com/microsoft/TypeScript/issues/26578

Просто для обычного надблюдателя или разработчика это видится чаще всего так — если фича появилась в языке N, а позже в языке M, значит M взял её из N. С JS и TS ситуация похожа, так как не все интересуются draft-спецификациями.

Не, всё не так. Для обычного наблюдателя языка N, где всё появилось (а это, обычно, какой-нибудь Common Lisp, OCaml или Haskell) вообще не существует.

А обсуждается вообще второстепенный вопрос — откуда куда эту фичу позаимствовали… так ли это вообще важно.

P.S. Больше всего меня поражает в сегодняшнем фронтеэнде просто-таки зашкаливающий уровень инфантилизма… Что-то типа мимо проходила настоящая жизнь, расцветали и гибли веб-фреймворки, появился интернет, даже язык для анимации снежинок (js) внезапно стал чуть ли не самым важным на земле. Осознать, что всё это уже было и когда-то «самым важным на земле» языком был RPG, потом VBA, потом уже JS… дано немногим. Интересно чем следующее поколение будет развлекаться? JS уже почти стал более-менее вменяемым и удобным языком, так что пора ему уйти на покой, как бы.
Фичу обсуждали несколько лет, сломали кучу копий и казалось, что этому не будет конца. Но в прошлом году её реализовали в v8 v8.dev/features/optional-chaining. После этого, когда остальные подтянутся, стало лишь вопросом времени.
Я, честно говоря, думал, что это настолько очевидно, что постеснялся заворачивать камент в тег sarcasm, но видимо надо было. Я думаю, все, кто пользовался typescript, или даже просто транспайлером а-ля babel и webpack — прекрасно понимают откуда берутся фичи.
«Ну не прекрасно ли это? Благодаря этому новшеству ES2020 стало возможным избавление от огромного количества строк кода.»
В которых программист вынуждался прописывать разумную обработку особых случаев. Мне вовсе не кажется прекрасным, что теперь ему позволяется на это наплевать.
Динамические импорты иногда бывают нужны. BigInt — хорошо, наконец-то можно будет не представлять BIGINT из базы как текст. Если только бэкэнд позволит.
вынуждался прописывать разумную обработку особых случаев

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


Если только бэкэнд позволит.

Вот бы еще формат JSON позволил( Точнее, формат-то позволяет указать любое число цифр в числе, но JSON.parse не умеет в большие числа

UFO just landed and posted this here

Два разных вызова import('module') создадут лишь один инстанс модуля, ничего плохого тут нет.


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

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

Да и просто, загрузка кода on-demand может быть полезна в некоторых сценариях.
В традиционном программировании это действительно весьма спорная вещь, но в контексте выполнения кода в браузере подгрузка кода по необходимости очень нужна.
Эта фича уже много лет как реализована в webpack через самодельный костыль, но с асинхронными импортами оно используется проще и удобнее.
Нужно это для выноса тяжелых и редко используемых зависимостей из основного бандла проекта.
Был удивлён тем, что 80% перечисленного уже использую в работе с января.
Не подскажете плагины, которыми транспайлите?
UFO just landed and posted this here

Так 14 уже вышла пару недель назад, нет?

ну как бы в прод пихают lts и не все могут обновляться каждую неделю :)

Не все пихают lts, stable вполне норм обычно

Хм, а если сжечь и заново — насколько было-бы хуже/лучше?

сжечь легаси — всегда хорошо. Можно выкинуть костыли из движка.
А то велосипеды ставить некуда :)

Я так мечтал о тебе, божественный "?."

user?.address?.prop1?.prop2?.prop3?.prop4?.value

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

Почему нельзя объявить оператором вызов свойств только один раз перед цепочкой? например, сделать так
user?.address.prop1.prop2.prop3.prop4.value

Может понадобиться как-то в середине цепочки что-то отловить? Я может глупость говорю. Мне это напоминает забор, где под каждую доску стелят соломку, чтобы тихо падало, вместо того, чтобы первой несущей забор свае сказать: «будут падать — не паникуй».

Конечно же, это КУДА лучше, чем было. первый раз когда я столкнулся с такими цепочками я думал я идиот, не может язык так обижать на таких примитивных задачах честную двадцатку лет.
А зачем нужно '?.' ставить после каждого свойства?
Причины прозрачны:
  1. Принцип наименьшего удивления. Подавление непосредственной ошибки конкретным оператором — самое очевидное и явное поведение этого оператором. Добавление маркера одним оператором другим, последующим — это очень как запутанно
  2. Добавить указанное поведение можно в будущем в самом лучшем виде, когда будет понятны юзкейсы. Откатить при выявившейся неудачности будет почти невозможно
  3. У меня есть сомнения в том, что это будет грамматически разрешимо без хаков и проблем с производительностью на случаях сложнее, чем обычная цепочка: o1?.o2[1]?.call()?.end(). Конкретно это цельная цепочка, но представим, что она как-то разбита на несколько подвыражений.

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

В пыхе же это просто варнинг в лог, обратись им хоть к господу богу. Скрипт не упадет.
Ну дык PHP — это изначально о Job Security: главное — чтобы скрипт не упал. А что деньги со счёта не туда уйдут — так это пофиг, это только хорошо, так заказчика можно «доить» вечно.

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

В статье пример неоднозначный. Оператор ставится после optional свойств — которые могут отсутствовать. Для обязательных свойств все остаётся без изменений.
Интересные нововедения. Особенно мне нравятся опциональные цепочки. Javascript как будто впитывает все удачные решения из других языков.
UFO just landed and posted this here
По-моему в последнем примере все логично
1) цикл начинает первую итерацию.
Запросил iterator.next()
Получил Promise.resolve(42), дождался его резолва
Вызвал тело цикла, и вывел в консоль
2) цикл начинает вторую итерацию
Запросил iterator.next()
Генератор внутри себя дошел до yield Promise.reject(43), и вернул его
Идти дальше, пока не был вызван новый(3-ий по счету) .next() — он не имеет права
Цикл получил Promise.reject(43) в качестве нового значения
Цикл дождался, и успешно бросил исключение

В итоге цикл закончился преждевременно, не вызвав .next в последний раз.
А значит генератор никогда не доберётся до своего finally

Вот если бы падение было в самом генераторе(3-ий пример) — то finally выполнился бы
И если бы цикл не упал, и запросил бы next() в третий раз(2-ой пример) — то finally также выполнился бы(как и любой другой код)
UFO just landed and posted this here
Да, я ошибся насчет второго примера.
Он дергает return() непосредственно перед тем как упасть
И странно, что цикл асинхронной итерации не поступает похожим образом при собственном падении(а не в теле цикла)

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

И теперь я тоже не понимаю что происходит, и нахожу поведение в 4-ом примере непонятным
UFO just landed and posted this here

Но что мешает циклу вызвать метод .throw или .return, которые именно для прерывания генератора и предназначены?

Да, я ошибся насчет 2-ого примера
Цикл все-таки падает(в теле цикла)
Но, перед тем как упасть, дождавшись промис, сперва дергает .return, и потом уже падает

В таком случае выглядит странно, что for..await не делает также, когда упал именно при обработке IteratorResult
Но при этом, при падении в теле цикла, он также как и цикл синхронной итерации, дергает return()
if(user && user.address && user.address.prop1 && user.address.prop1.prop2 && user.address.prop1.prop2.prop3 && user.address.prop1.prop2.prop3.prop4)

lodash.get? Не?
Пострадает производительность и типизация
К тому же речь о том, чтобы указывать вопрос для опциональных свойств, а значит замена не один-в-один
На моей памяти, был ещё вариант с монадами Maybe/Optional, а так же линзы. Но выбрали оператор как в C#.
По цифрам ничего не скажу — не было даже мысли проверять.
Можете сами проверить, если вам интересно.
Но навскидку я бы не поставил на успех if-а в этом «соревновании».

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

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

Абсолютно с вами согласен.
Дело в том, что у нас есть часть в вычислительной системе, где на мелочах можно выигрывать или проигрывать.
Можете сами проверить, если вам интересно.

Так и сделаю. Будут результаты, поделюсь…
Что за ужас в разделе про «Код до появления опциональных цепочек»?
Почему бы не проверять значения вложенных объектов рекурсивной функцией?
Чтобы больше нельзя было использовать типизацию, и рефакторинг?
Или чтобы дополнительно замедлить код вызовами функции?
const getUserDarkModePreference = (darkModePreference) => {
return darkModePreference ?? true;
}

вполне можно записать старыми методами так:
const getUserDarkModePreference = (darkModePreference) => {
return (darkModePreference===false)? false: true;
}

Второй вариант совершенно неэквивалентен первому.

При заданных входных значениях: true, null, false, undefined, абсолютно эквивалентен. И кстати более понятен и логичен.
Sign up to leave a comment.