Информация об изменениях

Сообщение Re[6]: Почему программисты прошлого были умнее от 28.11.2022 4:11

Изменено 28.11.2022 4:54 vdimas

Re[6]: Почему программисты прошлого были умнее
Здравствуйте, Sinclair, Вы писали:

V>>Я собеседовал десятки, если не больше сотни в разные годы.

V>>И тенденция слишком однозначная, чтобы это было простым совпадением на многих десятках людей.
S>Есть какие-то объективные данные?

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


S>Без них это так — трендёж о том, как раньше девки были краше.


Трындёж — это не иметь возможности сравнить претендентов из разных эпох, но делать заявления.


V>>И дело не в уровне программистов, дело кое в чём катастрофическом другом — профессия воспринимается всё более обыденно, всё меньше горят глаза, всё менее ЛЮБОПЫТНО.

S>
S>Угу. Я закончил школу в 1993 году. Из параллели в 50 человек в программирование пошло двое с половиной.

Наверно потому что им было интересно и до ВУЗ-а.


S>И сейчас успеха в программировании добивается примерно 1 из 20.


Верно, сейчас вменяемых 1-2 человека из выпускаемой группы ВУЗ-а в 20+ человек.
Я так и говорил, а ты споришь.

Зато у нас из группы примерно треть достаточно успешны, т.е. примерно как эти 1-2 сегодня.
И так же из других групп в потоке и еще на 2-х родственных специальностях.


S>То, что теперь пытаются идти в программирование 15 из 20, общей картины никак не меняет.


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

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

А сейчас пошли и у них всё стало получаться, "загорелись" профессией и всё в этом роде.

Но это всё неспособно компенсировать всё более возрастающий поток "балласта".
И этот "балласт" уже давно и серьёзно влияет на индустрию.

Разговоры про "планку входа" у нас шли вовсю шли уже в первой половине нулевых.
Я не могут себе представить эти разговоры в твоём 93-м, потому что за пределами требуемой на тот момент "планки входа" этих людей просто не было в профессии — они получали "корочку", но занимались другой деятельностью.


V>>А с чем ты сравниваешь?

S>С девяностыми.

Ты не ответил на вопрос.
Ты ж учился не на IT, откуда у тебя статистика по однокурсникам, учившимся на IT?


S>Ну, и с тем, какие программы и какими программистами писались в 80х.


Отож, 90% нынеших программистов принципиально неспособны писать те программы.
Думаю, конкретно ты был бы способен, но тебе пришлось бы многое пересмотреть из нынешних своих представлений.
Ну и прокачать некоторые навыки, например, внимательность и объективность.


S>У меня инсайд из НИИ Автоматизированных Систем — типичное учреждение промышленного программирования.

S>Уверяю вас: никакого "любопытства", никаких "исследователей". Совершенно простые смертные. Тётеньки, которые писали унылые программы на фортране.

И они получают свои 5-10 тыс $$ в месяц, поэтому сидят там? ))
Или там остались только те, кто не способен столько получать?


V>>И в насколько разные это были годы?

S>Лично я — с конца 90х и до сих пор.

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

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

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


V>>Проблема примерно в следующем — увлекающийся программист осваивал материала по специальности примерно раз в 10 больше, чем давала программа ВУЗ-а.

S>У нас и в 100 раз можно было больше, т.к. специальности не преподавали.
V>>Сейчас доля таких студентовв разы ниже, дай бог 1-2 на группу.
S>Их всегда и было 1-2 на группу.

Это в твоей непрофильной специальности из группы 1-2 любопытсвовали в IT, оттуда статистика? ))
Вообще странно, что ты сразу не пошёл на интересующую тебя специальность.


S>Если в одной группе окажется 3-4, то в другой будет 0-1.


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

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

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


V>>И у тебя разве есть достаточная выборка по однокурсникам хотя бы до начала нулевых, чтобы сравнивать с тем, как оно есть сейчас?

S>Конечно есть выборка.

Та не мог твой ВУЗ быть совсем отсталым, даже в пик развала в 93-м.
Просто у тебя выборка по непрофильной специальности.


V>>Чел попытался присвоить себе "ошибку", которая до него была уже "сделана" эдак тысячекратно, например, тот же nil в Lisp.

S>Да, с самомнением у вас всё хорошо. Хоар, оказывается, тупой — сам не знает, что сделал. И то, что вы nil в lisp не отличаете от NULL в Алголе — тоже плохо.

Оба на!
Пошёл юмор! ))

В Lisp и Algol абсолютно идентичные nil, никакого NULL в Algol нет, RTFM!
И распространённой практикой в те годы были списки на манер лисповых — cons/car-cdr.

Защита от nil всегда через проверки, что в Lisp, что в Algol, безальтернативно.

Далее.
Lisp не в вакууме жил, решал в т.ч. реальные задачи.
В том числе обращался к низлежащим АПИ и точно так же мог спровоцировать проходы по памяти.

Абсолютно идентично это было и в Algol.
Ответственность по-прежнему лежала на программисте — проверил ли он аргументы перед вызовом низлежащих опасных вызовов или нет.
Разумеется, идущие в поставке стандартные библиотеки обоих языков проверяли аргументы, в т.ч. на nil, т.е. были безопасны как в Lisp, так и в Algol, но речь не о стандартных библиотеках, верно?

Речь о пространстве допустимых ошибок.
В Лиспе вообще много чего проверять надо было, чтобы программа не улетела не туда в своём исполнении. ))
Таки, сильно динамический язык.

Ну и, тот же Лисп и им подобные языки тоже на чём-то писать надо — не всё же на асме?

Просто Хоар реально загоняет, я же приводил выдержки:

Ошибка уродливее, чем обратная косая черта в Windows

Ну какая еще Windows, хосподя...
Это из DOS.
А там из CP-M.
В 70-х годах Хоар об этом знал хорошо, но сейчас забыл, увы, поэтому несёт тихий бред.

Как думаешь, какой чертой пользовался сам Хоар приличную часть своей карьеры еще до всяких Windows? ))


V>>Альтернатива тут возможна только через IoС, т.е. в функциональных языках, когда некоему акцессору (итератору, скажем), подаётся колбэк.

S>Ок, самовосхваление кончилось. Пошёл чистый, незамутнённый бред. IoC и функциональные языки соотносятся примерно никак.

Оба на, юмор продолжается! ))

В общем, функциональные языки целиком на парадигме IoC живут.
Прямо начиная с Lisp.
Сам термин IoC из объектно-ориентированной среды, я его использовал сугубо удобства ради.
В Алгол68 ф-ии тоже поддерживаются как первоклассные типы, если что.


S>Нормальная альтернатива — это собственно выразимость требования непустоты ссылки в терминах системы типов.


Я тебе заранее на это уже отвечал — смотри как это обыгрывается в функциональных языках или в том же Kotlin, т.е. в языках, где присутствуют исключения.
В той версии Алгола не было исключений и не было первоклассных ф-ий.
Он появились в Алгол68.

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

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

Далее.
Если в языке есть возможность описывать пользовательские типы, выбрасывать и перехватывать исключения, переопределять операторы и вводить алиасы типов (как typedef в С/С++), то проблема упрощается.

У нас прямо в боевых проектах на С++ из базовой нашей библиотеки используется:
typedef NotNull<SomeType> SomeTypeRef;

void someFunc(SomeTypeRef arg) { ... }


Реализация NotNull тривиальна в единицы строк, а используется широко:
template<typename T>
class NotNull {
    T * ptr; 

public:
    NotNull(const NotNull<T> & other)
        : ptr(other.ptr) {}

    NotNull(T * other) 
        :  ptr(other)  
    {
        if(!other) 
            throw std::invalid_argument(...);
    }

    T* operator->() { return ptr; }

    T& operator*() { return *ptr; }
   
    ...
}



S>Колбек тут совершенно ни при чём — в нормальной системе типов у меня nullable reference отличается от non-nullable reference, и это всё статически проверяется.


Это, как раз, самая простая часть, не вызывающая сложностей.

У меня выше тоже SomeTypeRef статически отличается от SomeType*.
И никаких дополнительных фич языка не потребовалось.

А теперь давай про интероперабельность nullable и non-nullable типов.
Вот проверь статически Optional<T*> без IoC или исключений. ))
template<typename T>
class Optional;

typedef Optional<SomeType> SomeTypePtr;

template<typename T>
class Optional<T*> {
    T * ptr; 

public:
    // ========== для исключений ==========
    explicit operator bool() const { return !!ptr; }

    operator NotNull<T>() const {
        if(T * p = ptr)
            return NotNull<T>(p);    // здесь лишняя проверка нивелируется

        throw std::logic_error(...);
    }
    // ====================================

    // =========== для IoC ================
    template<class Some, class None>
    void dispatch(Some some, None none) {
        if(T * p = ptr)
            some(p);
        else
            none();
    }
    // ====================================
}

void func(SomeTypeRef arg) {
  arg->someFunc(); // безопасно
}

void reportEmpty() {}

SomeTypePtr ptr = GetOptionalPtr();
func(ptr); // автоконверсия в NotNull, выбросит исключение, если NULL

if(ptr)
   func(ptr); // безопасно, ноль дополнительных проверок

ptr.dispatch(func, reportEmpty); // функциональный стиль.


В Хаскеле возможен только IoC вариант, т.е. рантайм-диспетчеризация как в последней строчке:
data Optional t = Default | Specific t;

func :: Optional SomeType -> Void
func (Specific ptr) = someFunc ptr
func Default        = reportEmpty


Да, до некоторого предела вложенности компилятор при оптимизации производит распространение констант, поэтому часто рантайм-диспетчеризация заменяется на прямо вызов, но в современных С++ эта оптимизация куда глубже/качественней, так шта мой С++ вариант будет соптимизирован лучше.


S>Внезапно значительная часть ссылок оказывается non-nullable.


Какое открытие! ))


S>А nullable reference нужны не чаще чем, скажем, Nullable<int>. Как-то же работает C# с int? безо всяких IoC и коллбеков. Удивительно, да?


Не работает, RTFM! ))
Выбрасывает исключения.


V>>Других техник борьбы с nil, кроме диспетчеризации на манер IoC, в природе не существует, даже в Kotlin.

S>(facepalm). Тут прекрасно всё — и "даже" Котлин, как вершина развития языкостроения, и применение IoC для борьбы с nil, и диспетчеризация...
S>Жаль, что всё современное программирование прошло мимо вас.

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

ОК, дай мне пример языка, которым ты владеешь хотя бы на самом начальном уровне, где есть строгая первоклассная поддержка non-nullable ссылок.
Скорее всего, у тебя в копилке ни одного такого языка нет.
Но очередное громкое заявление про "современное программирование" было! ))

В общем, такие языки есть, но их нет в мейнстриме.
Более того, многие из них достаточно старые.


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

Посмотри, например, языки, со встроенной поддержкой зависимых типов, как там обыгрывают подобные сценарии.


V>>А фраза целиком лишь характеризует уже старого и недостаточно умного человека.

S>Забавно, что вы тут усердно опровергаете утверждение "программисты прошлого были умнее".

Хоар и был умнее.
Человеку почти 90 лет, тут не стоит манипулировать/спекулировать.


S>Видите, и Хоар вам недостаточно умён.


1. Один из распространённых приёмов демагогии.
2. Я ответил на эти спекуляции заране, зная тебя. Увы, не помогло. ))

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


S>Да, я помню, для вас и Билл Гейтс недостаточно успешен


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

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


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

S>Эта фраза показывает, что вы не понимаете сути "проблемы нулевых ссылок".

Да нет, эта фраза показывает, что ты не понимаешь зависимых типов.
Проблема же не только в null, ссылка вообще может ссылаться на мусор в памяти.
Т.е. простая проверка на не null не решает вопрос окончательно.

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


V>>И чего ж старик не упомянул эту проблему, хотя проблема в точности идентичная?

S>Надо полагать, оттого, что проблема — не в точности идентичная.
V>>Это ровно один и тот же класс ошибок, вызванных одной и той же причиной — невозможностью в compile-time выразить ВСЕ требуемые ограничения из runtime.
S>Это какой-то очень широкий класс ошибок.

Уфф...
Адрес — это индекс ячейки памяти.
Прблема невалидного адреса в точности равна проблеме невалидного индекса.

И ведет к асболютно идентичным ошибкам — к неверной реентерпретации памяти.
Я тебе в C# запросто создам управляемую ссылку на мусор в памяти (произвольный адрес, не обязательно null).

И никакое #nullable enable не спасёт.
Да и оно сейчас пока живёт как ворнинги.
И запросто обходится через !, без рантайм-проверок.

Это ты вот это всё имел ввиду под "современным программированием"? ))

В общем, в языках с зависимыми типами нет принципиальной разницы на допустимые ограничения, контроллируемые системой типов, будь это [0, 1, 2] или [0, 1..]
Там работает один и тот же механизм.

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

Например, в языках с зависимыми типами без исключений может применяться flow control,
т.е., некий uint[0..MAX_UINT] может быть приведёт к ограниченному типу uint[0..10] через простой if:
uint array[10] = ...;
uint x = readX();
func(array[x]); // ошибка компиляции

if(x < 10)
   func(array[x]); // OK, тип переменной x модифицируется контекстом предыдущих вычислений



S>Ну, то есть понятно, что в общем случае проблема — ровно в том, что статическое доказательство корректности произвольной программы сводится к проблеме останова, которая неразрешима.


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

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

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

Например, во многих языках с зависимыми типами ты не можешь прочитать массив данных из файла и передать его куда-то дальше, примерно так (псевдокод):
let array<?>(int) = readFromFile();
process(array);


Ты можешь действовать только через IoC:
readFromFile(process<N: uint>: array<N>(int) -> Void) {
    let loop<N:uint> array<N>(int) ar = {
      ...
      if(eof) 
        process(ar);  // конец работы, вызов поданного продолжения
      else
        loop(insert(ar, data))  // хвостовая рекурсия, вызов лямбды loop с новым типом ar (с новым размером)
    }

    loop array<0>(int);  // начало цикла
}


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


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


Давай не будем о нормальности.
Теория зависимых типов была разработана не с 0-ля в 70-е, а первые работы на эту тему были еще в 1925-м, задолго до первых компьютеров.
Не надо считать всех идиотами. ))

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


S>В частности, "проблема" нулевой ссылки легко статически разрешима на более-менее любой современной платформе.


Если ты про C#, то анекдот хороший.


S>Даже настольные языки, собранные на коленке энтузиастами, прекрасно обходятся без нулевых ссылок.


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

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

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


S>Кстати, вопросы индексов в массивах давно закрыты: https://www.cs.cmu.edu/~fp/papers/pldi98dml.pdf. Так то про "невозможность в компайл-тайм" — это лично ваши заблуждения. Развивайтесь, читайте.


— Ты куда, в баню?
— Да нет, в баню!


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

И статью ты ниасилил, иначе бы не сверкал невежеством тут:

S>IoC и функциональные языки соотносятся примерно никак.

V>>В точности проблема нулевых ссылок повторяется в массивах, к которым обращаются по индексу.
S>Эта фраза показывает, что вы не понимаете сути "проблемы нулевых ссылок".


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

Ты обратил по ссылке внимание на сам принцип написания программ?
Это другой принцип проектирования.

Показан один из беднейших инструментов реализации ЗТ — хвостовая рекурсия, каждый раз вызывается локальная ламбда с новым типом аргументов.
И вот как раз конечный результат вычислений можено будет подать куда-нибудь далее в вычислениях поданному как аргумент функциональному объекту, потому-то и IoC, что список неизвестного размера нельзя вернуть из ф-ии. ))
Можно только вызывать другую ф-ию в типизированном контексте.


V>>(в языках, которые претендуют на хоть какую-то эффективность)

S>Эта фраза тоже выдаёт непонимание сути проблемы. Как раз неэффективное решение проблемы и состоит в переносе проверок в ран-тайм.

Проверки в рантайм всё-равно есть, вопрос в том — сколько их.
Ведь достаточно проверить один раз (или достоверно получить валидное значение по new) и далее распространять значение уже с признаком валидности.

Насчёт "непонимания сути" — опять улыбнуло.
Это ты в своём C# не понимаешь сути, потому что нет алиасов типов, невозможно отсутствие конструктора структуры без параметров.
Поэтому ср-вами языка проблему не решить — нужен встроенный костыль.

А я тебе выше показал примеры на C++, которую столь узкую постановку вопроса решают на раз-два.
Причём, с нулевым оверхедом, в сравнении с обычными указателями.
И без переделки исходников, т.к. Optional<T*> и NotNull<T> — это умные указатели, с переопределёнными operator-> и operator*, т.е. их можно использовать там, где ожидался обычный указатель, только теперь можно распространять non-nullable указатели без лишних проверок.


S>Любое компайл-тайм решение получается более эффективным, как только время ожидаемой работы программы становится достаточно большим.


Увы, увы.
Программы, написанные в этом стиле, как по ссылке, построены таким образом, что в функции всегда передаются другие функции-"продолжения".
Т.е. вся работа основной программы — это бесконечный вызов ф-ий из ф-ий.
Но стек ведь не бесконечен? Отсюда монады и ленивость.
То бишь, "энергичный" вызов ф-ий заменяется динамически выстроенным графом продолжений, где вычисления передаются динамически же вычисленным в процессе работы программы веткам графа через явные if или неявную дистептчеризацию, на манер Хаскеля.
То бишь, никакого call не происходит, вычислительная модель языка в ленивой манере протягивает монаду процесса/потока по этому графу вычислений.

То бишь, вычисления выглядят в рантайме так:
func1 -> result1 -> func2 -> result2 -> func3 -> ...

И до чудес быстродействия там как до звёзд.


V>>И до изобретения исключений, без техники IoC, т.е. без функциональных ср-в в языке, ошибок такого рода в процедурных языках избежать было нельзя, можно было лишь сгенерировать проверочный код компилятором (...) и аварийно завершить программу, если проверка на индекс или nil была неудачной.

S>И опять вы складываете в одну кучу рантайм и компайл-тайм проверки. Это вы мухлюете или вправду не видите разницы?

Это ты не понял прочитанного. ))
Медитируй до просветления, плиз.


V>>Разумеется, новое дыхание в конце 90-х и начале 2000-х получили теории языков.

S>Вот как раз тут прямо таки нового появилось не очень много.
V>>Без изобретения нового.
S>Воот! В основном то, что мы наблюдаем — приезд в мейнстрим идей и концепций из 1960х. Так что "теории языков" вычёркиваем.

В 70-х только начали классифицировать типизированные лямбда-исчисления.
Классификация была нужна для понимания (1) необходимого и достаточного набора конструктов языка для соответствия выранным критериям и (2) для понимания необходимых техник программирования в данном классе ограничений, см лямбда куб (наглядное представление классификации).

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

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

Сегодняшние столь же "академические" языки в мейнстриме — это Golang, Dart, Хаскель.
И то, мейнстрим весьма условный. ))

F# (OCaml), Scala, Kotlin — уже нет.

C# — совсем нет.
В рамках выбранной концепции он далеко не полон, не обладает всеми необходимыми выразительными св-вами.
Собсно, поэтому развитие языка запросто идёт дальше при сохранении бинарного формата сборок еще аж со времён 2-го дотнета.
Блин, указатели на ф-ии только-только ввели.
Через stackalloc стало можно размещать не только примитивные целочисленные типы вот только недавно.
И т.д. и т.п.


V>>Я когда-то уже высказывался на эти темы ~12 лет назад в ответ молодому и горячему в те года Вольфхануду:

V>>http://www.rsdn.org/forum/philosophy/4247637.1
S>Ну, так и зачем самому себе противоречить?

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

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

Как тебе задача — выделить из данной цепочки символов всевозможные подцепочки максимальной длины, встречающиеся более одного раза.
Оцени сложность в терминах O.
Умножь на многие мегабайты размеров современных программ.
Это всего лишь одна из подзадач в процессе оптимизации — склейка самоповторов после стирания типов на одной из стадий оптимизации.
Сначала над типами работает бета-редукция и генерирование уникального кода из генерик-представления.
(А чуть ли не весь код на Хаскель — это сплошные генерики в терминах C#)
Re[6]: Почему программисты прошлого были умнее
Здравствуйте, Sinclair, Вы писали:

V>>Я собеседовал десятки, если не больше сотни в разные годы.

V>>И тенденция слишком однозначная, чтобы это было простым совпадением на многих десятках людей.
S>Есть какие-то объективные данные?

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


S>Без них это так — трендёж о том, как раньше девки были краше.


Трындёж — это не иметь возможности сравнить претендентов из разных эпох, но делать заявления.


V>>И дело не в уровне программистов, дело кое в чём катастрофическом другом — профессия воспринимается всё более обыденно, всё меньше горят глаза, всё менее ЛЮБОПЫТНО.

S>
S>Угу. Я закончил школу в 1993 году. Из параллели в 50 человек в программирование пошло двое с половиной.

Наверно потому что им было интересно и до ВУЗ-а.


S>И сейчас успеха в программировании добивается примерно 1 из 20.


Верно, сейчас вменяемых 1-2 человека из выпускаемой группы ВУЗ-а в 20+ человек.
Я так и говорил, а ты споришь.

Зато у нас из группы примерно треть достаточно успешны, т.е. примерно как эти 1-2 сегодня.
И так же из других групп в потоке и еще на 2-х родственных специальностях.


S>То, что теперь пытаются идти в программирование 15 из 20, общей картины никак не меняет.


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

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

А сейчас пошли и у них всё стало получаться, "загорелись" профессией и всё в этом роде.

Но это всё неспособно компенсировать всё более возрастающий поток "балласта".
И этот "балласт" уже давно и серьёзно влияет на индустрию.

Разговоры про "планку входа" у нас шли вовсю шли уже в первой половине нулевых.
Я не могу себе представить эти разговоры в твоём 93-м, потому что за пределами требуемой на тот момент "планки входа" этих людей просто не было в профессии — они получали "корочку", но занимались другой деятельностью.


V>>А с чем ты сравниваешь?

S>С девяностыми.

Ты не ответил на вопрос.
Ты ж учился не на IT, откуда у тебя статистика по однокурсникам, учившимся на IT?


S>Ну, и с тем, какие программы и какими программистами писались в 80х.


Отож, 90% нынеших программистов принципиально неспособны писать те программы.
Думаю, конкретно ты был бы способен, но тебе пришлось бы многое пересмотреть из нынешних своих представлений.
Ну и прокачать некоторые навыки, например, внимательность и объективность.


S>У меня инсайд из НИИ Автоматизированных Систем — типичное учреждение промышленного программирования.

S>Уверяю вас: никакого "любопытства", никаких "исследователей". Совершенно простые смертные. Тётеньки, которые писали унылые программы на фортране.

И они получают свои 5-10 тыс $$ в месяц, поэтому сидят там? ))
Или там остались только те, кто не способен столько получать?


V>>И в насколько разные это были годы?

S>Лично я — с конца 90х и до сих пор.

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

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

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


V>>Проблема примерно в следующем — увлекающийся программист осваивал материала по специальности примерно раз в 10 больше, чем давала программа ВУЗ-а.

S>У нас и в 100 раз можно было больше, т.к. специальности не преподавали.
V>>Сейчас доля таких студентовв разы ниже, дай бог 1-2 на группу.
S>Их всегда и было 1-2 на группу.

Это в твоей непрофильной специальности из группы 1-2 любопытсвовали в IT, оттуда статистика? ))
Вообще странно, что ты сразу не пошёл на интересующую тебя специальность.


S>Если в одной группе окажется 3-4, то в другой будет 0-1.


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

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

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


V>>И у тебя разве есть достаточная выборка по однокурсникам хотя бы до начала нулевых, чтобы сравнивать с тем, как оно есть сейчас?

S>Конечно есть выборка.

Та не мог твой ВУЗ быть совсем отсталым, даже в пик развала в 93-м.
Просто у тебя выборка по непрофильной специальности.


V>>Чел попытался присвоить себе "ошибку", которая до него была уже "сделана" эдак тысячекратно, например, тот же nil в Lisp.

S>Да, с самомнением у вас всё хорошо. Хоар, оказывается, тупой — сам не знает, что сделал. И то, что вы nil в lisp не отличаете от NULL в Алголе — тоже плохо.

Оба на!
Пошёл юмор! ))

В Lisp и Algol абсолютно идентичные nil, никакого NULL в Algol нет, RTFM!
И распространённой практикой в те годы были списки на манер лисповых — cons/car-cdr.

Защита от nil всегда через проверки, что в Lisp, что в Algol, безальтернативно.

Далее.
Lisp не в вакууме жил, решал в т.ч. реальные задачи.
В том числе обращался к низлежащим АПИ и точно так же мог спровоцировать проходы по памяти.

Абсолютно идентично это было и в Algol.
Ответственность по-прежнему лежала на программисте — проверил ли он аргументы перед вызовом низлежащих опасных вызовов или нет.
Разумеется, идущие в поставке стандартные библиотеки обоих языков проверяли аргументы, в т.ч. на nil, т.е. были безопасны как в Lisp, так и в Algol, но речь не о стандартных библиотеках, верно?

Речь о пространстве допустимых ошибок.
В Лиспе вообще много чего проверять надо было, чтобы программа не улетела не туда в своём исполнении. ))
Таки, сильно динамический язык.

Ну и, тот же Лисп и им подобные языки тоже на чём-то писать надо — не всё же на асме?

Просто Хоар реально загоняет, я же приводил выдержки:

Ошибка уродливее, чем обратная косая черта в Windows

Ну какая еще Windows, хосподя...
Это из DOS.
А там из CP-M.
В 70-х годах Хоар об этом знал хорошо, но сейчас забыл, увы, поэтому несёт тихий бред.

Как думаешь, какой чертой пользовался сам Хоар приличную часть своей карьеры еще до всяких Windows? ))


V>>Альтернатива тут возможна только через IoС, т.е. в функциональных языках, когда некоему акцессору (итератору, скажем), подаётся колбэк.

S>Ок, самовосхваление кончилось. Пошёл чистый, незамутнённый бред. IoC и функциональные языки соотносятся примерно никак.

Оба на, юмор продолжается! ))

В общем, функциональные языки целиком на парадигме IoC живут.
Прямо начиная с Lisp.
Сам термин IoC из объектно-ориентированной среды, я его использовал сугубо удобства ради.
В Алгол68 ф-ии тоже поддерживаются как первоклассные типы, если что.


S>Нормальная альтернатива — это собственно выразимость требования непустоты ссылки в терминах системы типов.


Я тебе заранее на это уже отвечал — смотри как это обыгрывается в функциональных языках или в том же Kotlin, т.е. в языках, где присутствуют исключения.
В той версии Алгола не было исключений и не было первоклассных ф-ий.
Он появились в Алгол68.

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

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

Далее.
Если в языке есть возможность описывать пользовательские типы, выбрасывать и перехватывать исключения, переопределять операторы и вводить алиасы типов (как typedef в С/С++), то проблема упрощается.

У нас прямо в боевых проектах на С++ из базовой нашей библиотеки используется:
typedef NotNull<SomeType> SomeTypeRef;

void someFunc(SomeTypeRef arg) { ... }


Реализация NotNull тривиальна в единицы строк, а используется широко:
template<typename T>
class NotNull {
    T * ptr; 

public:
    NotNull(const NotNull<T> & other)
        : ptr(other.ptr) {}

    NotNull(T * other) 
        :  ptr(other)  
    {
        if(!other) 
            throw std::invalid_argument(...);
    }

    T* operator->() { return ptr; }

    T& operator*() { return *ptr; }
   
    ...
}



S>Колбек тут совершенно ни при чём — в нормальной системе типов у меня nullable reference отличается от non-nullable reference, и это всё статически проверяется.


Это, как раз, самая простая часть, не вызывающая сложностей.

У меня выше тоже SomeTypeRef статически отличается от SomeType*.
И никаких дополнительных фич языка не потребовалось.

А теперь давай про интероперабельность nullable и non-nullable типов.
Вот проверь статически Optional<T*> без IoC или исключений. ))
template<typename T>
class Optional;

typedef Optional<SomeType> SomeTypePtr;

template<typename T>
class Optional<T*> {
    T * ptr; 

public:
    // ========== для исключений ==========
    explicit operator bool() const { return !!ptr; }

    operator NotNull<T>() const {
        if(T * p = ptr)
            return NotNull<T>(p);    // здесь лишняя проверка нивелируется

        throw std::logic_error(...);
    }
    // ====================================

    // =========== для IoC ================
    template<class Some, class None>
    void dispatch(Some some, None none) {
        if(T * p = ptr)
            some(p);
        else
            none();
    }
    // ====================================
}

void func(SomeTypeRef arg) {
  arg->someFunc(); // безопасно
}

void reportEmpty() {}

SomeTypePtr ptr = GetOptionalPtr();
func(ptr); // автоконверсия в NotNull, выбросит исключение, если NULL

if(ptr)
   func(ptr); // безопасно, ноль дополнительных проверок

ptr.dispatch(func, reportEmpty); // функциональный стиль.


В Хаскеле возможен только IoC вариант, т.е. рантайм-диспетчеризация как в последней строчке:
data Optional t = Default | Specific t;

func :: Optional SomeType -> Void
func (Specific ptr) = someFunc ptr
func Default        = reportEmpty


Да, до некоторого предела вложенности компилятор при оптимизации производит распространение констант, поэтому часто рантайм-диспетчеризация заменяется на прямо вызов, но в современных С++ эта оптимизация куда глубже/качественней, так шта мой С++ вариант будет соптимизирован лучше.


S>Внезапно значительная часть ссылок оказывается non-nullable.


Какое открытие! ))


S>А nullable reference нужны не чаще чем, скажем, Nullable<int>. Как-то же работает C# с int? безо всяких IoC и коллбеков. Удивительно, да?


Не работает, RTFM! ))
Выбрасывает исключения.


V>>Других техник борьбы с nil, кроме диспетчеризации на манер IoC, в природе не существует, даже в Kotlin.

S>(facepalm). Тут прекрасно всё — и "даже" Котлин, как вершина развития языкостроения, и применение IoC для борьбы с nil, и диспетчеризация...
S>Жаль, что всё современное программирование прошло мимо вас.

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

ОК, дай мне пример языка, которым ты владеешь хотя бы на самом начальном уровне, где есть строгая первоклассная поддержка non-nullable ссылок.
Скорее всего, у тебя в копилке ни одного такого языка нет.
Но очередное громкое заявление про "современное программирование" было! ))

В общем, такие языки есть, но их нет в мейнстриме.
Более того, многие из них достаточно старые.


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

Посмотри, например, языки, со встроенной поддержкой зависимых типов, как там обыгрывают подобные сценарии.


V>>А фраза целиком лишь характеризует уже старого и недостаточно умного человека.

S>Забавно, что вы тут усердно опровергаете утверждение "программисты прошлого были умнее".

Хоар и был умнее.
Человеку почти 90 лет, тут не стоит манипулировать/спекулировать.


S>Видите, и Хоар вам недостаточно умён.


1. Один из распространённых приёмов демагогии.
2. Я ответил на эти спекуляции заране, зная тебя. Увы, не помогло. ))

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


S>Да, я помню, для вас и Билл Гейтс недостаточно успешен


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

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


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

S>Эта фраза показывает, что вы не понимаете сути "проблемы нулевых ссылок".

Да нет, эта фраза показывает, что ты не понимаешь зависимых типов.
Проблема же не только в null, ссылка вообще может ссылаться на мусор в памяти.
Т.е. простая проверка на не null не решает вопрос окончательно.

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


V>>И чего ж старик не упомянул эту проблему, хотя проблема в точности идентичная?

S>Надо полагать, оттого, что проблема — не в точности идентичная.
V>>Это ровно один и тот же класс ошибок, вызванных одной и той же причиной — невозможностью в compile-time выразить ВСЕ требуемые ограничения из runtime.
S>Это какой-то очень широкий класс ошибок.

Уфф...
Адрес — это индекс ячейки памяти.
Прблема невалидного адреса в точности равна проблеме невалидного индекса.

И ведет к асболютно идентичным ошибкам — к неверной реентерпретации памяти.
Я тебе в C# запросто создам управляемую ссылку на мусор в памяти (произвольный адрес, не обязательно null).

И никакое #nullable enable не спасёт.
Да и оно сейчас пока живёт как ворнинги.
И запросто обходится через !, без рантайм-проверок.

Это ты вот это всё имел ввиду под "современным программированием"? ))

В общем, в языках с зависимыми типами нет принципиальной разницы на допустимые ограничения, контроллируемые системой типов, будь это [0, 1, 2] или [0, 1..]
Там работает один и тот же механизм.

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

Например, в языках с зависимыми типами без исключений может применяться flow control,
т.е., некий uint[0..MAX_UINT] может быть приведёт к ограниченному типу uint[0..10] через простой if:
uint array[10] = ...;
uint x = readX();
func(array[x]); // ошибка компиляции

if(x < 10)
   func(array[x]); // OK, тип переменной x модифицируется контекстом предыдущих вычислений



S>Ну, то есть понятно, что в общем случае проблема — ровно в том, что статическое доказательство корректности произвольной программы сводится к проблеме останова, которая неразрешима.


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

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

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

Например, во многих языках с зависимыми типами ты не можешь прочитать массив данных из файла и передать его куда-то дальше, примерно так (псевдокод):
let array<?>(int) = readFromFile();
process(array);


Ты можешь действовать только через IoC:
readFromFile(process<N: uint>: array<N>(int) -> Void) {
    let loop<N:uint> array<N>(int) ar = {
      ...
      if(eof) 
        process(ar);  // конец работы, вызов поданного продолжения
      else
        loop(insert(ar, data))  // хвостовая рекурсия, вызов лямбды loop с новым типом ar (с новым размером)
    }

    loop array<0>(int);  // начало цикла
}


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


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


Давай не будем о нормальности.
Теория зависимых типов была разработана не с 0-ля в 70-е, а первые работы на эту тему были еще в 1925-м, задолго до первых компьютеров.
Не надо считать всех идиотами. ))

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


S>В частности, "проблема" нулевой ссылки легко статически разрешима на более-менее любой современной платформе.


Если ты про C#, то анекдот хороший.


S>Даже настольные языки, собранные на коленке энтузиастами, прекрасно обходятся без нулевых ссылок.


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

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

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


S>Кстати, вопросы индексов в массивах давно закрыты: https://www.cs.cmu.edu/~fp/papers/pldi98dml.pdf. Так то про "невозможность в компайл-тайм" — это лично ваши заблуждения. Развивайтесь, читайте.


— Ты куда, в баню?
— Да нет, в баню!


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

И статью ты ниасилил, иначе бы не сверкал невежеством тут:

S>IoC и функциональные языки соотносятся примерно никак.

V>>В точности проблема нулевых ссылок повторяется в массивах, к которым обращаются по индексу.
S>Эта фраза показывает, что вы не понимаете сути "проблемы нулевых ссылок".


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

Ты обратил по ссылке внимание на сам принцип написания программ?
Это другой принцип проектирования.

Показан один из беднейших инструментов реализации ЗТ — хвостовая рекурсия, каждый раз вызывается локальная ламбда с новым типом аргументов.
И вот как раз конечный результат вычислений можено будет подать куда-нибудь далее в вычислениях поданному как аргумент функциональному объекту, потому-то и IoC, что список неизвестного размера нельзя вернуть из ф-ии. ))
Можно только вызывать другую ф-ию в типизированном контексте.


V>>(в языках, которые претендуют на хоть какую-то эффективность)

S>Эта фраза тоже выдаёт непонимание сути проблемы. Как раз неэффективное решение проблемы и состоит в переносе проверок в ран-тайм.

Проверки в рантайм всё-равно есть, вопрос в том — сколько их.
Ведь достаточно проверить один раз (или достоверно получить валидное значение по new) и далее распространять значение уже с признаком валидности.

Насчёт "непонимания сути" — опять улыбнуло.
Это ты в своём C# не понимаешь сути, потому что нет алиасов типов, невозможно отсутствие конструктора структуры без параметров.
Поэтому ср-вами языка проблему не решить — нужен встроенный костыль.

А я тебе выше показал примеры на C++, которую столь узкую постановку вопроса решают на раз-два.
Причём, с нулевым оверхедом, в сравнении с обычными указателями.
И без переделки исходников, т.к. Optional<T*> и NotNull<T> — это умные указатели, с переопределёнными operator-> и operator*, т.е. их можно использовать там, где ожидался обычный указатель, только теперь можно распространять non-nullable указатели без лишних проверок.


S>Любое компайл-тайм решение получается более эффективным, как только время ожидаемой работы программы становится достаточно большим.


Увы, увы.
Программы, написанные в этом стиле, как по ссылке, построены таким образом, что в функции всегда передаются другие функции-"продолжения".
Т.е. вся работа основной программы — это бесконечный вызов ф-ий из ф-ий.
Но стек ведь не бесконечен? Отсюда монады и ленивость.
То бишь, "энергичный" вызов ф-ий заменяется динамически выстроенным графом продолжений, где вычисления передаются динамически же вычисленным в процессе работы программы веткам графа через явные if или неявную дистептчеризацию, на манер Хаскеля.
То бишь, никакого call не происходит, вычислительная модель языка в ленивой манере протягивает монаду процесса/потока по этому графу вычислений.

То бишь, вычисления выглядят в рантайме так:
func1 -> result1 -> func2 -> result2 -> func3 -> ...

И до чудес быстродействия там как до звёзд.


V>>И до изобретения исключений, без техники IoC, т.е. без функциональных ср-в в языке, ошибок такого рода в процедурных языках избежать было нельзя, можно было лишь сгенерировать проверочный код компилятором (...) и аварийно завершить программу, если проверка на индекс или nil была неудачной.

S>И опять вы складываете в одну кучу рантайм и компайл-тайм проверки. Это вы мухлюете или вправду не видите разницы?

Это ты не понял прочитанного. ))
Медитируй до просветления, плиз.


V>>Разумеется, новое дыхание в конце 90-х и начале 2000-х получили теории языков.

S>Вот как раз тут прямо таки нового появилось не очень много.
V>>Без изобретения нового.
S>Воот! В основном то, что мы наблюдаем — приезд в мейнстрим идей и концепций из 1960х. Так что "теории языков" вычёркиваем.

В 70-х только начали классифицировать типизированные лямбда-исчисления.
Классификация была нужна для понимания (1) необходимого и достаточного набора конструктов языка для соответствия выранным критериям и (2) для понимания необходимых техник программирования в данном классе ограничений, см лямбда куб (наглядное представление классификации).

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

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

Сегодняшние столь же "академические" языки в мейнстриме — это Golang, Dart, Хаскель.
И то, мейнстрим весьма условный. ))

F# (OCaml), Scala, Kotlin — уже нет.

C# — совсем нет.
В рамках выбранной концепции он далеко не полон, не обладает всеми необходимыми выразительными св-вами.
Собсно, поэтому развитие языка запросто идёт дальше при сохранении бинарного формата сборок еще аж со времён 2-го дотнета.
Блин, указатели на ф-ии только-только ввели.
Через stackalloc стало можно размещать не только примитивные целочисленные типы вот только недавно.
И т.д. и т.п.


V>>Я когда-то уже высказывался на эти темы ~12 лет назад в ответ молодому и горячему в те года Вольфхануду:

V>>http://www.rsdn.org/forum/philosophy/4247637.1
S>Ну, так и зачем самому себе противоречить?

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

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

Как тебе задача — выделить из данной цепочки символов всевозможные подцепочки максимальной длины, встречающиеся более одного раза.
Оцени сложность в терминах O.
Умножь на многие мегабайты размеров современных программ.
Это всего лишь одна из подзадач в процессе оптимизации — склейка самоповторов после стирания типов на одной из стадий оптимизации.
Сначала над типами работает бета-редукция и генерирование уникального кода из генерик-представления.
(А чуть ли не весь код на Хаскель — это сплошные генерики в терминах C#)