Не поминайте всуе PL/1 (ссылка на статью)


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

2023-08-20 kt

Читаю заметку "Вышел язык программирования Go 1.21: что нового и хорошего появилось?" https://habr.com/ru/companies/ru_mts/articles/755580/

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

Как любят писать в комментариях: "это все что вам нужно знать о прогрессе в языках программирования"

2023-08-23 veector

ИМХО, такие функции не должны встраиваться в язык. Ибо такими темпами, со временем все будете стараться встроить в язык.

2023-08-24 kt

Как раз, опыт PL/1 и показывает, что если думать при создании языка, что должно быть встроенным, то «такие темпы» стремятся к нулю. За десятилетия эксплуатации компилятора PL/1-KT я добавил именно от себя только встроенную функцию cossin, поскольку FPU в х86 может выдавать сразу и косинус и синус. Поэтому очень жаль было терять такую аппаратную возможность в языке.
Да и в обновленном PL/1 от IBM мало чего добавилось за 40 лет. Сходу могу вспомнить только функцию TALLY и разные мелочи.

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

2023-08-24 Автор сайта

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

Должны ли в язык встраиваться функции типа min и max — вопрос дискуссионный. С одной стороны, вынос функций в библиотеки лучше структурирует язык. С другой, если в языке есть целые числа и операции над ними, то почему встроенные операции иметь можно, а встроенные функции нельзя? Почему можно складывать, вычитать, умножать и делить без подключения библиотек, а вот найти максимум и минимум нет? Нелогично.

2023-08-30 veector

Автор сайта:
Почему можно складывать, вычитать, умножать и делить без подключения библиотек, а вот найти максимум и минимум нет? Нелогично.
ИМХО, это как раз просто и логично. Минимум и максимум не встроены в язык, потому что их можно сделать, используя возможности языка (компилятора языка). А вот если бы, эти функции нельзя было сделать средствами компилятора языка, тогда функция имеет право быть добавленной в сам язык.

Обратите внимание на cossin, про которую написал kt чуть выше. Т.к. компилятор языка, который он использует, скорее-всего не позволяет ему средствами языка сделать вычисление сразу косинуса и синуса с помощью FPU х86, то ему пришлось это встроить в язык (ибо другого варианта нет). Поэтому, что бы не кроить компилятор язык под разные аппаратные вычислители, в языках есть возможность вставить "ассемблерные вставки", т.е. код, понятный конкретному железу на языке, приближенному к железу. Ведь язык может использоваться не только для x86 железа, плюс, даже x86 железо может меняться и обрастать новыми командами и вычислительными блоками. Только представьте, что "завтра" у вас появится команда процессора вычисляющая min и max аппаратно за одну команду!

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

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

2023-08-30 Автор сайта

Пожалуй, Вы правы. И возразить нечего.

2023-08-31 kt

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

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

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

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

...

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

Разумеется, когда мы используем, например, DirectX, нам нужны библиотеки, но это уже совсем другая история.

2023-09-06 alextretyak

встроенную функцию cossin, поскольку FPU в х86 может выдавать сразу и косинус и синус. Поэтому очень жаль было терять такую аппаратную возможность в языке.
Помнится лет 20 назад я познакомился с Intel C++ Compiler. И уже тогда он умел заменять рядом стоящие вызовы функций sin() и cos() от одинакового аргумента на одну инструкцию fsincos.
Также нечто подобное делает GCC — заменяет вызовы sin() и cos() на один вызов Unix-овой функции sincos(). [Вот пример кода, иллюстрирующий такую оптимизацию.]

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

[И кстати, есть ещё одна аналогичная оптимизация в GCC: замена выражения (value << shift) | (value >> (32 − shift)) одной инструкцией rol, осуществляющей циклический сдвиг value влево на shift бит (https://godbolt.org/z/rjzqc3Wh7).]

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

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

Должны ли в язык встраиваться функции типа min и max — вопрос дискуссионный.
Я считаю, что ответить на этот вопрос можно анализом частоты использования этих функций при решении задач, на которые ориентирован язык программирования [т.е. которые предполагается решать на этом языке]. Редко-используемые функции можно вынести в сторонние библиотеки, а часто-используемые — включить в стандартную библиотеку языка (либо встроить в язык без необходимости что-то подключать, как например функции abs() и round() в Python доступны без подключения встроенного модуля math).

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

2023-09-07 Автор сайта

замена выражения (value << shift) | (value >> (32 − shift)) одной инструкцией rol, осуществляющей циклический сдвиг value влево на shift бит
В языке D наряду с обычными сдвигами << и >> есть сдвиги циклические <<< и >>>, которым соответствует единственная машинная операция.

Редко используемые функции можно вынести в сторонние библиотеки, а часто-используемые — включить в стандартную библиотеку языка (либо встроить в язык без необходимости что-то подключать, как например функции abs() и round() в Python доступны без подключения встроенного модуля math).
Так один человек решает одни задачи, а другой другие. Если проблему выявления частоты использования функций выявлять статистически, то нужна широкая выборка.

2023-09-09 alextretyak

В языке D наряду с обычными сдвигами << и >> есть сдвиги циклические <<< и >>>, которым соответствует единственная машинная операция.
Возможно, так было когда-то, либо кто-то предлагал такие операторы, но на данный момент в D нет операторов для циклических сдвигов.
Вот цитата из документации D:
>>> означает беззнаковый (т.е. логический) сдвиг также в Java, C# и других языках.
И насколько мне известно, операторов для циклических сдвигов нет ни в одном языке программирования. Лично я думал над тем, чтобы добавить такие операторы: (<<) и (>>), т.е. чтобы v (<<) n означало циклический сдвиг v влево на n бит, но т.к. требуются они крайне редко, то решил оставить только встроенные функции rotl и rotr.

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