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

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

А где у статьи тег «юмор»?
а автор и не шутит, он серьезно так думает:) В этом и есть весь юмор статьи
НЛО прилетело и опубликовало эту надпись здесь
По поводу тона, да… Наверное, переборщил. Хотелось развлечь и развлечься. И нет, я не против нового. Наоборот, я часто сам выступаю в роли тех, кого критикую в тексте. Да, такое тоже бывает )
НЛО прилетело и опубликовало эту надпись здесь
Неприязни нет, есть большие сомнения. Как и в отношении лямбд, корутин и многого другого. Просто сомнения. Это не мешает мне всем этим пользоваться.
Дело в том, что это такие вещи, которые надо использовать очень аккуратно, важно не переборщить, не перейти границу. И, если я, скажем, могу для себя такую границу худо-бедно прочертить, то обязательно найдется тот, кто этого сделать не сможет и зайдет слишком далеко. К сожалению, сталкиваться с этим приходится гораздо чаще, чем хотелось бы.
НЛО прилетело и опубликовало эту надпись здесь
Но кто будет добавлять механизмы по вывиливанию нула из твоего текущего старого проекта?

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


Ну допустим выпилите вы нулл из проекта. Пусть даже автоматически. Можете ли вы дать гарантию, что программа будет выполняться точно так же, как раньше?
Штуки вроде Option в языках вроде java приводят к дополнительной аллокации объекта, а это не самая дешевая операция. Чуть больше мусора в куче, чуть больше работы для GC. Но в целом программа уже не будет такой же.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Включая неухудшение и неулучшение производительности?

Да, включая нефункциональные требования и в частности производительность.

В вопросе с null, как говориться, «смешались в кучу кони люди». Null возник в момент, когда ссылка на объект перестала интерпретироваться как число. Он просто обозначает, что ваша переменная ни на что сейчас не ссылается. Большинство претензий у разработчиков не к null, а к NPE (или NRE). И, если я не ошибаюсь, именно их появление в языке называют ошибкой.

Все пилюли так или иначе связаны со способами проверки на null. Но кажется, что проблема раздута, нет ни каких доказательств того, что эти пилюли действительно увеличивают производительность разработчика. На конференции Joker лет пять назад сотрудник JetBrains рассказывал, что они потратили сотни человеко-часов на добавление в код Idea аннотаций Nullable и NotNull. И он честно показал метрики по багам связанным с NPE за некоторый период до и после. Расхождение было в пределах погрешности: ошибок как было не много, так и осталось. Лучше бы он про них не рассказывал.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

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

Это просто означает, что нельзя засыпать внутри критических секций. Причём тут wait-free — не очень понятно.

"Нельзя" — это полагаться на человеческий фактор. Предпочтительнее всё же, когда "невозможно". wait-free как раз позволяет обойтись вообще без критических секций и связанных с ними рисков и тормозов.

Вот только:


Во-первых, wait-free алгоритмы, как правило, довольно сложны — а потому куда больше подвержены человеческому фактору нежели критические секции.


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


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

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


  2. Если не использовать критические секции — за ними и не надо следить.


  3. Какие языки и что именно проверяют?


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

Вот только атомарность не компонуется, и вызов нескольких wait-free алгоритмов корректным wait-free алгоритмом может уже и не являться.


Если не использовать критические секции — за ними и не надо следить.

"Не использовать" — это полагаться на человеческий фактор.


Какие языки и что именно проверяют?

Ну вот Rust проверяет:


future returned by bar is not Send
  1. wait-free не про атомарность, а про отсутствие конкуренции за ресурсы. Так что всё прекрасно компонуется.


  2. Линтер в помощь.


  3. Спец проверка для проблемы, которая есть только у мьютексов — это, конечно, замечательно, но у wait-free данной проблемы нет вовсе.



Ну, вот пример корректного wait-free кода с сотней корутин в тредпуле:


static auto produce(Output!long numbers)
{
    foreach (n; 10000000.iota)
        numbers.put(n);
}

static auto consume(Output!long sums, Input!long numbers)
{
    long s;
    foreach (n; numbers)
        s += n;
    sums.put(s);
}

        Output!long numbers;
        Input!long sums;

        foreach (t; 100.iota)
            sums.pair.go!consume(numbers.pair);
        numbers.go!produce;

        long total;
        foreach (s; sums)
            total += s;

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


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

Либо приведите пример, где что-то там не скомпануется, либо не сотрясайте интернет попусту.


Нет с этим проблем — обычный round-robin.


Ну да, кроме тормозов не замечу. Вы что доказать-то пытаетесь тут?

Рассмотрим операции чтения и записи разделяемой переменной. При наличии правильных барьеров они являются вполне себе wait-free алгоритмами.


А теперь попробуйте на основе этих операций увеличить переменную на 1 без гонок.


Вы что доказать-то пытаетесь тут?

Пытаюсь доказать, что "возьмёт такая корутина мьютекс, да как уснёт" не является той проблемой, для решения которой нужны wait-free алгоритмы.

В случае wait-free это будет 2 разные переменные в разных кеш-линиях. Значение счётчика — их сумма.


А всё, что было до "особенно" проигнорировали, ясно.

В случае wait-free это будет 2 разные переменные в разных кеш-линиях. Значение счётчика — их сумма.

Но это решение не является композицией исходных операций.


А всё, что было до "особенно" проигнорировали, ясно.

Ничего я не игнорировал.

У вас не композиция, а смешивание получилось.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Замыкания совсем другая история.
Почему?

Дарю.
Режим markdown в десктопном варианте, где количество символов > вначале строки указывает вложенность цитаты


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

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

далее текст


Хм, действительно с markdown сейчас проблема.

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

Какой именно "ею" будут редко пользоваться?

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

А эта фича опциональной и не является.

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

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

НЛО прилетело и опубликовало эту надпись здесь
файла на сотню строк, который состоит из 60-80 лямбд и замыканий

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


С таким же успехом можно составить файл на 100 строк с 60-80 условными операторами, а потом всем рассказывать что условный оператор — плохо.

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

Ну или для замкнутых переменных можно использовать односимволный префикс типа $name.

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

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

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

Кстати, давать имена скоупам — не самая плохая идея.

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

Ну вот ниже я привёл самую громоздкую конструкцию из замыканий которую я смог придумать — декоратор, который превращает функцию в декоратор:


function declareWrapper(len) {
  function (wrapper) {
    return function decoratorFactory(...config) {
      config.length = len;

      return function decorator(fn) {
        return function wrappedFunction(...args) {
          return wrapper(...config, args2 => fn(...args2), args);
        }
      }
    }
  }
}

// использование:

@declareWrapper(1)
function withLog(name, fn, args) {
    console.log(`${name} enter`, args);
    const ret = fn(args);
    console.log(`${name} exit`, ret);
    return ret;
}

@withLog("foo")
function foo(x) {
    return x+1;
}

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

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

На мой взгляд, ваш тон — тон гомеопата. Гомеопатия не отрицает эффективность проверенных препаратов, но предлагает производить с ними нелепые манипуляции, считая, что эффект препарата с доказанной эффективностью переносится на молекулы воды, которые находились рядом с этим препаратом.
Аналогично, вы критикуете языки, но не доказываете, что ваши претензии являются значимыми. Например, если язык скрывает часть информации, достигая лаконичности, вы относите это к критическим недостаткам, которые приведут к потере денег заказчиком продукта. Проблема здесь в том, что вы не доказываете потери заказчика. Ваша логика основывается на том, что мы однозначно идентифицируем указанные вами недостатки, как нечто негативное. А вот то, что эти недостатки приводят к финансовым потерям заказчика — это уже ваша личная теория, не подкреплённая доказательствами.
Мы можем пойти дальше и найти пару примеров того, как гомеопатический препарат предшествовал выздоровлению пациента. Либо, найти пример того, как внедрение языка Go привело к потерям средств заказчика. Всё это будет равноценными логическими ошибками.
Думаю, что если прибегнуть к доказательствам, то выяснится, что для определённых проектов требуются языки с динамической типизацией, для других — со статической. Одним проектам нужны скоростные функции, написанные на Go, исовершенно не требуются объекты с классами. Другим проектам необходима компоновка сущностей в классы и интерфейсы. Это вполне нормально, когда температуру сбивают парацетомолом, а микрофлору кишечника восстанавливают линексом. Было бы странно решать обе задачи мукалтином и говорить, что парацетомол — безрассудная трата денег, если он только сбивает температуру, но совершенно не борется с кашлем. Собственно, все ваши тезисы сводятся к аналогичным выводам, только для ЯП. Нет, я не против доказательного анализа эффективности языков. Более того, такой анализ проводится разработчиками, которые планируют интеграцию нового языка в проект. Допустим, если сервер не справляется с нагрузкой, перевод АПИ с FastAPI (python) на Go может решить проблему, а близость синтаксиса языков покроет риск поиска специалиста по поддержке. Остаётся только оценить возможность нарастить мощность сервера и сравнить с затратами на внедрение языка. Полагаю, что случаи без оценки эффективности внедрения новых языков не являются системными.

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

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

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

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

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

Вон тут упомянули язык Го, который мне не слишком эстетически близок, но у него есть чёткий use case — «чтобы даже мартышка смогла». При этом его авторы люди немолодые, знающие и вряд ли склонные к экспериментам ради новизны. Однако же обеспечивают прогресс и новизну тем не менее.
НЛО прилетело и опубликовало эту надпись здесь
Ну как бы флаг в руки — всегда будут люди, которые пробуют новое ради новизны, это нормально. Вопрос в том, насколько веяния моды должны дёргать остальную массу, которой новизна ради новизны не слишком интересна. В идеале да, хочешь пробовать новую причёску/музыку/блюдо просто ради пробы — пожалуйста, но не надо других втягивать без нужды.

Но без фазы «а давайте попробуем» го бы остался внутри гугла. Что и произошло с многими другими вещами у гугла.


И у гугла, и не у гугла. Чего там, это нормально. Открываем какой-нибудь rosetta code и видим, что он состоит в основном из совершенно экзотических или мёртвых языков.
НЛО прилетело и опубликовало эту надпись здесь
Ну а какая у человека вообще может быть претензия к тому, что кто-то развлекается приятным ему способом? Кто-то на ютюбе клипы смотрит, кто-то велосипеды изобретает.

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

Это просто ради примера, у меня нет претензий конкретно к Swift, но да, вот так втягивание и происходит.
НЛО прилетело и опубликовало эту надпись здесь
Увы и ах, это делает так Эппл, и Фейсбук, и Юнити, и не только. Ну повторюсь, какие у нормального человека могут быть претензии к тому, что кто-то развлекается новым ради развлечения? Да никаких. Проблемы исключительно тогда, когда выкатывается X, и отныне всё только на X, а у тебя библиотека Y, которая с X не работает вообще, и страдай.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Я даже согласен с основной идеей — что полезность и новшества следует обосновывать.

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

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

Частично эти проблемы от стиля кодирования. И утечки памяти, и запутанная многопоточность обходятся правилами и дисциплиной.
Конечно, эти проблемы также можно обойти сборщиком мусора и иммутабельными данными (как в эрланге), или borrow checker'ом (как в расте), или детектором утечек, etc. Но во времена, когда C++ становился популярными, эти штуки работали медленно (или отсутствовали), и на том этапе выиграл С++. Сейчас, спустя N десятков лет, и сборщики не так тормозят, и borrow checker есть. Конечно, это всё сейчас можно вернуть из прошлого, но тогда использовать не удавалось, приходилось соблюдать дисциплину на С++ (что получалось не во всех проектах).


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

Уверен, для каждого "поворота не туда" были причины. Легко уверенно говорить "не туда" спустя десятилетия. Нельзя так уверенно сказать "не туда" для поворотов, которые делаются сейчас.

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

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

Мне кажется, если бы человека года так с 2007 по 2021 держали в плену и заставляли писать на Java 1.6 и EJB, то после освобождения и знакомства с современными концепциями и языками программирования, разорванный шаблон должен был бы породить текст как раз вроде этого.


Вроде бы уже прошло достаточно времени (7 лет с релиза восьмерки), чтобы даже самые отъявленные ретрограды поняли, в какую именно сторону развивается Java как язык, и поубавили градус хейта в сторону ФП.

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

Да примерно такое же, как и ООП, когда там нельзя даже вызывать методы у примитивных типов.


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

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

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

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

Ответы на ваши вопросы вполне просты и выводятся из теории рынка: в далёком прошлом ПО писали по-научному; ошибки в программах были, но это именно обычные человеческие опечатки/невнимательность, за каждой программой стояло математическое доказательство её работоспособности. Причины: компьютерное время было в дефиците по сравнению с временем программистов, поэтому запускать ПО с ошибками слишком дорого обходилось. А программистов было слишком мало по сравнению с населением Земли, поэтому порог вхождения был крайне высок (требовалось и знание математики, и машин, и алгоритмов...). Сейчас ситуация обратная: процессорное время слишком дешёво, программистов слишком много, ущерб, который испытывает бизнес от багов в ПО очень низкий, ниже, чем стоимость подготовки команды образованных программистов и их работы. Дешевле запустить 100 000 юнит тестов, чем вычитать код из хотя бы 100 строк и напрячь голову. Таким образом рынок продолжает двигаться и по сей день: программистов становится ещё больше, квалификация их становится ещё ниже, порог вхождения поддерживается на сбалансированном уровне за счёт количества спецификаций, которых надо учить, а ущерб, получаемый корпорациями от багов медленно растёт.

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

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

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

Что касается систем автоматических доказательств… помнится, теория алгоритмов гласит, что даже проблема остановки не имеет решения. Поэтому они могут найти какие-то ошибки и упростить их исправление, но окончательное заключение, что программа работает, делает то, что заявлено в ТЗ, и ничего более — должен делать человек.

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

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

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

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

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

Обычно КА рассматривается не как вещь в себе, а как часть системы, включающей в себя, например, внешнюю память.


Так, если "добавить" к КА бесконечную ленту — получится машина Тьюринга, которая, вроде как, обладает тьюринг-полнотой.

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

Как-то так обычно и выглядят КА в реальной жизни, а не в фантазиях.

И насколько я понимаю, все вот эти расширения модели КА делают полученный результат нифига не верифицируемым и недоказуемым. Т.е. ничем не лучше любой другой программы, точно так же можно налажать. Разве нет?
Если добавить к КА память — то вероятно понадобится адресация, а значит адрес.
Зачем? В С переменная действительно именованный адрес памяти, но в Хаскеле — именованное значение.
>Зачем?
Затем, что мы про конечные автоматы говорили изначально, а все же не про хаскель. И их расширение путем добавления (динамической) памяти. Я согласен, что моя формулировка «вероятно понадобится адресация» наверное не совсем правильная — адресация понадобится, если мы будем добавлять память «как в C», а это наверное не единственный вариант.

Как вы себе представляете расширение КА памятью в виде именованных значений а-ля хаскель? Я вполне допускаю что такое сделать можно — но во всяком случае сразу не очевидно, как именно.
Можете пояснить, а откуда взялась динамическая память? у нас есть КА с закрытой таблицей переходов, это статика.
Ну, скорее не откуда, а зачем. Насколько я понимаю, статический КА даже не Тьюринг полный. Для понимания, начните вот отсюда: habr.com/ru/post/550270/?reply_to=22881950#comment_22878648
Извините, я начал с Глушкова :) Насколько я понимаю, если словарь языка конечен, но язык бесконечен, то полнота по Тьюрингу обеспечивается.
Э… если что — минус не мой, но я честно говоря, тоже такой ответ не понял. Можете более развернуто?

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

Так что там у Глушкова?
На всякий случай, чтобы убедиться, что я совсем не фигню порю, полез погуглить. Сразу нашел про эквивалентность линейных автоматов с правилом 110 (с доказательством). Да, это не КА, рассмотренные по одиночке, а только вместе с окрестностью, но это вполне себе КА с конечными словарем и таблицей переходов. Память под каждый КА можно выделить единожды, но переменная состояния должна быть мутабельной.
Так что там у Глушкова?
Ну, не очень хорошо, умер даже :) На такой неконкретный вопрос могу только посоветовать глянуть его книгу «Синтез цифровых автоматов», предисловие и оглавление.
Я хоть и практик, но я пожилой практик :) Поэтому кто такой В.М. Глушков — я в общем-то знаю.
НЛО прилетело и опубликовало эту надпись здесь
Да, это я протупил. Даже если сделать что-то типа ping-pong буфера, неявно вылезает указатель.
И насколько я понимаю, все вот эти расширения модели КА делают полученный результат нифига не верифицируемым и недоказуемым. Т.е. ничем не лучше любой другой программы, точно так же можно налажать. Разве нет?

Разумеется, именно потому я и написал что багов меньше не станет.

А, ну да. В этом смысле вообще никаких вопросов. Я просто с первого раза не до конца понял.
Занете одну небольшую программу на С? sudo называется?
Весь мир пользуется. На большей части продакшен серверов есть. Влияние на безопасность всего и вся критическое.
И баг нашелся. Спустя много-много лет использования. Баг влияющий на безопасность.

Может не надо на С?
Наличие некорректных программ, написанных на каком-то языке, не означает, что невозможно писать корректно на нём. Реализация ООП и прочих парадигм на С оказываются изящны и гибки. В конце концов, точно также, как код на С транслируется в ассемблер, код на С++, JAVA, GO и прочих подобных языков может быть транслирован в эквивалентный им код на С. Но если так поступить, увидев результат вы скорее всего захотите выкинуть половину/90%/99.7% получившегося, просто как не выполняющего никакой полезной функции.

В sudo баг нашёлся: переполнение буфера. Сколько раз на всевозможных формумах обсуждалось, как избегать переполнения.
НЛО прилетело и опубликовало эту надпись здесь
«А я себя хочу ограничивать, потому что внимание у меня так себе, память так себе, концентрация так себе» — существует ли хоть одно направление инженерной деятельности, где не требовались бы сильно развитые перечисленные качества? Получается ли у вас писать хоть на каком-нибудь языке писать с первой попытки без ошибок, пусть даже с помощью всяких утилит?
У меня таже проблема с памятью, концентрацией и т.п, как у автора, а возможно даже хуже. Пробовал хаскел (на что намек в комментарии). Не помогло. Не судьба
Если бы мне поставили задачу, что категорически необходимо взять в команду человека/группу людей, с такими данными… я бы смотрел в сторону ГО. У языка хороший манифест, и если заявленное правда, то в языке мало подводных камней.
Рассуждая дальше, я бы выбрал политику +читаемость -низкоуровневая производительность. Каждый алгоритм стараться вместить в стандартные 25, 40, 80 или сколько строк нынче принято считать за 1 экран. Описание алгоритма должно умещаться в 1 тезис, иначе разбивать его на выполнение цепочки алгоритмов, возможно, с условиями и циклами. Обоснование корректности по стандартному списку из школьного курса: граничные значения, проверка ветвей, циклы, обработка ошибок. Написанный и проверенный код убираем под спойлер, забываем весь только что написанный код, и держим в голове (и на экране) только одну строчку с описанием алгоритма. Когда количество алгоритмов становится больше, то организуем их в структуру. N алгоритмов нижнего уровня убираем под спойлер, а над ними пишем верхний уровень из N/10. Если не получается уместиться хотя бы в N/5, то отбрасываем затею и ищем ошибку в архитектуре.

Таким образом на всём процессе разработки в голове необходимо держать только 1 страницу текущего кода и 1 страницу описаний алгоритмов предыдущего уровня. Это вполне реально. Если рассматривать пирамиду из всего трёх уровней и коэффициентом 5, получается 125 алгоритмов по 40 строк без повторений (5000 строк), среди которых вы сможете свободно ориентироваться не более, чем за 3 обращения к собственной документации. КПД такого кода вряд ли превысит 10%, но даже 1% от теоретического максимума было бы больше, чем мы имеем сейчас в популярном ПО.

Конечно, это всего лишь теоретическое рассуждение, не подкреплённое практикой, но… вдруг.
НЛО прилетело и опубликовало эту надпись здесь

Вот еще бы краткое введение с объяснением смысла алгоритма и можно писать отдельную статью.

Пробовал хаскел (на что намек в комментарии).

Там на самом деле намёк на Idris, Agda и прочие языки с завтипами.


Хотя если считать аварийное завершение приложения хорошим выходом, то подойдёт любой современный язык кроме Си и С++ (причём последний "виноват" лишь в совместимости с Си).

Вы путаете наличие каких-то качеств и их безошибочную работу

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

Вы говорите про ошибки, которые расположены рядом, пускай и на соседних строка, когда глядя на них очевидно, что эти строки ошибочны. Например, если конкатенировать переменные с sql запросом, то очевидно, что они должны быть экранированы, и для этого хватит просмотреть условно пять строчек вверх. В то же время, в си ошибки не очевидны, и проблема заключается не в одной очевидной строке(вызов запроса с не экранированными переменными, а как минимум в двух не очевидно выглядящих. Например, переполнение буфера это две строки — выделение памяти и запись в этот буфер. Обе строки выглядят правильными сами по себе, так как это среднестатистический код на си, но в сочетании дают ошибку. Более того, даже если обе эти строки и верны, а потом, по каким-то причинам между ними мы вставили третью строку, которая либо перевыделяет память, либо меняет значение указателя, то только сочетание этих двух строк приводит к ошибке. Тут будет недостаточно просмотреть код на пять строк вверх, так как запись в буфер может быть в одной функции, создание буфера в другой, а вызов всего этого — в третьей, и соответственно нужно будет просмотреть сразу три функции, на одно простое действие. Никакой внимательностью или аккуратностью этого не достичь, так как это требует слишком большого объёма работы.
В sudo баг нашёлся: переполнение буфера. Сколько раз на всевозможных формумах обсуждалось, как избегать переполнения.
Нужно всего лишь сделать пару тысяч прыжков по коду и прочитать в каждом из них условно от одной, до нескольких сотен строк, ради одной маленькой правки, да.
А си — на нём получается компактный код, и сам стандарт компактный. Что сильно облегчает доказательство.
Размер стандарта влияет лишь на сложность реализации компилятора, и возможно библиотек времени исполнения. После того, как это написано, размер стандарта явно ни на что не влияет, вы же не пишете свой компилятор? Например, если добавить в си указатели с размером, то это усложнит стандарт, но упростит доказательство. Про компактность странно слышать — попробуйте, например на си написать аналог
new DateTime().format("Y")
и вам потребуется сразу три строки, вместо однй, две из которых будут связаны с управлением памятью. Если конкатенировать результат, то вам потребуется ещё как минимум три строки, в то время как в других языках это будет по прежнему хватит одной.
В конце концов, точно также, как код на С транслируется в ассемблер, код на С++, JAVA, GO и прочих подобных языков может быть транслирован в эквивалентный им код на С. Но если так поступить, увидев результат вы скорее всего захотите выкинуть половину/90%/99.7% получившегося, просто как не выполняющего никакой полезной функции.
Любая достаточно сложная программа на C или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp
Это имеет смысл разве что на hello wold, на более сложных задачах вам всё равно придётся писать этот код самостоятельно. Так например, некоторые программы до сих пор не любят пути с юникодом и пробелами, так как программисты на си, вместо того, чтобы использовать библиотечные строки, которые нормально работают с такими путями, изобретают велосипед самостоятельно, и каждый самостоятельно исправляет в нём баги. И касается это не только строк, но и кучи других проблем.
НЛО прилетело и опубликовало эту надпись здесь
На самом деле даже этого не хватит, либо функция экранирования должна быть идемпотентной, что дорого, если вообще возможно.

Нет, не возможно и не должна.

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

Так работают соглашения. По умолчанию предполагается, что никакая строка уровнем выше не экранирована. Если же такое экранирование находится — это ошибка, и она исправляется. И это, как правило, работает.


Для большей же надёжности можно для экранированных строк отдельный тип данных ввести.

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

Не больнее работы со строками...

— new DateTime().format(«Y»), — отличный пример. В том же си, когда printf парсит строку, чтобы вывести обычное число, практика была признана порочной; в с++, к примеру, механизм заменили. На другие языки программирования это не распространяется?

Вы написали код на 2 строчке короче, чем в си, но какой ценой: создание объекта (наверняка со всякими защитами и кучей служебных полей), использование неявного свойства, что конструктор без параметров инициализирует текущей датой и временем, использование загадочного формата «Y», который не соответствует ISO 8601, в памяти зависает объект на неопределённый срок.

Дял ответа на ваш вопрос следует впомнить, что язык программирования — это просто инструмент, и создавался с определённым намерением. Если намерение человека не согласуется с таковым создателя, значит инструмент ему не подходит. Поэтому вопрос можно свести к тому «с каким намерением создавался тот или иной язык».
Проведя аналогичное размышление (https://habr.com/ru/company/timeweb/blog/551224/) можно сделать вывод, что «целевой» язык должен иметь возможность расширять свой функционал без превращения в новый язык. Логично предположить, что у такого языка должна быть какая-то базовая комплектация. Достаточно минималистичная. Но подождите, такой язык уже существует! Это си. Простенький синтаксис, стандартная библиотека на уровне «минималный набор для выживания» и возможность создавать неограниченное количество собственных библиотек.

Давайте тогда подключим какой-нибудь модуль с уже определённым объектом now, и напишем now->year. Полученное значение, разумеется, будет int. sprintf(buf,"%4d",now->year), я считаю, что писать так — я считаю неуважение к самому себе (и пользователям программы), поэтому подключим ещё парочку модулей и сделаем:
/* Предварительно запишем что-нибудь */
WriteC(stream_object,«Сегодня „);
/* Припишем текущий год в одну строчку */
WriteI(stream_object,now->year);
/* Ещё запишем что-нибудь */
WriteC(stream_object,“ год.»);
Согласен, что на с++ есть дополнительная изящность: stream_object<<«Сегодня „<<(now->getyear())<<“ год»;
но смысл не меняетя.

наверняка со всякими защитами
И что в них плохого? У си практически для каждой вещи есть какое-то примечание и если человек его не прочитал, то он обретёт проблему на ровном месте. Если это распространённый проект, то скорее всего, что большинство таких ошибок уже найдены и с ними столкнуться не придётся, но ещё не факт. А непопулярные проекты — вообще кладезь подобных ошибок. Некоторые примечания не пишутся в явном виде, как например инъекция:
На другие языки программирования это не распространяется?
В других языка можно увидеть память если не посмотреть в документацию?
но какой ценой: создание объекта (наверняка со всякими защитами и кучей служебных полей), использование неявного свойства, что конструктор без параметров инициализирует текущей датой и временем, использование загадочного формата «Y», который не соответствует ISO 8601, в памяти зависает объект на неопределённый срок.

Вы уверены, что во всех ста процентах случаев можно избежать выделения памяти в куче, например если это будет регулярное выражение или какой-то ещё более сложный объект и его нужно будет возвращать из функции? В примере ниже вы тоже создаёте now, разве это не объект? Вы полагаете, что неопределённый срок возможен только со сборщиком мусора, но на практике, это может возникать и при ручном управлении памятью. В гноме тоже есть(или уже поправили?) утечка памяти, которая кочевала из релиза в релиз, но до неё никому не было дела, все только переводили стрелки.
я считаю неуважение к самому себе (и пользователям программы), поэтому подключим ещё парочку модулей и сделаем:
Скорее всего, вам придётся ограничиться своим кодом, а при интеграции с библиотекой, придётся использовать более низкоуровневый код.
WriteC(stream_object,«Сегодня „);
Этот код очень зависим от контекста, и если потребуется запись в строку, например для последующей обработки, отправки в базу данных, то потребуется создавать отдельный буфер, что добавит ещё строки три(создание, получение си строки, освобождение). Возможно, эту строку нужно будет ещё раз скопировать уже в массив, либо придётся возвращать сразу уже буфер, что приведёт к проблемам так как другие функции принимают char*, а не StringBuilder*, либо деструктор буфера не должен освобождать строку…

Если в каких-то других языках для решения проблемы можно подключить какой-то пакет, то в си практически каждая проблема приведёт к необходимости написания шаблонного кода.
Проведя аналогичное размышление (https://habr.com/ru/company/timeweb/blog/551224/) можно сделать вывод, что «целевой» язык должен иметь возможность расширять свой функционал без превращения в новый язык.
И в чём это заключается применительно к си? Это лисп можно расширить, за счёт его развитой системы макросов, или руби, за счёт его динамичности буквально во всём, когда прямо в коде класса можно вызвать код, который, например определит какой-то метод.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Если есть язык гарантирующий отсутствие багов, то конечно же не надо.

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

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

Возможности по стрельбе в ногу? Так в этом и смысл.

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

И возможно это вкусовщина, но возможность выстрелить себе в ногу весьма дисциплинирует. Ибо довольно странно видеть защищённый от стрельбы в ногу «Hello world» размером десяток мегабайт и исполняющийся секунды занимая при этом все 8 ядер.
Но, раз уж мы затронули эту тему, пару слов про ООП-диссидентов. Сложно сказать, что движет этими несчастными.

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

Так ведь и для ООП и Java этого никто не делал.
Вы потом правда пишете, что
Реальность такова, что доказательство эффективности различных химических веществ — мероприятие крайне недешевое и доступно только Большой Фарме. А те не будут тратить деньги на лекарства, на которых они не смогут сорвать куш.

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

Ну это откровенного говоря не правда. Испытали его давно. И не раз. И даже с необычной стороны.
Доказательная медицина предполагает определенный алгоритм испытаний. Главным из них является т.н. «двойное (или тройное) слепое рандомизированное исследование» с участием десятков тысяч добровольцев. Говорят, что это реально очень дорого. В отношении парацетамола такие исследования, на сколько мне известно, не проводились.

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

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

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

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

НЛО прилетело и опубликовало эту надпись здесь
Что там проблематично — о производительности рассуждать чуть сложнее, но это совсем другая история.

Насколько удобно там работать с изменяемым состоянием? Условно, есть два массива и в цикле мы вызываем
a[i].e -= 5;
b[i].h -= 10;
Теперь мы захотели изменять ещё и соседние элементы при каком-то условии.
a[i].e -= 5;
b[i].h -= 10;
if(c) {
	b[i - 1].h -= 10;
	b[i + 1].h -= 10;
}
Насколько сильно изменится код, при том, что условие может зависеть от предыдущей итерации цикла?
НЛО прилетело и опубликовало эту надпись здесь
Мне несколько непонятно, что происходит в примере выше, из-за отличного от привычного мне синтаксиса, и необходимости смотреть объявление множества функций.

Посмотрел на примеры State
import Control.Monad.State
main = do 
	r <- runStateT (do
		modify (+1)
		(_, t) <- runStateT (do
			modify (+1)
			c <- get
			lift $ lift $ print c
			) 1
		modify (*t)
		s <- get
		lift $ print s 
		modify (+3)
		) 5
	print r

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

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

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

Детальное ТЗ требует формальной спецификации. Если есть такая спецификация, то есть и язык на котором она написана. Программная инженерия это и есть написание спецификации ТЗ и написание транслятора языка спецификации в исполнимый объект. Перевод спецификации ТЗ в промежуточный код на ЯП высокого уровня, будь то Си или LLVM IR, а так же перевод из промежуточного представления в исполнимый код задачи полностью формальные, а значит реализуемы без участия человека. Создание самого же языка спецификаций ТЗ, скорее, научная работа.
Если у вас есть детальное ТЗ и/или формальная спецификация, то 90% вашей задачи уже решено. Весь software engineering выстроен на проблеме того, что иметь такую спецификацию — утопия.
Честно говоря, не совсем понял в чём посыл статьи. Да, программисты играют в войнушку с кривыми палками, и никого это особо не волнует. Программирование все-таки больше про деньги, и если вдруг решат бороться за эффективность и/или производительность труда в рамках компании, выбор языка будет далеко не на первом месте.

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


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

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

Наверно, это проблемы авиации, что в ней используется "software provided as-is". Нужно что-то более надёжное — переписывайте. Глупо предъявлять к системе подсчёта лайков требования как к самолёту — это неэффективно, высокая надёжность не везде необходима.

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

Разве "as-is" — не исчерпывающая информация о "надёжности"?

НЛО прилетело и опубликовало эту надпись здесь
Интересный пост. В чём-то автор прав, в чём-то нет, но определённо излил душу, рассказал о наболевшем.

Считаю, что обсуждать пост не надо, он самодостаточен и тем прекрасен :-D

А где абзац про ООП и джаву то? Как к ним относится доказательная медицина? Если продолжать аналогии — если джава лечит все болезни, то зачем вообще эта «альтернативная медицина»?

Зачем усложнять, когда всё просто?!
«Выживают» те ЯП, которые приносят большую прибыль.

Так что популярные ЯП уже доказали свою «правильность».

Грубо говоря «доказательство» происходит «здесь и сейчас» и «напрягаться» не надо «от слова совсем». ;-)
> За его запятой может прятаться вселенная, а за вашим «плюсиком» ну максимум — конкатенация строк.
$result=universe($parameters);
$universe=new Universe($parameters);
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

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


Продираться через блевотину в поисках хотя бы вопросов, а не то, что ответов… так себе.


Я считаю, что подобным материалам не место на хабре.

Спасибо за ценный отзыв, Николай Михайлович!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории