Обновить

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

"Забытый” — это сильное преувеличение. Скорее, Perl перешёл из мейнстрима в нишевый инструмент для конкретных задач. Если 15 лет назад для задач на HP-UX на PA-RISC ты выбрал Perl и теперь у тебя куча легаси, он всё ещё твой лучший друг! Без проблем перенесёшь на любую современную платформу, сэкономив немало сил и средств.

Куча критической инфраструктуры (банки, заводы, энергетика) построена на этом "железе". Можно переписать на Python, но это X-Y месяцев работы команды, тесты, риски. А старый Perl-скрипт просто работает. И теперь твоё мудрое, принятое 15 лет назад решение, экономит компании миллионы.

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

Хотя ИИ теперь есть

Перл очень простой язык. Если человек не способен его изучить и писать на нём, у меня возникает непонимание как вообще в ит попал такой человек. Он сильно проще той же жабы.

В том то и дело, что писать просто. Читать чужой код уже сложнее )

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

бейсик простой язык и паскаль, слабо вам прям сейчас взять проект на полмиллиона строк кода на паскале (не object) и поддерживать? язык то простой! проще жабы!

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

Паскаль, а еще лучше Дельфя

ага, конечно лучше, ктобы сомневался, но Делфя сложнее для освоения, давайте уж Паскаль будем рассматривать, он же проще ;)

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

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

p.s. я знаю что в перле есть ООП, я про другое сейчас

Даже незнаю какой версией пользовался TurboPascal. ООП добавили примерно в 1989 году, но я тогда его не понимал совсем. Писла в школе для друзей утилиты DOSовские для работы с дисками и всякой аппаратурой по ком порту. Самый большой проект который переделывал, какая-то файловая оболочка, 2х панельный менеджер. Встроеный ассемблер использовал. Помню что там строки безпасные, без нуль терминаторов. Енумы, запаписи и указатели строгие, не дают в ногу стрелять. Компилируется быстро, каких-то косяков не помню. Единственно много текста ввдодить, нет фигурных скобок для блоков. Еще С++ тогда считался хакерским, а Паскаль не круто было.

В перле можно писать в ООП стиле, никаких проблем.

Паскаль отличается своей многослойностью, а так норм язык.

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

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

Чем? процедурным кодом на полмиллиона строк потому что вы двухпанельным менеджером и текстовым редактором пользуетесь?

Разговор был в начале о том что перл простой, его любой выучит

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

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

а в случае с Перлом это почти про все проекты можно сказать уже, но язык при этом не помогает

ну если быть до конца честным, то надо прямо сказать что очень мало программистов может через год разобрать то что написал на любом ЯП. особенно если писал без ТЗ и документации. Что хорошо в perl а так же в java, это автодокументация, кстати в данной статье есть её пример в коде, ну и утилитка perldoc или javadoc в помощь ;)

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

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

Они оба были написаны на питоне, первый очень шакально но очень прямолинейно и хоть с какойто попыткой в архитектуру (хоть извращенную но всётаки), второй в черезчур в Java-стиле

мы без проблем всем отделом (4 разраба бэка) за полгода оба раскурили, отрефачили и вывели в прод

Забавный был опыт

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

==

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

Позволяет. Поддерживали. А Java не просто так в энтерпрайзе поселилась, а потому что её активно рекламировали и предназначалась она на замену C++ как более простой язык. И то сказать, уже более десяти лет ходит шутка про новый стандарты плюсов:

это компилируется C++11 Дальше будет только хуже
это компилируется C++11 Дальше будет только хуже

…и знаете, Перл гораздо читабельнее вот этого!

Так двухпанельники или командную строку? Истинные адепты командной строки презирают nc-clones.

Я не настолько старый ) и речь про языки.

emacs - выбор мастеров! ;)

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

emacs - выбор мастеров! ;)

Угу, но dired полноценно не освоил, хотя там по сути весь функционал nc-клонов.

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

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

для какой-то операции с файлами чуть сложнее cp или mv они используют "стандартный файловый менеджер"

Это молодёжь какая то. Я скорее про тех, кто юниксовым шеллом пользуется со времён СМ-4.

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

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

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

У меня дома где то с 1997ого, но всё таки досовские привычки победить не удалось )

выполнять без мыши 

Есть ещё альтернативная религия - Plan 9 - где, наоборот, вместе с командной строкой очень широко используется мышь, все три кнопки нужны )

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

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

И на удивление часто из редакторов только vi.

Это база для сисадмина.

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

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

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

Проблема с перлом, что в нем есть неинтуитивные странности, вплоть до такого шухера что глобальные переменные $a и $b зарезервированы для сортировки. Ну и аргументы $1 $2 $3 нужно все время переназывать

В любом практическом языке есть куча неинтуитвных странностей. Например, в Python - изучал его летом, с некоторой дичи просто остолбеневал. А зачем переназывать $1 $2 $3, если им сразу в регулярке можно дать человеческие имена?

Что вы имеете в виду? С моей точки зрения перловская передача параметров выглядит криво:
sub f {
my ($a, $b, $c) = @_;

  1. Так это не $1 $2, а $_[1] $_[2] - совсем разные вещи! Ибо $1 $2 только в матчинге регэкспов, по большому счету (мы ж не в шелле). Ну и да, $_[1] будет только в каких-нибудь магических обертках, в обычных функциях назовут именами.

  2. Для тупых не умеющих абстрагироваться от привычек (см. ниже, и вообще привычки это плохо) из других языков - с 5.36 по умолчанию, а до того под “use feature ‘signatures’” доступен синтаксис вида

           sub foo ($left, $right = 0) {
               return $left + $right;
           }
  1. Неа, это не криво, это УДОБНО. Это полный контроль над передаваемыми аргументами (чем-то напоминает Erlang), то есть можно вместо идиотизмов типа “перегрузка функций” обработать всё в одном месте: например, позволить субе быть как статической функцией, так и методом, принимать после обязательных параметров опциональный хэш в виде перечня key-value pairs, после которого опять же снова может быть что-то опциональное (которое мы просто проверим по типу концевых элементов, если они есть). То есть принимаем список и возвращаем список, наивысшая абстракция в стиле Lisp. Поэтому опытные перловики предпочитают приучиться к этому “старому” стилю, а не использовать сигнатуры “потому что стало можно”.

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

Чего?.. Вот уж про сигнатуры никогда проблем не слышал, как они могли “вбить гвоздь в крышку гроба”.

Дайте дипсеку промпт "Язык perl. Как сигнатуры - параметры функций - могут вызвать неоднозначность понимания" и несколько раз прогоните. Он десятки проблем покажет. Разные проблемы в разных повторах. Конфликты с другими стандартными вариантами, несовпадения в разных версиях, похожесть на самодельные сигнатуры - кучи и кучи потенциальных проблем.

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

там несколько страниц примеров. Проще всё же спросить нейронку.
Сигнатуры например есть в Mojolicious . Куда уж популярней.

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

А в чем проблема? Всего лишь полмиллиона и не дельфёв, убежавших вперёд со времен моей юности, а на замороженном Паскале. Я вот работал на импортозамещении биллинга опсоса, 10 миллионов строк, из них миллион на COBOL, вот это было куда веселее!

Это не так, синтаксис basic, pascal очень простой и понятный, как и JavaScript классический, именно поэтому на этих языках раньше и начинали обучение программированию.

С++, rust тупо не понять, если не знаешь синтаксиса

Давайте по другому пример приведу

Язык 1С, там всё очень просто, даже блин по русски, синтаксис, операторы, там ПРЕДЕЛЬНО простые.

А потом откроем код большого проекта на нем написанного и попробуем разобраться.

==

еще раз, простота языка != простота разработки крупных проектов на нем

Язык не плохой. Но только без модных фреймворков)

А что такое “модные” ? Свежие? Их есть (Beekeper хоть). Популярные среди разработчиков на данном языке? Их тоже есть, Mojolicious тот же (который потом портировали на JavaScript кстати).

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

Вот да, Mojolicious отличный пример. Сколько версий, столько и несовместимостей. Да, он чудесен и удобен. Но не через 10 лет.

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

код на нём выглядит как что‑то между Python, C, и чем‑то своим

А ничего, что Перл появился когда Питона ещё в планах не было?

Да, я бы скорее awk среди подобных упомянул.

Собственно, Ларри Уолл создал Perl именно по причине того, что ему стало не хватать возможностей grep/sed/awk при работе с текстовой информацией.

Ну так написано же не "стиль создавался на основе Python", а просто сравнили. Почему бы и нет?

Ну так и не похоже ни разу. Во первых Python вполне читабельный, во вторых там идеологически "There should be one-- and preferably only one --obvious way to do it", что чётко противоречит первому примеру с perl.

Начинал свою карьеру на нём, делали сайты. Язык просто one love

cat "test... test... test..." | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y; -/:-@[-`{-};`-{/" -;;s;;$_;see'

cat /dev/random | perl # Мне повезёт

Господи, что это? :)

Патч Бармина :)

Парсить плюсовый код... А вы смелый

В чём перлу нет равных, так это Code golf (контесты на самый короткий код). Смотришь на результат победителя и замираешь в немом изумлении

Не только на самый короткий, но так же и самый запутанный, или просто визуально красивый. Классический пример - код, печатающий стихотворение "99 bottles of beer on the wall". Ключ -Mre=eval нужен для разрешения исполнения кода, внедренного в регулярные выражения, что в современных версиях perl по умолчанию отключено из соображений безопасности. Раньше он не требовался.

$ perl -Mre=eval
    ''=~(        '(?{'        .('`'        |'%')        .('['        ^'-')
    .('`'        |'!')        .('`'        |',')        .'"'.        '\\$'
    .'=='        .('['        ^'+')        .('`'        |'/')        .('['
    ^'+')        .'||'        .(';'        &'=')        .(';'        &'=')
    .';-'        .'-'.        '\\$'        .'=;'        .('['        ^'(')
    .('['        ^'.')        .('`'        |'"')        .('!'        ^'+')
   .'_\\{'      .'(\\$'      .';=('.      '\\$=|'      ."\|".(      '`'^'.'
  ).(('`')|    '/').').'    .'\\"'.+(    '{'^'[').    ('`'|'"')    .('`'|'/'
 ).('['^'/')  .('['^'/').  ('`'|',').(  '`'|('%')).  '\\".\\"'.(  '['^('(')).
 '\\"'.('['^  '#').'!!--'  .'\\$=.\\"'  .('{'^'[').  ('`'|'/').(  '`'|"\&").(
 '{'^"\[").(  '`'|"\"").(  '`'|"\%").(  '`'|"\%").(  '['^(')')).  '\\").\\"'.
 ('{'^'[').(  '`'|"\/").(  '`'|"\.").(  '{'^"\[").(  '['^"\/").(  '`'|"\(").(
 '`'|"\%").(  '{'^"\[").(  '['^"\,").(  '`'|"\!").(  '`'|"\,").(  '`'|(',')).
 '\\"\\}'.+(  '['^"\+").(  '['^"\)").(  '`'|"\)").(  '`'|"\.").(  '['^('/')).
 '+_,\\",'.(  '{'^('[')).  ('\\$;!').(  '!'^"\+").(  '{'^"\/").(  '`'|"\!").(
 '`'|"\+").(  '`'|"\%").(  '{'^"\[").(  '`'|"\/").(  '`'|"\.").(  '`'|"\%").(
 '{'^"\[").(  '`'|"\$").(  '`'|"\/").(  '['^"\,").(  '`'|('.')).  ','.(('{')^
 '[').("\["^  '+').("\`"|  '!').("\["^  '(').("\["^  '(').("\{"^  '[').("\`"|
 ')').("\["^  '/').("\{"^  '[').("\`"|  '!').("\["^  ')').("\`"|  '/').("\["^
 '.').("\`"|  '.').("\`"|  '$')."\,".(  '!'^('+')).  '\\",_,\\"'  .'!'.("\!"^
 '+').("\!"^  '+').'\\"'.  ('['^',').(  '`'|"\(").(  '`'|"\)").(  '`'|"\,").(
 '`'|('%')).  '++\\$="})'  );$:=('.')^  '~';$~='@'|  '(';$^=')'^  '[';$/='`';

Почитать о том, как был создан этот шедевр, можно здесь

А создатель языка Larry Wall был неоднократным победителем конкурсов IOCCC, пример его кода - https://github.com/ioccc-src/winner/blob/master/1986/wall/wall.c

Обалдеть - это нереально круто

На языке Perl пишут целые новеллы, вот к примеру Black Perl:

BEFOREHAND: close door, each window & exit; wait until time.
    open spellbook, study, read (scan, select, tell us);
write it, print the hex while each watches,
    reverse its length, write again;
    kill spiders, pop them, chop, split, kill them.
        unlink arms, shift, wait & listen (listening, wait),
sort the flock (then, warn the "goats" & kill the "sheep");
    kill them, dump qualms, shift moralities,
    values aside, each one;
        die sheep! die to reverse the system
        you accept (reject, respect);
next step,
    kill the next sacrifice, each sacrifice,
    wait, redo ritual until "all the spirits are pleased";
    do it ("as they say").
do it(*everyone***must***participate***in***forbidden**s*e*x*).
return last victim; package body;
    exit crypt (time, times & "half a time") & close it,
    select (quickly) & warn your next victim;
AFTERWORDS: tell nobody.
    wait, wait until time;
    wait until next year, next decade;
        sleep, sleep, die yourself,
        die at last

Не зря Лэрри Уол был лингвистом.

Он ведь ещё и верующий и поэтому в Perl к примеру есть функция bless и в Raku мажорные версии называются "Апокалипсисами". Лэрри Уол вообще крайне забавный, шутливый, интересный и весёлый человек)

Спасибо, не знал о таком (хотя на Perl немного программирую уже четверть века).

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

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

И даже зная результат, читать его интервью интересно и интересно посмотреть что же в perl6 получилось.

Помнится я выходной себе заработал, у нас был спор с начальником, что будет быстрее парсить файлы его поделка на sed или моя на Перл. Моя поделка оказалась быстрее :)

Помнится я выходной себе заработал, у нас был спор с начальником, что будет быстрее парсить файлы его поделка на sed или моя на Перл. Моя поделка оказалась быстрее :)

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

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

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

Если скачать исходники Perl и скомпилировать, то в при компиляции будет создана miniperl - облегченная версия интерпретатора Perl. Сама она используется для дальнейшей сборки Perl. Это всего один исполняемый файл, который весит всего пару мегабайт!

Если компилировать в Windows с помощью древнего Windows Server 2003 R2 SDK, то получите файл miniperl.exe, который будет слинкован с древней версией msvcrt.dll и будет работать в любой версии Windows, начиная с XP без всяких дополнительных runtime библиотек.

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

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

"Век живи, век учисть", сказал поручик. Возьмем на вооружение.

Ещё как вариант - busybox, который есть и под винду. Там grep/sed/awk, для мелких задач хватит. Perl хорош, когда пользуешься постоянно - иначе забываются специфические вещи типа контекстов и писать тяжело. А по awk и вспоминать особо нечего, если что по мануалу за несколько минут можно весь язык в памяти обновить )

Под винду (во времена до WSL2) было удобно ставить git-bash - сразу не только grep/sed/awk, но и perl и vim (не говоря уже о собственно гите).

sudo cpanm MODULE

У меня в системе (FreeBSD) нет никакого cpanm. Использую классический вариант установки модулей:

sudo perl -MCPAN -e 'install SomeModuleName'

Надо заметить, что в отличии от многих популярных ныне языков программирования, CPAN - это архив с исходными кодами, а не репозиторий готовых пакетов. При выполнении команды install будет вызвана система сборки, которая создаст Makefile и запустит компиляцию C/C++ кода (если он присутствует в модуле), а результирующая библиотека (.so файл) будет установлена в дерево каталогов данной версии интерпретатора Perl. Но бывают и модули написанные чисто на Perl, они устанавливаются без компиляции.

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

На данный момент архив CPAN содержит более 220 000 модулей на все случаи жизни.

Абсолютно легко добавить cpanm во фрю, ведь это апп-модуль App::cpanminus ;-)

Абсолютно легко добавить cpanm во фрю

Можно, но зачем ? ;)

Зачем -MCPAN, если можно cpan -I -i ? И установить local::lib конечно.

Этот скрипт cpan помимо local::lib имеет еще зависимости:

use App::Cpan;
use CPAN::Version;

Зачем, если можно без них и встроенными средствами ?

Зачем страдать “встроенными”, если можно проще? Вся мощь что перла, что фряхи - в легкой инсталляции нужных сторонних пакетов.

Зависимости следует искоренять! (с) мой.

Хаха, и что вместо? Статически линковать всё в один огромный бинарь, как делают в Go или Rust? Спасибо, но нет, юниксы от этой глупости ушли еще более четверти века назад.

Хаха, и что вместо? Статически линковать всё в один огромный бинарь,

В нынешних условиях это вполне себе отличное решение. И бинарь нифига не огромный получается.

Не огромный? Точно? Я вспоминаю Telegram Desktop на пару гигабайт в отладочной версии… щас уже наверняка куда больше.

Нет, не отличное это решение, а говно от кукловодов для идиотов.

А без дебага сколько ? Прошу цифры в студию.

-rwxr-xr-x 1 root wheel 233M 16 апр. 19:45 /usr/local/bin/Telegram

Что всё равно ОЧЕНЬ много.

А после strip /usr/local/bin/Telegram?

Покажите пожалуйста вывод ldd /usr/local/bin/Telegram и readelf -a /usr/local/bin/Telegram. Чего-то лишнего туда насовато.

PS: У меня Firefox вместе со своим Gecko меньше занимает:

rz@butterfly:~ % ll /usr/local/lib/firefox/
total 254132
-rw-r--r--  1 root  wheel        480 Mar 25 12:36 application.ini
drwxr-xr-x  3 root  wheel        512 Apr 10 00:01 browser/
drwxr-xr-x  3 root  wheel        512 Mar 13  2022 defaults/
-rw-r--r--  1 root  wheel         87 Mar 25 15:46 dependentlibs.list
-rwxr-xr-x  1 root  wheel     654200 Mar 25 15:47 firefox*
-rwxr-xr-x  1 root  wheel     654200 Mar 25 15:47 firefox-bin*
drwxr-xr-x  2 root  wheel        512 Apr 10 00:01 fonts/
-rwxr-xr-x  1 root  wheel      35000 Mar 25 15:44 glxtest*
drwxr-xr-x  3 root  wheel        512 Sep 10  2025 gmp-clearkey/
-rwxr-xr-x  1 root  wheel   10085368 Mar 25 15:19 libgkcodecs.so*
-rwxr-xr-x  1 root  wheel     207576 Mar 25 15:45 liblgpllibs.so*
-rwxr-xr-x  1 root  wheel    5661552 Mar 25 15:45 libmozavcodec.so*
-rwxr-xr-x  1 root  wheel     806840 Mar 25 15:45 libmozavutil.so*
-rwxr-xr-x  1 root  wheel       9144 Mar 25 15:43 libmozgtk.so*
-rwxr-xr-x  1 root  wheel    1777504 Mar 25 15:19 libmozsqlite3.so*
-rwxr-xr-x  1 root  wheel      22600 Mar 25 15:43 libmozwayland.so*
-rwxr-xr-x  1 root  wheel  201539288 Mar 25 15:45 libxul.so*
-rw-r--r--  1 root  wheel   37564540 Mar 25 15:48 omni.ja
-rwxr-xr-x  1 root  wheel     659272 Mar 25 15:44 pingsender*
-rw-r--r--  1 root  wheel        102 Mar 25 15:46 platform.ini
-rw-r--r--  1 root  wheel          0 Mar 25 15:48 removed-files
-rwxr-xr-x  1 root  wheel      33688 Mar 25 15:44 vaapitest*

Так он уже stripped! И не статический, в том-то и мой поинт - если б ЭТО еще и статическим было, при критикуемом мной подходе Go/Rust, размеры были бы вообще невообразимые! Полный readelf не покажу, он по размерам сюда не влезет просто. Да, часть его размеров - это встроенные картинки, но они особо не менялись со времен, когда он менее 100 Мб занимал. Сейчас же в нём еще и браузер есть на webkit-gtk (правда мне лень рыться в выводе ниже, влинкован или как .so)/

$ file /usr/local/bin/Telegram 
/usr/local/bin/Telegram: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 13.5, FreeBSD-style, stripped
$ ldd /usr/local/bin/Telegram
/usr/local/bin/Telegram:
        libBlocksRuntime.so.0 => /usr/lib/libBlocksRuntime.so.0 (0x2239f9df0000)
        libminizip.so.1 => /usr/local/lib/libminizip.so.1 (0x2239fa294000)
        librnnoise.so.0 => /usr/local/lib/librnnoise.so.0 (0x2239fbc90000)
        libopenal.so.1 => /usr/local/lib/libopenal.so.1 (0x2239fa701000)
        libprotobuf-lite.so.29.6.0 => /usr/local/lib/libprotobuf-lite.so.29.6.0 (0x2239fab44000)
        libabsl_strings.so.2501.0.0 => /usr/local/lib/libabsl_strings.so.2501.0.0 (0x2239fb4b5000)
        libabsl_throw_delegate.so.2501.0.0 => /usr/local/lib/libabsl_throw_delegate.so.2501.0.0 (0x2239fbf1d000)
        libhunspell-1.7.so.0 => /usr/local/lib/libhunspell-1.7.so.0 (0x2239fc667000)
        libavfilter.so.11 => /usr/local/lib/libavfilter.so.11 (0x2239fe19e000)
        libpipewire-0.3.so.0 => /usr/local/lib/libpipewire-0.3.so.0 (0x2239fd194000)
        libssl.so.111 => /usr/lib/libssl.so.111 (0x2239ff57e000)
        libavformat.so.62 => /usr/local/lib/libavformat.so.62 (0x223a00ce8000)
        libavcodec.so.62 => /usr/local/lib/libavcodec.so.62 (0x223a04000000)
        libswresample.so.6 => /usr/local/lib/libswresample.so.6 (0x223a004db000)
        libswscale.so.9 => /usr/local/lib/libswscale.so.9 (0x223a01c02000)
        libavutil.so.60 => /usr/local/lib/libavutil.so.60 (0x223a031dd000)
        libopus.so.0 => /usr/local/lib/libopus.so.0 (0x223a07a00000)
        libopenh264.so.8 => /usr/local/lib/libopenh264.so.8 (0x223a025a3000)
        libsrtp2.so.1 => /usr/local/lib/libsrtp2.so.1 (0x223a05d7b000)
        libvpx.so.12 => /usr/local/lib/libvpx.so.12 (0x223a062a6000)
        libm.so.5 => /lib/libm.so.5 (0x223a070e9000)
        libcrc32c.so.1 => /usr/local/lib/libcrc32c.so.1 (0x223a08ad5000)
        libjpeg.so.8 => /usr/local/lib/libjpeg.so.8 (0x223a09ca7000)
        libXcomposite.so.1 => /usr/local/lib/libXcomposite.so.1 (0x223a08f2f000)
        libXdamage.so.1 => /usr/local/lib/libXdamage.so.1 (0x223a0a626000)
        libXrandr.so.2 => /usr/local/lib/libXrandr.so.2 (0x223a0b4ed000)
        libXtst.so.6 => /usr/local/lib/libXtst.so.6 (0x223a0b99b000)
        libXext.so.6 => /usr/local/lib/libXext.so.6 (0x223a0c30a000)
        libXfixes.so.3 => /usr/local/lib/libXfixes.so.3 (0x223a0d06f000)
        libX11.so.6 => /usr/local/lib/libX11.so.6 (0x223a0e546000)
        liblz4.so.1 => /usr/local/lib/liblz4.so.1 (0x223a0d53c000)
        libada.so.3 => /usr/local/lib/libada.so.3 (0x223a0eb01000)
        libz.so.6 => /lib/libz.so.6 (0x223a0f701000)
        libcrypto.so.111 => /lib/libcrypto.so.111 (0x223a109d4000)
        libdispatch.so.1 => /usr/local/lib/libdispatch.so.1 (0x223a1067c000)
        libKF6CoreAddons.so.6 => /usr/local/lib/libKF6CoreAddons.so.6 (0x223a110d5000)
        libxxhash.so.0 => /usr/local/lib/libxxhash.so.0 (0x223a1256c000)
        libxcb-keysyms.so.1 => /usr/local/lib/libxcb-keysyms.so.1 (0x223a11909000)
        libxcb.so.1 => /usr/local/lib/libxcb.so.1 (0x223a12ca7000)
        libxcb-record.so.0 => /usr/local/lib/libxcb-record.so.0 (0x223a12d2e000)
        libxcb-screensaver.so.0 => /usr/local/lib/libxcb-screensaver.so.0 (0x223a12d89000)
        libqrcodegencpp.so.1 => /usr/local/lib/libqrcodegencpp.so.1 (0x223a14a65000)
        libQt6Svg.so.6 => /usr/local/lib/qt6/libQt6Svg.so.6 (0x223a133aa000)
        libQt6OpenGLWidgets.so.6 => /usr/local/lib/qt6/libQt6OpenGLWidgets.so.6 (0x223a141fa000)
        libQt6QuickWidgets.so.6 => /usr/local/lib/qt6/libQt6QuickWidgets.so.6 (0x223a1649b000)
        libQt6Widgets.so.6 => /usr/local/lib/qt6/libQt6Widgets.so.6 (0x223a18a00000)
        libQt6WaylandCompositor.so.6 => /usr/local/lib/qt6/libQt6WaylandCompositor.so.6 (0x223a14aa9000)
        libQt6Quick.so.6 => /usr/local/lib/qt6/libQt6Quick.so.6 (0x223a19a00000)
        libQt6OpenGL.so.6 => /usr/local/lib/qt6/libQt6OpenGL.so.6 (0x223a15bb7000)
        libQt6Gui.so.6 => /usr/local/lib/qt6/libQt6Gui.so.6 (0x223a1c000000)
        libQt6Qml.so.6 => /usr/local/lib/qt6/libQt6Qml.so.6 (0x223a174a0000)
        libQt6Network.so.6 => /usr/local/lib/qt6/libQt6Network.so.6 (0x223a1ac15000)
        libQt6Core.so.6 => /usr/local/lib/qt6/libQt6Core.so.6 (0x223a1d200000)
        libgio-2.0.so.0 => /usr/local/lib/libgio-2.0.so.0 (0x223a1bc78000)
        libgobject-2.0.so.0 => /usr/local/lib/libgobject-2.0.so.0 (0x223a1e429000)
        libglib-2.0.so.0 => /usr/local/lib/libglib-2.0.so.0 (0x223a1fa5a000)
        libc++.so.1 => /usr/lib/libc++.so.1 (0x223a1efd2000)
        libcxxrt.so.1 => /lib/libcxxrt.so.1 (0x223a206f9000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x223a21005000)
        libthr.so.3 => /lib/libthr.so.3 (0x223a221c1000)
        libc.so.7 => /lib/libc.so.7 (0x223a22ebd000)
        libdbus-1.so.3 => /usr/local/lib/libdbus-1.so.3 (0x223a21968000)
        libabsl_die_if_null.so.2501.0.0 => /usr/local/lib/libabsl_die_if_null.so.2501.0.0 (0x223a243c4000)
        libabsl_log_initialize.so.2501.0.0 => /usr/local/lib/libabsl_log_initialize.so.2501.0.0 (0x223a24071000)
        libabsl_statusor.so.2501.0.0 => /usr/local/lib/libabsl_statusor.so.2501.0.0 (0x223a243ef000)
        libutf8_validity.so => /usr/local/lib/libutf8_validity.so (0x223a249ec000)
        libabsl_log_internal_check_op.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_check_op.so.2501.0.0 (0x223a25de3000)
        libabsl_log_internal_conditions.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_conditions.so.2501.0.0 (0x223a24b6c000)
        libabsl_log_internal_message.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_message.so.2501.0.0 (0x223a252cf000)
        libabsl_log_internal_nullguard.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_nullguard.so.2501.0.0 (0x223a26c12000)
        libabsl_examine_stack.so.2501.0.0 => /usr/local/lib/libabsl_examine_stack.so.2501.0.0 (0x223a28209000)
        libabsl_log_internal_format.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_format.so.2501.0.0 (0x223a278a8000)
        libabsl_log_internal_structured_proto.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_structured_proto.so.2501.0.0 (0x223a290be000)
        libabsl_log_internal_proto.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_proto.so.2501.0.0 (0x223a2998d000)
        libabsl_log_internal_log_sink_set.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_log_sink_set.so.2501.0.0 (0x223a2a3e9000)
        libabsl_log_sink.so.2501.0.0 => /usr/local/lib/libabsl_log_sink.so.2501.0.0 (0x223a2a926000)
        libabsl_log_entry.so.2501.0.0 => /usr/local/lib/libabsl_log_entry.so.2501.0.0 (0x223a2bc74000)
        libabsl_flags_internal.so.2501.0.0 => /usr/local/lib/libabsl_flags_internal.so.2501.0.0 (0x223a2add7000)
        libabsl_flags_marshalling.so.2501.0.0 => /usr/local/lib/libabsl_flags_marshalling.so.2501.0.0 (0x223a2c2d3000)
        libabsl_flags_reflection.so.2501.0.0 => /usr/local/lib/libabsl_flags_reflection.so.2501.0.0 (0x223a2ccf8000)
        libabsl_flags_config.so.2501.0.0 => /usr/local/lib/libabsl_flags_config.so.2501.0.0 (0x223a2d964000)
        libabsl_flags_program_name.so.2501.0.0 => /usr/local/lib/libabsl_flags_program_name.so.2501.0.0 (0x223a2eb51000)
        libabsl_flags_private_handle_accessor.so.2501.0.0 => /usr/local/lib/libabsl_flags_private_handle_accessor.so.2501.0.0 (0x223a2def1000)
        libabsl_flags_commandlineflag.so.2501.0.0 => /usr/local/lib/libabsl_flags_commandlineflag.so.2501.0.0 (0x223a2edd3000)
        libabsl_flags_commandlineflag_internal.so.2501.0.0 => /usr/local/lib/libabsl_flags_commandlineflag_internal.so.2501.0.0 (0x223a30c1a000)
        libabsl_log_globals.so.2501.0.0 => /usr/local/lib/libabsl_log_globals.so.2501.0.0 (0x223a2faef000)
        libabsl_vlog_config_internal.so.2501.0.0 => /usr/local/lib/libabsl_vlog_config_internal.so.2501.0.0 (0x223a2ff47000)
        libabsl_log_internal_fnmatch.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_fnmatch.so.2501.0.0 (0x223a3101b000)
        libabsl_log_internal_globals.so.2501.0.0 => /usr/local/lib/libabsl_log_internal_globals.so.2501.0.0 (0x223a320f5000)
        libabsl_raw_hash_set.so.2501.0.0 => /usr/local/lib/libabsl_raw_hash_set.so.2501.0.0 (0x223a31840000)
        libabsl_hash.so.2501.0.0 => /usr/local/lib/libabsl_hash.so.2501.0.0 (0x223a3230f000)
        libabsl_city.so.2501.0.0 => /usr/local/lib/libabsl_city.so.2501.0.0 (0x223a3275f000)
        libabsl_low_level_hash.so.2501.0.0 => /usr/local/lib/libabsl_low_level_hash.so.2501.0.0 (0x223a33423000)
        libabsl_hashtablez_sampler.so.2501.0.0 => /usr/local/lib/libabsl_hashtablez_sampler.so.2501.0.0 (0x223a34ab2000)
        libabsl_random_distributions.so.2501.0.0 => /usr/local/lib/libabsl_random_distributions.so.2501.0.0 (0x223a34221000)
        libabsl_random_seed_sequences.so.2501.0.0 => /usr/local/lib/libabsl_random_seed_sequences.so.2501.0.0 (0x223a351f3000)
        libabsl_random_internal_pool_urbg.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_pool_urbg.so.2501.0.0 (0x223a36661000)
        libabsl_random_internal_randen.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_randen.so.2501.0.0 (0x223a35512000)
        libabsl_random_internal_randen_hwaes.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_randen_hwaes.so.2501.0.0 (0x223a35782000)
        libabsl_random_internal_randen_hwaes_impl.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_randen_hwaes_impl.so.2501.0.0 (0x223a366fc000)
        libabsl_random_internal_randen_slow.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_randen_slow.so.2501.0.0 (0x223a36b9c000)
        libabsl_random_internal_platform.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_platform.so.2501.0.0 (0x223a37956000)
        libabsl_random_internal_seed_material.so.2501.0.0 => /usr/local/lib/libabsl_random_internal_seed_material.so.2501.0.0 (0x223a385ac000)
        libabsl_random_seed_gen_exception.so.2501.0.0 => /usr/local/lib/libabsl_random_seed_gen_exception.so.2501.0.0 (0x223a39593000)
        libabsl_status.so.2501.0.0 => /usr/local/lib/libabsl_status.so.2501.0.0 (0x223a3a2cb000)
        libabsl_cord.so.2501.0.0 => /usr/local/lib/libabsl_cord.so.2501.0.0 (0x223a3a8c6000)
        libabsl_cordz_info.so.2501.0.0 => /usr/local/lib/libabsl_cordz_info.so.2501.0.0 (0x223a3b437000)
        libabsl_cord_internal.so.2501.0.0 => /usr/local/lib/libabsl_cord_internal.so.2501.0.0 (0x223a3bf78000)
        libabsl_cordz_functions.so.2501.0.0 => /usr/local/lib/libabsl_cordz_functions.so.2501.0.0 (0x223a3c3b0000)
        libabsl_exponential_biased.so.2501.0.0 => /usr/local/lib/libabsl_exponential_biased.so.2501.0.0 (0x223a3ccea000)
        libabsl_cordz_handle.so.2501.0.0 => /usr/local/lib/libabsl_cordz_handle.so.2501.0.0 (0x223a3dee0000)
        libabsl_synchronization.so.2501.0.0 => /usr/local/lib/libabsl_synchronization.so.2501.0.0 (0x223a3d7e2000)
        libabsl_graphcycles_internal.so.2501.0.0 => /usr/local/lib/libabsl_graphcycles_internal.so.2501.0.0 (0x223a3e847000)
        libabsl_kernel_timeout_internal.so.2501.0.0 => /usr/local/lib/libabsl_kernel_timeout_internal.so.2501.0.0 (0x223a3fea9000)
        libabsl_time.so.2501.0.0 => /usr/local/lib/libabsl_time.so.2501.0.0 (0x223a3ea63000)
        libabsl_civil_time.so.2501.0.0 => /usr/local/lib/libabsl_civil_time.so.2501.0.0 (0x223a3f470000)
        libabsl_time_zone.so.2501.0.0 => /usr/local/lib/libabsl_time_zone.so.2501.0.0 (0x223a406f3000)
        libabsl_tracing_internal.so.2501.0.0 => /usr/local/lib/libabsl_tracing_internal.so.2501.0.0 (0x223a411eb000)
        libabsl_crc_cord_state.so.2501.0.0 => /usr/local/lib/libabsl_crc_cord_state.so.2501.0.0 (0x223a426be000)
        libabsl_crc32c.so.2501.0.0 => /usr/local/lib/libabsl_crc32c.so.2501.0.0 (0x223a41378000)
        libabsl_crc_internal.so.2501.0.0 => /usr/local/lib/libabsl_crc_internal.so.2501.0.0 (0x223a41885000)
        libabsl_crc_cpu_detect.so.2501.0.0 => /usr/local/lib/libabsl_crc_cpu_detect.so.2501.0.0 (0x223a42cb8000)
        libabsl_bad_optional_access.so.2501.0.0 => /usr/local/lib/libabsl_bad_optional_access.so.2501.0.0 (0x223a44c03000)
        libabsl_stacktrace.so.2501.0.0 => /usr/local/lib/libabsl_stacktrace.so.2501.0.0 (0x223a42d0c000)
        libabsl_leak_check.so.2501.0.0 => /usr/local/lib/libabsl_leak_check.so.2501.0.0 (0x223a43e05000)
        libabsl_strerror.so.2501.0.0 => /usr/local/lib/libabsl_strerror.so.2501.0.0 (0x223a45c26000)
        libabsl_symbolize.so.2501.0.0 => /usr/local/lib/libabsl_symbolize.so.2501.0.0 (0x223a452fc000)
        libabsl_debugging_internal.so.2501.0.0 => /usr/local/lib/libabsl_debugging_internal.so.2501.0.0 (0x223a46a36000)
        libabsl_malloc_internal.so.2501.0.0 => /usr/local/lib/libabsl_malloc_internal.so.2501.0.0 (0x223a480ad000)
        libabsl_demangle_internal.so.2501.0.0 => /usr/local/lib/libabsl_demangle_internal.so.2501.0.0 (0x223a478f9000)
        libabsl_demangle_rust.so.2501.0.0 => /usr/local/lib/libabsl_demangle_rust.so.2501.0.0 (0x223a48eec000)
        libabsl_decode_rust_punycode.so.2501.0.0 => /usr/local/lib/libabsl_decode_rust_punycode.so.2501.0.0 (0x223a495a5000)
        libabsl_utf8_for_code_point.so.2501.0.0 => /usr/local/lib/libabsl_utf8_for_code_point.so.2501.0.0 (0x223a49ad8000)
        libabsl_bad_variant_access.so.2501.0.0 => /usr/local/lib/libabsl_bad_variant_access.so.2501.0.0 (0x223a49dcf000)
        libabsl_str_format_internal.so.2501.0.0 => /usr/local/lib/libabsl_str_format_internal.so.2501.0.0 (0x223a49f41000)
        libabsl_int128.so.2501.0.0 => /usr/local/lib/libabsl_int128.so.2501.0.0 (0x223a4af21000)
        libabsl_strings_internal.so.2501.0.0 => /usr/local/lib/libabsl_strings_internal.so.2501.0.0 (0x223a4c05e000)
        libabsl_string_view.so.2501.0.0 => /usr/local/lib/libabsl_string_view.so.2501.0.0 (0x223a4b1cb000)
        libabsl_base.so.2501.0.0 => /usr/local/lib/libabsl_base.so.2501.0.0 (0x223a4d33c000)
        libabsl_spinlock_wait.so.2501.0.0 => /usr/local/lib/libabsl_spinlock_wait.so.2501.0.0 (0x223a4c5a4000)
        libabsl_raw_logging_internal.so.2501.0.0 => /usr/local/lib/libabsl_raw_logging_internal.so.2501.0.0 (0x223a4da07000)
        libabsl_log_severity.so.2501.0.0 => /usr/local/lib/libabsl_log_severity.so.2501.0.0 (0x223a4e9aa000)
        libncursesw.so.9 => /lib/libncursesw.so.9 (0x223a4eeac000)
        libharfbuzz.so.0 => /usr/local/lib/libharfbuzz.so.0 (0x223a4fce7000)
        liblcms2.so.2 => /usr/local/lib/liblcms2.so.2 (0x223a50087000)
        libplacebo.so.360 => /usr/local/lib/libplacebo.so.360 (0x223a509c7000)
        libvmaf.so.3 => /usr/local/lib/libvmaf.so.3 (0x223a51c17000)
        libass.so.9 => /usr/local/lib/libass.so.9 (0x223a50f9b000)
        libva.so.2 => /usr/local/lib/libva.so.2 (0x223a520aa000)
        libshaderc_shared.so.1 => /usr/local/lib/libshaderc_shared.so.1 (0x223a52200000)
        libfontconfig.so.1 => /usr/local/lib/libfontconfig.so.1 (0x223a52a84000)
        libfreetype.so.6 => /usr/local/lib/libfreetype.so.6.18.3 (0x223a53489000)
        libdl.so.1 => /usr/lib/libdl.so.1 (0x223a54b47000)
        libintl.so.8 => /usr/local/lib/libintl.so.8 (0x223a53f40000)
        libxml2.so.16 => /usr/local/lib/libxml2.so.16 (0x223a55958000)
        libbz2.so.4 => /usr/lib/libbz2.so.4 (0x223a56e1e000)
        libdvdnav.so.4 => /usr/local/lib/libdvdnav.so.4 (0x223a56236000)
        libdvdread.so.8 => /usr/local/lib/libdvdread.so.8 (0x223a57647000)
        libbluray.so.3 => /usr/local/lib/libbluray.so.3 (0x223a5835e000)
        libgmp.so.10 => /usr/local/lib/libgmp.so.10 (0x223a5885f000)
        libgnutls.so.30 => /usr/local/lib/libgnutls.so.30 (0x223a59a45000)
        libsrt.so.1.5 => /usr/local/lib/libsrt.so.1.5 (0x223a58fe8000)
        libwebpmux.so.3 => /usr/local/lib/libwebpmux.so.3 (0x223a5abe9000)
        liblzma.so.5 => /usr/lib/liblzma.so.5 (0x223a5bfe3000)
        libdav1d.so.7 => /usr/local/lib/libdav1d.so.7 (0x223a5ba60000)
        librsvg-2.so.2 => /usr/local/lib/librsvg-2.so.2 (0x223a5c9ea000)
        libcairo.so.2 => /usr/local/lib/libcairo.so.2 (0x223a5d24f000)
        libaom.so.3 => /usr/local/lib/libaom.so.3 (0x223a5f625000)
        libjxl.so.0.11 => /usr/local/lib/libjxl.so.0.11 (0x223a60263000)
        libjxl_threads.so.0.11 => /usr/local/lib/libjxl_threads.so.0.11 (0x223a5e333000)
        libmp3lame.so.0 => /usr/local/lib/libmp3lame.so.0 (0x223a5f307000)
        libSvtAv1Enc.so.4 => /usr/local/lib/libSvtAv1Enc.so.4 (0x223a62124000)
        libvorbis.so.0 => /usr/local/lib/libvorbis.so.0 (0x223a617d7000)
        libvorbisenc.so.2 => /usr/local/lib/libvorbisenc.so.2 (0x223a63a43000)
        libwebp.so.7 => /usr/local/lib/libwebp.so.7 (0x223a6276f000)
        libx264.so.164 => /usr/local/lib/libx264.so.164 (0x223a64306000)
        libx265.so.215 => /usr/local/lib/libx265.so.215 (0x223a65e85000)
        libva-drm.so.2 => /usr/local/lib/libva-drm.so.2 (0x223a62f1e000)
        libvdpau.so.1 => /usr/local/lib/libvdpau.so.1 (0x223a64d73000)
        libdrm.so.2 => /usr/local/lib/libdrm.so.2 (0x223a65c9b000)
        libXrender.so.1 => /usr/local/lib/libXrender.so.1 (0x223a683ee000)
        libXi.so.6 => /usr/local/lib/libXi.so.6 (0x223a67a0a000)
        librt.so.1 => /usr/lib/librt.so.1 (0x223a692d3000)
        libinotify.so.0 => /usr/local/lib/libinotify.so.0 (0x223a6a317000)
        libQt6DBus.so.6 => /usr/local/lib/qt6/libQt6DBus.so.6 (0x223a6bc73000)
        libkvm.so.7 => /lib/libkvm.so.7 (0x223a6a212000)
        libprocstat.so.1 => /usr/lib/libprocstat.so.1 (0x223a6a784000)
        libXau.so.6 => /usr/local/lib/libXau.so.6 (0x223a6b642000)
        libXdmcp.so.6 => /usr/local/lib/libXdmcp.so.6 (0x223a6c510000)
        libGLX.so.0 => /usr/local/lib/libGLX.so.0 (0x223a6d305000)
        libOpenGL.so.0 => /usr/local/lib/libOpenGL.so.0 (0x223a6e0ea000)
        libxkbcommon.so.0 => /usr/local/lib/libxkbcommon.so.0 (0x223a6e4d3000)
        libQt6QmlMeta.so.6 => /usr/local/lib/qt6/libQt6QmlMeta.so.6 (0x223a6fa2e000)
        libQt6QmlModels.so.6 => /usr/local/lib/qt6/libQt6QmlModels.so.6 (0x223a70dbf000)
        libQt6QmlWorkerScript.so.6 => /usr/local/lib/qt6/libQt6QmlWorkerScript.so.6 (0x223a6fc98000)
        libwayland-server.so.0 => /usr/local/lib/libwayland-server.so.0 (0x223a7083a000)
        libEGL.so.1 => /usr/local/lib/libEGL-NVIDIA.so.1 (0x223a7210f000)
        libpng16.so.16 => /usr/local/lib/libpng16.so.16 (0x223a71c1a000)
        libgthread-2.0.so.0 => /usr/local/lib/libgthread-2.0.so.0 (0x223a72c18000)
        libbrotlidec.so.1 => /usr/local/lib/libbrotlidec.so.1 (0x223a73c17000)
        libzstd.so.1 => /usr/local/lib/libzstd.so.1 (0x223a74db1000)
        libicui18n.so.76 => /usr/local/lib/libicui18n.so.76 (0x223a75daf000)
        libicuuc.so.76 => /usr/local/lib/libicuuc.so.76 (0x223a76ff2000)
        libicudata.so.76 => /usr/local/lib/libicudata.so.76 (0x223a748a5000)
        libexecinfo.so.1 => /usr/lib/libexecinfo.so.1 (0x223a77734000)
        libdouble-conversion.so.3 => /usr/local/lib/libdouble-conversion.so.3 (0x223a77c99000)
        libb2.so.1 => /usr/local/lib/libb2.so.1 (0x223a78231000)
        libpcre2-16.so.0 => /usr/local/lib/libpcre2-16.so.0 (0x223a78c4f000)
        libgmodule-2.0.so.0 => /usr/local/lib/libgmodule-2.0.so.0 (0x223a79aaa000)
        libffi.so.8 => /usr/local/lib/libffi.so.8 (0x223a7a64a000)
        libiconv.so.2 => /usr/local/lib/libiconv.so.2 (0x223a7b197000)
        libpcre2-8.so.0 => /usr/local/lib/libpcre2-8.so.0 (0x223a7b2ad000)
        libutil.so.9 => /lib/libutil.so.9 (0x223a7c43f000)
        libgraphite2.so.3 => /usr/local/lib/libgraphite2.so.3 (0x223a7bf0f000)
        libunwind.so.8 => /usr/local/lib/libunwind.so.8 (0x223a7d451000)
        libvulkan.so.1 => /usr/local/lib/libvulkan.so.1 (0x223a7e5bd000)
        libfribidi.so.0 => /usr/local/lib/libfribidi.so.0 (0x223a7e06a000)
        libunibreak.so.6 => /usr/local/lib/libunibreak.so.6 (0x223a7f14a000)
        libexpat.so.1 => /usr/local/lib/libexpat.so.1 (0x223a7fc1e000)
        libudfread.so.3 => /usr/local/lib/libudfread.so.3 (0x223a80a54000)
        libp11-kit.so.0 => /usr/local/lib/libp11-kit.so.0 (0x223a81c5c000)
        libidn2.so.0 => /usr/local/lib/libidn2.so.0 (0x223a814ca000)
        libunistring.so.5 => /usr/local/lib/libunistring.so.5 (0x223a82546000)
        libtasn1.so.6 => /usr/local/lib/libtasn1.so.6 (0x223a834ae000)
        libhogweed.so.6 => /usr/local/lib/libhogweed.so.6 (0x223a84c28000)
        libnettle.so.8 => /usr/local/lib/libnettle.so.8 (0x223a83f7c000)
        libmd.so.6 => /lib/libmd.so.6 (0x223a857e5000)
        libgdk_pixbuf-2.0.so.0 => /usr/local/lib/libgdk_pixbuf-2.0.so.0 (0x223a86cf1000)
        libpangocairo-1.0.so.0 => /usr/local/lib/libpangocairo-1.0.so.0 (0x223a85ea2000)
        libpango-1.0.so.0 => /usr/local/lib/libpango-1.0.so.0 (0x223a8713f000)
        libxcb-render.so.0 => /usr/local/lib/libxcb-render.so.0 (0x223a87271000)
        libxcb-shm.so.0 => /usr/local/lib/libxcb-shm.so.0 (0x223a87b7c000)
        libpixman-1.so.0 => /usr/local/lib/libpixman-1.so.0 (0x223a88c43000)
        libjxl_cms.so.0.11 => /usr/local/lib/libjxl_cms.so.0.11 (0x223a88430000)
        libhwy.so.1 => /usr/local/lib/libhwy.so.1 (0x223a89441000)
        libbrotlienc.so.1 => /usr/local/lib/libbrotlienc.so.1 (0x223a89ac9000)
        libogg.so.0 => /usr/local/lib/libogg.so.0 (0x223a8a49a000)
        libsharpyuv.so.0 => /usr/local/lib/libsharpyuv.so.0 (0x223a8ad67000)
        libelf.so.2 => /lib/libelf.so.2 (0x223a8bb32000)
        libGLdispatch.so.0 => /usr/local/lib/libGLdispatch.so.0 (0x223a8c976000)
        libepoll-shim.so.0 => /usr/local/lib/libepoll-shim.so.0 (0x223a8dbc8000)
        libnvidia-glsi.so.1 => /usr/local/lib/libnvidia-glsi.so.1 (0x223a8f8eb000)
        libbrotlicommon.so.1 => /usr/local/lib/libbrotlicommon.so.1 (0x223a8cac4000)
        libomp.so => /usr/lib/libomp.so (0x223a8e356000)
        libpangoft2-1.0.so.0 => /usr/local/lib/libpangoft2-1.0.so.0 (0x223a8d612000)
        libthai.so.0 => /usr/local/lib/libthai.so.0 (0x223a8ec2b000)
        libdatrie.so.1 => /usr/local/lib/libdatrie.so.1 (0x223a908bf000)
        [vdso] (0x7ffffffff000)
$ readelf -a /usr/local/bin/Telegram | wc -l   
  167531
$ ldd /usr/local/bin/Telegram | awk '{print $3}' | xargs du -hLc
202M    total

Жесть жосткая! Я считал, что Firefox - самая раздутая программа, но этот ваш Telegram бьёт все рекорды. Боюсь представить сколько памяти он пожирает при работе.

Есть возможность собрать с его с -flto ?

И какой самый толстый обьект внутри ELF-а ? Похоже там полноценная виртуальная машина со своей копией Ubuntu. :-)

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

CPU: 32,5% user,  0,0% nice,  6,0% system,  0,3% interrupt, 61,2% idle
Mem: 5987M Active, 5788M Inact, 1025M Laundry, 2715M Wired, 1054M Buf, 357M Free
ARC: 524M Total, 122M MFU, 343M MRU, 5291K Anon, 3109K Header, 50M Other
     374M Compressed, 442M Uncompressed, 1,18:1 Ratio
Swap: 16G Total, 8752M Used, 7680M Free, 53% Inuse

  PID USERNAME    THR PRI NICE   SIZE    RES STATE    C   TIME    WCPU COMMAND
21590 vadim       106  20    0    31G  7214M select   3 237:57  75,44% firefox
77669 vadim        24  20    0  7636M   476M select   1   5:30   0,20% /usr/local/lib/firefox/firefox -contentproc {0
28896 vadim        25  20    0  3438M   391M select   1   4:08   0,01% /usr/local/lib/firefox/firefox -contentproc {7
78385 vadim        24  20    0  3194M   406M select   0  12:46   0,02% /usr/local/lib/firefox/firefox -contentproc {e
  394 vadim        21  20    0  3164M   292M select   3   6:06   1,45% /usr/local/lib/firefox/firefox -contentproc {8
 6350 vadim        19  20    0  3156M   400M select   0  13:06   1,34% /usr/local/lib/firefox/firefox -contentproc {b
 6438 vadim        19  20    0  3112M   329M select   1  10:07   0,76% /usr/local/lib/firefox/firefox -contentproc {b
90089 vadim        22  20    0  3106M   307M select   3   5:51   0,93% /usr/local/lib/firefox/firefox -contentproc {4
 6499 vadim        19  20    0  3074M   322M select   3   8:06   0,97% /usr/local/lib/firefox/firefox -contentproc {9
 6490 vadim        19  20    0  3030M   313M select   3   8:02   1,07% /usr/local/lib/firefox/firefox -contentproc {3
28049 vadim        23  20    0  2993M   245M select   3  11:43   0,06% /usr/local/lib/firefox/firefox -contentproc {e
 1646 vadim        19  20    0  2989M   236M select   0   4:00   0,18% /usr/local/lib/firefox/firefox -contentproc {6
 9057 vadim        29  84    0  2898M   445M CPU3     3   4:14  38,92% /usr/local/lib/firefox/firefox -contentproc {6
78083 vadim        20  20    0  2888M   227M select   2  11:22   0,12% /usr/local/lib/firefox/firefox -contentproc {b
 5875 vadim        19  20    0  2826M   162M select   0   0:37   0,08% /usr/local/lib/firefox/firefox -contentproc {a
 6698 vadim        20  20    0  2779M   184M select   1   3:21   0,06% /usr/local/lib/firefox/firefox -contentproc {f
27671 vadim        20  20    0  2755M   192M select   2   0:24   0,00% /usr/local/lib/firefox/firefox -contentproc {6
 6611 vadim        19  20    0  2747M   163M select   3   0:38   0,05% /usr/local/lib/firefox/firefox -contentproc {d
 6620 vadim        19  20    0  2732M   161M select   0   0:39   0,05% /usr/local/lib/firefox/firefox -contentproc {9
78104 vadim        19  20    0  2730M   138M select   0   1:56   0,02% /usr/local/lib/firefox/firefox -contentproc {0
27680 vadim        19  20    0  2719M   182M select   0   0:12   0,00% /usr/local/lib/firefox/firefox -contentproc {5
21793 vadim        19  20    0  2692M   163M select   0   1:17   0,24% /usr/local/lib/firefox/firefox -contentproc {7
23658 vadim         1  52    0  2691M  1968K pipewr   0   0:10   0,00% git log --all -- mail/claws-mail
 9059 vadim        20  20    0  2675M   238M select   1   0:19   0,03% /usr/local/lib/firefox/firefox -contentproc {e
65171 vadim        19  20    0  2670M   168M select   3   1:02   0,03% /usr/local/lib/firefox/firefox -contentproc {0
21733 vadim        19  20    0  2639M   114M select   0   0:42   0,02% /usr/local/lib/firefox/firefox -contentproc {2
21615 vadim        18  20    0  2636M   185M select   2   5:09   0,70% /usr/local/lib/firefox/firefox -contentproc {3
44518 vadim        20  20    0  2633M   149M select   1   2:06   0,00% /usr/local/lib/firefox/firefox -contentproc {6
...
 6726 vadim        18  20    0  2480M   106M select   3   0:01   0,00% /usr/local/lib/firefox/firefox -contentproc {2
 9075 vadim        18  20    0  2480M   141M select   3   0:01   0,00% /usr/local/lib/firefox/firefox -contentproc {6
14633 vadim        13  20    0  2466M   136M select   1   0:01   0,00% /usr/local/lib/firefox/firefox -contentproc {8
18722 vadim        13  20    0  2465M   137M select   0   0:01   0,00% /usr/local/lib/firefox/firefox -contentproc {a
18669 vadim        13  20    0  2465M   137M select   0   0:01   0,00% /usr/local/lib/firefox/firefox -contentproc {6
19106 vadim        58  20    0  2164M   435M select   2  15:16   0,00% Telegram
19075 vadim         3  23    0  1124M    72M select   0  41:51   6,57% /usr/local/libexec/Xorg :0 -verbose 5 -logverb

Нет, браузеры по-прежнему жрут больше, Хромой вообще сотни гиг мапит.

И какой самый толстый обьект внутри ELF-а ?

Пишите как посмотреть, я не настолько сварщик :)

Сейчас же в нём еще и браузер есть на webkit-gtk

Ха! Так в чем поинт использовать .so, если приложения и так половину опенсорсного мира содержат внутри ? По факту получается, что разработчики давно уже всё статиком затянули во внутрь (AppImage, Flatpak - те же яйца). Какой толк от динамической линковки при таком раскладе ?

Вы цифры-то посмотрели? Он таки грузит .so на двести метров, примерно своего же размера то есть. Если бы каждое qt-приложение тащило бы его еще внутрь себя статиком, я бы на своих 16 гигах уже совсем помер (а так просто рестартую Файрфокс раз в несколько дней, когда своп засрётся). В том числе за это и не люблю все эти снапы-флатпаки (к счастью, у меня их и нет).

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

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

Вы цифры-то посмотрели? Он таки грузит .so на двести метров, примерно своего же размера то есть.

Дело в том, что из всего того, что загружено, реально используется очень малая доля. Мне как-то попадалась статья на эту тему, где проводились исследования ряда популярных GUI приложений (Web-браузеры - тема отдельного разговора). В ней исследователи пришли к выводу, что в среднем, из каждой загруженной приложением библиотеки испольузется только 5% её кода, а всё остальное висит в памяти мертвым грузом. Это означает, что если выполнить Link-Time Optimization (-flto), то размер кода уменьшится в 20 раз! Иными словами, в один и тот же обьем памяти можно разместить до 20-ти приложений написанных и слинкованых таким образом.

Картину портят Web-браузеры и прочие приложения которые содержат в себе виртуальную машину и полную копию "мира" для этой ВМ. Также не способствует развитию идеи статической линковки с LTO вошедший в обиход способ распространения ПО в виде Flatpack, AppImage и Docker. Короче, если бы не мода на "удобство установки", то современный софт можно было бы конкретно ужать в размерах - в динамические библиотеки вынести только часто используемые системные функции (libc, libthr и т.д.), а всё остальное линковать статиком с -flto. Помимо экономии памяти было бы существенное снижение обьема гимороя вызванного поддержанием совместимости различных версий.

Ну вообще-то нет, не висит. В этом легко можно убедится, попробовав открыть эти .so на запись и получить странную ошибку Text file busy. Это значит, что подсистема виртуальной памяти рассматривает их как этакий “своп”, и неиспользуемые страницы просто выкидывает из памяти, при необходимости загружая вновь из файла. При этом будет экономия на том, что используемые части у разных программ всё же пересекаются, а в случае статической линковки у каждого будет таки своя копия.

Это не говоря уже о том, что в цифры 20 раз при -flto я не верю - 2-3 раза куда ни шло.

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

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

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

Сейчас есть замена - cpm - сильно быстрее работает

Познакомился с Perl, когда пришлось погрузиться в тему написания скриптов для ПО Ansys CFX. А поскольку Ansys обильно скупал различные другие софты, каждый из которых поддерживал скрипты только на каком-то конкретном языке, то под капотом там собиралась знатная солянка. Поэтому в рамках одной задачи газодинамика/тепло/прочность собиралась пачка взаимосвязанных скриптов на разных языках, например Python + Perl + внутренние языки Apdl и ccl. Было весело :) Но ни до, ни после больше с Perl не встречался, видимо какая-то узкая ниша за ним осталась и все.

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

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

Да какая там оптимизация с динамическим связыванием переменных. Внимание, вопрос:
Что выведет на экран следующая программа? :)

#!/usr/bin/perl

sub foo {
    print "$x, $y\n"
}

sub bar {
    local $x = 0;
    foo()
}

sub baz {
    local $y = 0;
    bar()
}

$x = 1337;
$y = 42;
foo();
bar();
baz()

Для кого-то новости фрагменты из документации, которые спрашивают на собеседованиях на перловика? Хотя тащемта любой человек, использовавший local в шелл-скриптах, поймет данный конкретный пример и без неё - а в них больше ничего и нету, в Перле же тридцать лет my есть, с котором поведение станет “ожидаемым” (это ведь был пример из разряда “смотрите как в этом языке неожиданно и неинтуитивно”, да?).

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

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

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

Так и Perl имеет lexical scope variables. И они являются предпочтительными. local используется редко, обычно все переменные определяются как my и тогда они связаны лексически и работают быстро.

Ни тот, ни другой не “ищет её в тексте программы”, даже когда в том же Перле лексическое связывание (а это как раз типовой случай с my, на local писали более 30 лет назад) - делается это в стурктурах-хелперах байткода, полученного из AST. И в случае динамического скоупинга, как в примере с local, тоже не ищет - к каждой такой переменной просто привязывается “её собственный” теневой стек, к которому добавляются инструкции push в месте local и pop на закрывающей фигурной скобке блока (на самом деле стэки Перла устроены несколько иначе и сложнее, но концептуально всё те же save/restore вместо поиска каждый раз). Возможность реального поиска по стеку вызовов я видел только в Tcl (upvar сотоварищи).

Как-то так он теперь не Perl, а Raku.

Это то, что было под названием Perl 6. А пятый так и остался теперь снова единственный perl.

Для своих задач (те же тексты) он уже хорошо оптимизирован, видел сравнение кода на Go “в лоб”, которое оказалось в примерно 40 раз медленнее перлового решения той же задачи.

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

Регулярки они и в африке регулярки. Главное случайно не заддосить себя, как Cloudflare однажды, чем собственно PCRE и знаменит по большей части. Ну, а сделать трансформер на основе какого-нибудь tree sitter не сказать чтобы сложно. Не знаю зачем вообще понадобилось делать рекурсивные регулярки, когда достаточно линейно распарсить.

Perl сгубило желание автора создать универсальный язык, совпавшее с началом эпохи Unicode. В итоге первое растянулось на 20 лет (Perl 6, Raku), а второе - сделало бесполезной изрядную часть CPAN наследия, которой собственно и был силён язык в прежние годы. Компактность Perl сейчас могла бы пригодится в связке с LLM экономить токены, но ему они плохо обучены и делают много ошибок.

Unicode. В итоге первое растянулось на 20 лет (Perl 6, Raku), а второе - сделало бесполезной изрядную часть CPAN наследия, которой собственно и был силён язык в прежние годы

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

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

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

В десятых уже было всё хорошо. Да, умолчание осталось конечно же про ASCII - а как иначе совместимость со скриптами 30-летней давности (а я такие видел в проде в этом десятилетии) иметь? Но десятка прагм нету, просто utf8 где надо, да и всё. Последние багфиксы по теме уникода, кажется, были в 5.18 (то есть времён Очаковских до покоренья Крыма).

Если этот пост задумывался как реклама Перла, получилось не очень. Сравнивать синтаксис надо было не с Питоном, а с тем, из чего Perl и вырос - смесь Shell, sed, awk и Си. Эти задачи и стоило показывать, как он облегчает их, особенно на примере всяческих однострочников, а с Питоном сравнивать - это уже отдельная специальная олимпиада.

Пост изначально задумывался как реклама Perl, но в процессе структурирования информации о нём у меня появились сомнения, после чего я и добавил знак вопроса в название поста. Возможно его действительно лучше было сравнить с sed и awk, рассказать, что он изначально создавался из-за ограниченности awk и его название расшифровывают как "Practical Extraction and Reporting Language", но я решил сильно много про его историю не писать и просто рассказать о его возможностях. Я сравнивал Perl с тем, что знаю и чем имел дело, а про awk я почти ничего не знаю. Для меня в первую очередь важно было понять есть ли смысл использовать Perl сейчас, а не когда-то там или в каких-то legacy проектах, поэтому как-то так.

Конечно есть! Вот с тем же лексическим scoping’ом у того же Питона до сих пор всё ужасно, как этим вообще пользуются, блин! И совместимость - написав на Перле, я могу не париться с тем, что каждый год под новую версию нужно всё переписывать. Да и просто приятнее на нём писать, чем на этих BDSM-языках…

Язык хороший, примеры - говно.

print &subr

Вот так не пишите никогда. Разве что при написании собственного autoloader-а (но это точно не про введение в Perl). Есть три основных способа вызвать подпрограмму (она же функция):

1. subr()
2. subr
3. &subr

Так вот, преимущественно стоит использовать первый метод. С ним меньше всего подводных камней и неоднозначностей. Пример:

printf("У %d коров %d рогов\n", x, 2 * x);

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

my @sorted = sort { $a <=> $b } map { $_->{order} } @records;

А третьим способом позьзоваться не надо почти никогда. Это наследие Perl4 который уже 32 года не актуален. Хотя совместимость с ним поддерживается.

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

my @commands = (
'init',
'run',
'exit',
);

Это не является нарушением синтаксиса, а diff-ы при добавлении элементов выходят аккуратнее.

З.Ы. За Perl-ом закрепилась дурная слава write-only языка не в силу его имманентных свойств, а из-за того, что горе-программистам лень прочитать (а прочитав - выполнять) perldoc perlstyle который идет в комплекте с интерпретатором.

  1. В примерах я пытался показать возможности языка, ну и два последних - это его возможности + то как лично я его использовал.

  2. Вот насчёт вашего мнения о том, как стоит вызывать сабрутины я не согласен.

    print &subr

    Вот так не пишите никогда

    Я не знаком с историей того как там менялся Perl, какие методы легаси, а какие нет, но я читал книжку O'Reilly Learning Perl, 8th Edition, которая 2021 года издания и в главе про сабрутины (если быть точным с 72 по 73-ю страницу) говорится о том, что использование амперсанда строго показывает компилятору то, что это вызов сабрутины и благодаря этому у нас как минимум не будет проблем с тем, если наша сабрутина называется также, как и существующая функция, а как максимум мы сможем объявлять сабрутину после её использования и при чтении кода вызов сабрутины будет визуально выделяться, поэтому почему нет? Что конкретно с амперсандом не так?

    Вот вам прямая цитата текста из этой книги

    Omitting the Ampersand

    As promised, now we’ll tell you the rule for when you can omit the ampersand on a subroutine call. If the compiler sees the subroutine definition before invocation, or if

    Perl can tell from the syntax that it’s a subroutine call, the subroutine can be called without an ampersand, just like a built-in function. (But there’s a catch hidden in that

    rule, as you’ll see in a moment.)

    This means that if Perl can see that it’s a subroutine call without the ampersand, from the syntax alone, that’s generally fine. That is, if you’ve got the parameter list in parentheses, it’s got to be a function call:

    my @cards = shuffle(@deck_of_cards);  # No & necessary on &shuffle

    In this case, the function is the subroutine &shuffle. But it may be a built-in function, as you’ll see in a moment.

    Or, if Perl’s internal compiler has already seen the subroutine definition, that’s generally OK too. In that case, you can even omit the parentheses around the argument list:

    sub division {
      $_[0] / $_[1];                   # Divide first param by second
    }
    
    my $quotient = division 355, 113;  # Uses &division

    This works because of the rule that you may always omit parentheses when they don’t change the meaning of the code.

    You can’t omit those parentheses if you use the &, though.

    However, don’t put that subroutine declaration after the invocation; if you do, the compiler won’t know what the attempted invocation of division is all about. The compiler has to see the definition before the invocation in order to use the subroutine call as if it were a built-in. Otherwise, the compiler doesn’t know what to do with that expression because it doesn’t know what division is yet.

    As with many things in this book, our use of the & is expedient for teaching you the Perl language rather than teaching you to be an experienced Perl programmer. Some people disagree. We say more about this in the “Why we teach the subroutine ampersand” blog post.

    That’s not the catch, though. The catch is this: if the subroutine has the same name as a Perl built-in, you must use the ampersand to call your version. With an ampersand,

    you’re sure to call the subroutine; without it, you can get the subroutine only if there’s no built-in with the same name:

    sub chomp {
      print "Munch, munch!\n";
    }
    
    &chomp;  # That ampersand is not optional!

    Without the ampersand, you’d be calling the built-in chomp, even though you’ve defined the subroutine &chomp. So the real rule to use is this one: until you know the names of all of Perl’s built-in functions, use the ampersand on function calls. That means you will use it for your first one hundred or so programs. But when you see someone else has omitted the ampersand in their own code, it’s not a mistake; perhaps they simply know that Perl has no built-in with that name.

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

Что конкретно с амперсандом не так?

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

#!/usr/bin/perl

use strict;
use warnings;

sub setter(\$$) {
    my ($ref, $val) = @_;
    $$ref = $val if ref($ref);
}

my $x = 0;
print "1. x=$x\n";
setter($x, 5);
print "2. x=$x\n";
&setter($x, 10);
print "3. x=$x\n";

результат:

1. x=0
2. x=5
3. x=5

Во втором случае setter не присвоил переменной $x значение 10.

Или вот еще. Напишем махонькую программку в которой есть только exit. Но сделаем в слове exit опечатку.

#!/usr/bin/perl

use strict;
use warnings;

exut;

Проверим синтаксис запустив perl с ключом -c, т.е. попросим его прекомпилировать код, но не исполнять.

~$ perl -c /tmp/nosub.pl
Bareword "exut" not allowed while "strict subs" in use at /tmp/nosub.pl line 6.
/tmp/nosub.pl had compilation errors.

А теперь добавим & перед exut и снова попробуем.

~$ perl -c /tmp/nosub.pl
/tmp/nosub.pl syntax OK

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

Разве прототипы как раз таки не legacy? Но со вторым аргументом, я соглашусь, так становится проще отлавливать ошибки. Ну я вижу смысл в ваших словах и пожалуй перейду на вашу сторону, уберу в вызовах сабрутин амперсанды и добавлю скобочки. Спасибо, что объяснили.

Не целиком legacy, скажем так (пример с конкретно \$ “не очень”, а с простыми вполне). Вот, скажем, автор AnyEvent определил функцию дефолтного логгера так, чтоб можно было писать вот в таком бесскобочном стиле:

$ grep log cborlog.pl | head -5
AE::log fatal => "flag exists on start with $pid contents\n" if $pid;
        AE::log info => "starting process for layer $layer on %s", $decoders{$layer}->{inc};
                on_destroy => sub { AE::log trace => "layer $layer exited"; $cond->end },
                on_error   => sub { save_cbor(1); AE::log fatal => "RPCFORK $layer ERROR: $_[0]"; },
$AnyEvent::Log::LOG->log_to_path($opts->logfile) if $opts->{logfile}; # XXX path vs file

Синтаксис прототипов стоило объяснить для новичков, которые скорее всего в этих комментариях, тем более что обычно передачу по ссылке ВОТ ТАК не делают - в вызове сделают setter(\$x, 42) чтоб явно показать, что передана ссылка, а не просто параметр.

А про проверку синтаксиса объяснение для новичков хорошее, лайк.

Что конкретно с амперсандом не так?

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

#!/usr/bin/perl

use strict;
use warnings;

sub inner {
    print "Передано " . scalar(@_) . " аргументов: " . join(', ', @_) . "\n";
}

sub outer {
    inner;
    &inner;
}

outer(1,2,'dummy');

результат:

~$ /tmp/tst.pl
Передано 0 аргументов: 
Передано 3 аргументов: 1, 2, dummy

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

Ну здесь же то же самое сказали - можно без них, по большому счету они нужны, если мы назвали свою именем встроенной функции - но зачем так делать? Когда такое может быть необходимо в случае развера проекта, в нём тогда будут модули, нэймспэйсы, объекты, так что MyModule::chomp() или $object->chomp() снова не потребует амперсанда.

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

А с прототипами и их внезапной неработой самые приколы начинаются когда функции библиотечные или даже встроенные. Возьмем print, очень популярную, все ее назубок знают. А все ли знают какой у нее прототип? И что будет если вызывать эту функцию с & и игнорировать прототипы? Давайте вызовем ее тремя способами. Первый:

#!/usr/bin/perl

use strict;
use warnings;

print STDERR "error1\n";

результат:

error1

Второй:

#!/usr/bin/perl

use strict;
use warnings;

print(STDERR "error2\n");

результат:

error2

Третий:

#!/usr/bin/perl

use strict;
use warnings;

&print(STDERR "error3\n");

результат:

String found where operator expected (Do you need to predeclare "STDERR"?) at /tmp/print.pl line 6, near "STDERR "error3\n""
syntax error at /tmp/print.pl line 6, near "STDERR "error3\n""
Execution of /tmp/print.pl aborted due to compilation errors.

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

Там хитрость в том, что у данной конкретной функции прототип нестандартный: обычно в бесскобочной записи все аргументы являются просто списком через запятую, только без самих скобок: funcname "arg1", "arg2", "arg3"; А у print там может опционально появляться хэндл:

print "arg1", "arg2", "arg3";
print STDERR "arg1", "arg2", "arg3";

Обратите внимание, что после STDERR нет запятой, он как бы “не совсем” аргумент, а делает вызов похожим на “конструкцию языка”, как это было бы в “обычном языке”.

обычно в бесскобочной записи все аргументы являются просто списком через запятую

В бесскобочной записи как раз можно описать собственный print.

#!/usr/bin/perl

use strict;
use warnings;

sub IO::Handle::myprint {
    my ($fh, @args) = @_;
    print $fh scalar(gmtime()) . ': ', @args, "\n";
}

myprint STDERR "hello";

результат:

~$ /tmp/globparam.pl 
Fri Apr 24 23:10:47 2026: hello

Тут хитрость в том, что парсер без скобок трактует это как вызов метода myprint для STDERR который одновременно является и typeglob и объектом класса IO::File, наследником IO::Handle. А в IO::Handle мы только что доопределили свой метод. Но в варианте со скобками это пришлось бы переписать как:

STDERR->myprint("hello");

у данной конкретной функции прототип нестандартный

У данной (print) прототип нестандартный. Но есть встроенные и со стандартными прототипами которые без прототипа работать не будут. Вот, скажем, у push стандартный прототип (\@@). Если его вызвать с амперсандом:

#!/usr/bin/perl

use strict;
use warnings;

my @arr;

&push(@arr, 'value');

то получим:

Undefined subroutine &main::push called at /tmp/push.pl line 8.

Еще, кстати, побочный эффект. С амперсандом оно ищет только в main::, а в CORE:: не ищет. Ну ок, подскажем ему где искать.

#!/usr/bin/perl

use strict;
use warnings;

my @arr;

&CORE::push(@arr, 'value');

и получаем:

Type of arg 1 to &CORE::push must be array reference at /tmp/push.pl line 8.

И это в чистом виде игнорирование прототипа. Вполне стандартного. Прототип \@@ говорит, что первым параметром должен быть указан массив, а в функцию будет передана ссылка на него. Поскольку прототип игнорировался, то были переданы значения (ноль значений на самом деле, так как @arr пустой), а не ссылка.

Тут хитрость в том, что парсер без скобок трактует это как вызов метода myprint для STDERR который одновременно является и typeglob и объектом класса IO::File, наследником IO::Handle.

А, это то самое место, где new Class::Name @args по той же причине работает, и это место из языка лучше было бы выкинуть (современный стиль жестко не рекомендует), хотя конкретно для принта трюк получился хороший.

У данной (print) прототип нестандартный. Но есть встроенные и со стандартными прототипами которые без прототипа работать не будут. Вот, скажем, у push стандартный прототип (\@@)

Нет, он нестандартный, не в том плане, что не описан в манах, а в том, что “обычно так не делают” (не рекомендуется).

обычно в бесскобочной записи все аргументы являются просто списком через запятую

Кстати, есть исключение. Если первый параметр указан в прототипе как & то первым параметром можно написать блок кода перед которым не надо sub и после которого не нужна запятая. То есть с прототипом &@ легко можно написать свой аналог grep и вызывать его как my @filtered = mygrep { $_ > 5 } 0..10; И тут неважно есть скобки или нет, вот так my @filtered = mygrep({ $_ > 5 } 0..10); тоже можно.

Да, это единственное место в прототипах “без запятых”, которое любят и широко применяют. В каком-нибудь try {} catch {} очень органично ложится, например.

Хах, я вот могу сказать, что “как обычный програмист на Перле”, не знаю почему так без рыться в документации, потому что “обычно так не делают”, применение прототипов ограничено. “Доктор, когда я вот делаю, мне больно! - А вы так не делайте” (с)

А разве print это уже функция?

Да, конечно. Встроенная функция из пространства имен CORE (см. https://perldoc.perl.org/CORE)

А еще хэши на Perl работают в несколько раз быстрее, чем на Python-е. Довольно много переписывал с Perl-а на Python и всякий раз удивлялся. В Python dictionary - это object, a в Perl-e - нет.

Это вроде про Perl говорили: "There is more than one way to do things" :) ну и классика system(“make deploy”) == 0 || die “deploy failed: $!”;

Сделай или умри...

There is more than one way to do things

Именно за это многие Perl и не любят. Много вариантов с разной эффективностью и уместностью

||

Правильный оператор в подобных конструкциях -- or

Я не Perl expert, приколку помню, синтаксис чат гпт подсказал, его ногами бейте.

Да, это не проблема языка, а проблема психологии. Многие предпочитают BDSM вместо свободы. Ну и да, большое количество свободы подразумевает внутреннюю самодисциплину, иначе начинается “ох, а еще и так можно, а давайте попробуем всё”, что и послужило причиной большого количества немайнтенабельного кода 90-х, сделавшего Перлу дурную славу - потом-то “наигрались”, а осадочек остался…

Вот да, ещё одно место где легко получить нереальные проблемы при поддержке не очень опытным программистом. Приоритет операций в перле сложный.

Что там сложного? Табличка приоритетов в самом начале man perlop, при сомнениях открыть глянуть очень быстро, не читая весь.

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

“Единственной интуитивно понятной вещью является материнская сиська, всему остальному надо учиться” (с)

У меня, например, нет такого интуитивного понимания. Более того, из опыта Си с разными & и && интуиция говорит, что и тут должно отличаться (зачем-то же их сделали разными).

Одна из основ перла - это именно интуитивность. Он делает именно то что ты предполагаешь. Но не во всех случаях. Он понимает когда строка это число, понимает что надо сделать если я пишу print 2+‘2’; и делает то что я предполагал. Это его сильная сторона. А вот or и || отличается - две операции, почти одинаковые, но с разным приоритетом. Их надо было делать совсем одинаковыми.

& и && это совсем разные операторы, а or и || -одинаковые. Но из за неочевидного поведени они могут порождать проблемы.

Я не знаю насколько Ларри Уолл был серьёзен в выступлении, но он обосновывает приоритеты операций не естественными для программирования причинами, а философскими. То есть от него заранее можно ожидать любой пакости. Он её и совершил, начав perl6 - и убив perl тем самым.

Я толсто намекал, что для разных людей понятие интуитивности - разное. Нет, для человека, совсем ничего не видевшего, как & и && будут разными, либо наоборот, так и or и || совсем не одинаковы. Тем более, что, например, в криптографической литературе || часто используется для конкатенации и вообще к or отношения не имеет. Происхождение же разницы очевидно, опять же, для человека с правильным бэкграундом: в шелле && и || используются для управления выполнением, имея низкий приоритет, Ларри нужны были как они, так и сишные операторы, и сишные видимо чаще, поэтому для управления он и дал им другие названия.

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

И нет, пакости с Perl6 он не совершал - это совершенно обычная, естественная для программистов ошибка “сейчас всё возьмем и перепишем с нуля”. Её совершают очень многие, Netscape так вообще из бизнеса вылетел, прекратив существование как компания. Против неё целые эссе мне попадались… так что нет, злого умысла у Ларри здесь не было.

может в 87-м это и считалось, полезно - «Здесь больше одного способа это сделать», на мой взгляд это только отвлекает от самой программы и концентриует не на том - "что сделать", а на том - "как сделать", по моему это самое вредное свойство, которое может быть у ЯП. Автор вообще походу прикололся, когда создавал этот язык, а дурачки подтянулись и сказали - ой как интересно, слава богам, что его забыли

Людей, на полном серьезе не понимающих, почему многообразие и свобода хорошо, надо принудительно сажать писать на COBOL, где, например, символ комментария можно поставить только в определенной колонке строки и нигде иначе (6-й штоле, забываю уже), строки длиннее 72 символов синтаксическая ошибка, и надо внимательно смотреть, где расставлять точки (вместо точек с запятыми там) в случае вложенных IF. Вспоминая, как из-за подобной ошибки (только в Фортране) в свое время упала ракета.

Вообще, конечно, тут вспоминается великий психиатр Эрих Фромм, книга “Бегство от свободы”…

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации