Системы типов я сравнивать не берусь, я в этом далеко не эксперт, однако же синтаксический сахар, который позволяет написать одну строчку вместо 2-3 и сделать код более читабельным, мне бесполезным не кажется.
Заменять 2-3строчки на одну - это всегда такая себе затея. Она превращает язык в помойку. Когда бездумно добавляется сахар ради сахара.
Если на языке можно реализовать ? - это хорошо. Если же ? это просто костыль на уровне компилятор, то это плохо. В язык нужно добавлять возможности через которые уже реализуется сахар. А не просто сахар.
Потому добавление сахара - это проблема. И потому, что весь не добавишь. И потому что это идёт в ущерб фичам. Здесь достаточно посмотреть на раст. Где примитивного саха много, а фичей мало.
Касательно типа объекта ошибки, это ожидаемо. Интересно было бы посмотреть, как это выглядит в достаточно больших и долгоживущих проектах, написанных профессиональными разработчикми на Rust (к которым я сам не отношусь). Безусловно, вариант который вы привели, с некоторым базовым типом и выделением объекта на куче выглядит как наиболее очевидное и наивное решение.
На уровне пропаганды заявляет о "сохранении типов", в реальности практически любой код на расте использует затирание типов в ошибок.
Есть маргинальные решения где через костыли на макросах пытаются мержить емамы, но это никто не использует в реальности. По крайней мере я такого не видел.
Хотя, я тут бегло погуглил, вроде бы даже есть какие-то библиотеки вроде anyhow , которые упрощают жизнь и позволяют подружить типы ошибок из разных библиотек. В общем, думаю, какое-то адеватное решение есть.
Это то самое box dyn err.
Вы имеете ввиду реализацию pm непосредственно в Rust?
Везде, особенно в раст. Да, в более-менее адекватных фп-языках уже давно эмулируют перегрузку через pm. Это куда удобнее, чем искатаь match в лапше. Но там есть всё те же проблемы с тем, что их нельзя расширять из пользовательского кода.
Просто в целом, это довольно известная, проверенная временем и широко применяющаяся концепция, например в функциональных языках программирования.
Проблема только в том, что на функциональных языках программирования ничего не написано. А что пишется - там уже работает естественный отбор.
Допустим, каждый последователь расскажет, что у него там "чистый фп-язык" - все дела. Но в реальности, когда он идёт писать код - всё забывается. И уже язык становиться мультипарадигмальным, а массив всегда был в фп.
Неважно что "ты" считаешь и как думаешь. Есть то, что работает, а что не работает. И когда кто-то начинает что-то делать - реальность всегда вносит коррективы. И вот фп уже не фп. И пм уже не пм.
Не больше. fn в отличии от auto в цпп - это костыль, который обусловлен слабостью "парсера". -> в цпп имеет смысла, когда как в расте - это просто костыль, потоу как лево всегда занято костылём ввиде fn/let и прочего.
Право используется потому, потому как это даёт возможность использовать парметры как часть типа. Допустим `(auto x) -> decltype(x.err)`
Поэтому, допустим, сущуествует template<>. Оно нужно для того, чтобы можно было определить теплейт-параметр до типа возврата. `T <T>f` - такое написать нельзя. Более-менее смышлёные последователи права ссылаются на то, что право у них по этой причине. Нет. Право там именно потому, что fn.
Про fn - это пошло ещё с паскаля, как пример максимально примитивного парсинга. Суть там простая. У нас есть описание неких грамматических правил и нам нужно узнать то, какому правилу соответствует набор токенов, в простом случае.
Вот самый просто способ - это максимально сильно упрощать грамматику, уменьшая коллизии в правилах. А когда от них уйти нельзя - просто тупо писать идентификатор правила слева.
Т.е. все эти fn/let и прочее - это синтаксический мусор, который не имеет никакого смысла, кроме как для упрощения разбора. Упрощение разбора никогда актуальным не являлось. Поэтому все сказки "это для оптимизации" - являются чушью. Достаточно посмотреть на время компиляции раста. Это экономия на спичках, которая крайне сомнительна.
Подобный подход - удел студентов, которые только начинают писать языки.
Сейчас очень часто можно видеть использование auto -> в цпп. Это просто пропагандисткий причём призваный сместить внимание с отстутствия вывода типа возврата в расте. Потому как писать подобным образом смысла не имеет, а когда имеет - аналога в расте существовать не может в силу его скудных возможностей.
Нет, просто раст куда более ограничен. От этого там существует тысячи костылей, где никакой компилятор ничего не энфорсит, кроме обёрток над ансейф-костылями.
sv - это какая-то часть строки. Этих частей много. С чего вдруг это должно "энфорсить" иммутабельность на исходную строку? Ни с чего.
Это вью на кусок памяти и, очевидно, что никаким образом ничего не говорит и не должно говорить о том, что этот кусок памяти меняться не должен.
А почему там что-то "энфорсится" - потому что это максимально примитивная реализация. Более примитивного ничего придумать невозможно. И причина этого не в том, что это какое-то "человеколюбие" - как раз таки всё наоборот. Его там нет. На человека там сброшена задча мучится с этими костылями.
Используется подобная максимально примитивная схема потому, что она элементарно реализуется, а возможности реализовать что-то больше не было. Да и нет.
Такая же ситуация с -> и остуствием вывода типа возврата. Просто не смогли, а все рассуждения "чтобы видеть типы" - это сказки для бедных и оправдания. Почему же тогда у лямбды есть вывод типов?
И сказки про "лямбда это лямбда" - такие же сказки, потому как вывод типов в лямбде есть потому, что костылём эта лямбда просто воспринимается как кусок кода. Т.е. она не-полиморфна.
Поэтому, даже если принять оправдание "лямбда это лямбда", то почему же лямбда не полноценно? Почему я не могу написать `let id = |x| x; id(10); id(10.);`
? - это костыль, который лишь говорит о том, где все сказки "удобно, пм - круто" были фейком. Можно почитать то, что пели последователи result до ?.
Если говорить о реальном коде, особенно о C++(где есть полиморфизм и куда более мощная ситема типов, нежели в раст), то ? становиться бесполезным.
Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.
К слову, pattern matching тоже неплохо бы работал с std::expected.
pm достаточно слабая концепция, которая во много неполноценна. А уж тем более в C++, если есть полиморфизм и перегрузка.
Поэтому в том же расте за пределами очевидных учебных примеров pm используется редко. Везде используются трейты.
Одна из причин - не расширяемость. pm работает всегда только по закрытому типу, который зачастую объявлен где-то в кишках какой-то библиотеки. Расширить его нельзя. Никак.
Трейт/перегрузку(трейты в расте это такая попытка реализовтаь перегрузку из цпп) это делать позволяют. Т.е. где-то в пользовательском коде можно написать impl чего-то, либо перегрузку.
Тем, что он влияет на анализатор. Точно так же как и throw. https://godbolt.org/z/fshW7Wodz - максимально простой пример. Конечно, в реальности контексты использования более сложные, но суть такая же.
Т.е. мы точно знаем, что код сюда не дойдёт, но это нигде не отражено на уровне типов. Не написать код мы не можем - это будет не-полное использование и компилятор будет ругаться.
Так же в некоторых случаях компилятор просто не может вывести это из кода. Допустим из произвольного asm. Тот же noreturn применяется для того же.
Конечно, куда лучше было бы ограничить это где-то сверху и далее информацию передать через типы, но такого нет.
Предположим, что код с интами работает быстрее, а отрицательные числа нам ненужны. Заменить на uint32_t нельзя - будет медленее. Но компилятор всегда будет предполагаеть наличие их.
Поэтому можно сделать if(x < 0) __builtin_unreachable(); либо if(x >= 0) else __builtin_unreachable()
Какую лексику? Подробнее. Какой троллинг? Насколько же интел/невежества-боты предсказуемы. Ещё под какого-то наблюдателя косит. Очевидно подобному персонажу "без разницы" прав кто-то либо нет, в том числе и он сам.
Как же усиленно интел-боты и фанаты невежества гадят в карму. Что им ещё делать, кроме как затыкать неугадных и даже не пытаться что-то ответить.
И никак же они усиленно плюсуют того, кто попросту врёт и враньё кого опровергается за 2минут использования гагла(привете avx и numpy).
Фиксирую так же то, как они будут оправдываться, раскказывая, что гадят они потому, что я как-то их оскорбил. И это будет очередным враньё, потому как об этом:
обиженного подростка
Да, именно называние оппонентов обиженными подростками - это то самое глушилово неугодных. При этом ладно бы этому были какие-то пруфы, как это сделал я в случае с "терминальными невежеством".
Мне максимально похрен на их попытки, поэтому просто сообщаю о ситуации тем, кто будет не разбираясь бежать минусовать заминованной и плюсовать заплюсованной.
Ну, если бы вы её открыли, то увидели бы, что это агитка Интела как раз, где они на порядки ускоряют отдельные функции, это не тоже самое, что "ускорить питон в 20 раз", если у вас конечно код не состоит из бесконечного цикла вычисляющего арккосинус на массивах :) И это кажется сравнение с полным отсутствием векторизации, даже не AVX2 vs AVX512
Опять же, терминальное невежество и любимые сказки про "бесконечные циклы". Надо ещё про наносекунды с казать. Только в avx512 мы получили доступ к нормальному умножению из плавучки, а не костылю. С учётом fma и x2 шириной - это даёт даже не 2 и не 4 раза.
Я понимаю недовольство тем, что Интел не даёт всё и сразу и желательно подешевле, особенно когда оно есть в железке физически
Я не понимаю кто и зачем начал это плюсовать? Ведь здесь каждое откровение - невежество в терминальной стадии.
Вот опять же, кто хочет и чего подешевле? Вот мне нужена железяка с avx512. Я не хочу платить 500-2k баксов в месяц за дедик на aws, который к тому же, неудобно использовать.
Покупать хеоны мне неупало, потому что это мусор. Хеоны с настящим avx512 не бывают с нормальной частотой, а использовать 2-3гцц днище на десктопе, да ещё и с мусорной памятью невозможно.
Я бы купил ака-декстопный интеловский огрызок, но он мёртвый. Интел под него новое железо не выпускает. Это моя вина?
а на то, как всё это железо будет использоваться в реальности и кому продаваться, то можно увидеть, что в большинстве случаев разница будет едва ли не в пользу потребителя — и отсутствия AVX-512 никто не заметит и в лимит AVX 5.1Ггц не упрётся (у меня i5-12600k и он на "штатных" 4.6ГГц и "супербашне" прыгает до 100 градусов за 1 секунду в ycruncher'e).
Опять же, очередной пример невежества и отствия дружбы с логикой. Интел как раз таки и отключает это, потому что это как раз таки очень много кому нужно. Если было бы ненужно - не отключал бы, очевидно. Зачем делать что-то, если можно не делать с тем же результатом? Это тупо невыгодно.
Кстати, я помню таких же фанбоеев, которые мне рассказывали куллстори про "у интела были причины", когда интел прокидал меня с z270.
И сегментация рынка не только лишает домашних потребителей "энтерпрайз" фичей, но и защищает этих самых домашних потребителей от энтерпрайз закупщиков.
Нет, никаким образом. Кстати, как то быстро меняется история. То вдруг "это никому ненужно", а теперь уже "защищает". Зачем защищать?
Или вы бы хотели, чтобы в процессорах за 300 баксов был полный фарш и это было бы идеальным решением для массового серверного рынка? Посмотрите на видеокарты и поймете, что случилось бы в такой ситуации.
Ничего бы не случилось. Ситуация с видеокартами никак не связана с майнингом. Она связана с глобальными проблемами и созданием искусственного дефицита. При этом кому нужно всё вполне отгружается.
Но рассуждения глупость не поэтому. Есть количество процессоров, где интел продаёт n + m, есть два рынка. Есть все резко свичнутся в n, то ничего не изменится. Просто m никто не будет покупать и интел не будет выпускать m.
Только интел этого делать не будет и будет специально создавать дефицит, именно потому, что это невыгодно.
Вот просто пример с видеокартами. Себестоимость производства любых чипов практически одинакова, как минимум она одинакова для одинаковых чипов. Внимание вопрос - зачем нвидия выпускает всякий мусор, если можно выпускать только топ-карты? Будут покупать столько же, а навара больше.
Правильно, потому что нвидии невыгодно, чтобы у пользователя были жирные видюхи. Они хотят в это время как можно больше заматать дерьма, чтобы в последующем у купившик какой-то огрызок был стимул купить новое.
Поэтому нвидия будет продавать те же чипы, только максимально обрезанные. Рассказывая эти сказки про "брак" и прочую чушь.
Смешно же про серверы, которым прям так нужен этот AVX-512 и которые вместо зионов бы корки брали.
Причём тут сервера и он нужен нетолько на сервере, к тому же нужно начать с изучения вопроса. Там на половине этих хеонов никакого реального авх512 нет.
Если говорить про десктоп, то никаких авх512 здесь нет вообще. Это была единственная надежа. Единственное, где можно что-то получить - это на мёртвой платформе с протухшем скайлеком.
Во-первых, на подавляющем большинстве серверов (хоть нормальных, хоть "хетзнеровских" десктопах) крутить AVX-512 — последнее, что является приоритетом при выборе процессора, 99% это всякие веб-сервера, БД и прочее.
Терминально невежество. Симды используются везде. Даже с таком днище как веб-серверы, которыми мир не ограничивается. Как минимум там есть криптография, типичный дефолт чача+поли раза в 2 быстрее скалярных аналогов. И то лишь потому, что в интелел есть циклический сдвиг, а всимдах нет. Всё это скейлится линейно практически. Там есть работа со строками, которые либо реалузются симдами, либо форвардятся в glibc.
Не говоря уже о всяких мемсетах/мемкопи, которые процентов 20 времени месят эти "серверы".
Ради идентереса можете пойти посмотреть бенчмарки glibc vs ембедед-поделки, в том числе и в чём-то реальном. Основная разница - это симды.
Во-вторых, даже если это был бы numpy во все поля, то 99% тупо ставят его из пакетов и почти никто и никогда не собирает под конкретную платформу, а никаких готовых сборок под AVX-512 днём с огнём не найти.
Ещё более терминальное невежество. Нормальный компилятор умеет в сборку под множество таргетов и выбор нужного клона в рантайме. Так это сделано в той же glibc. Так же это, скорее всего, сделано и в numpy. В любом случае, кому нужно - тот накатит.
Как специалист говорю, не верите?
Мне уже откровений выше достаточно, но я не поленился погуглить:
At runtime import, the CPU is probed for the set of supported CPU features. A mechanism is used to grab the pointer to the most appropriate kernel, and this will be the one called for the function.
Там максимально невнятно написано, но судя по всему это есть. Опять же, специалиста видно издалека.
Зайдите в ods.ai и устройте опрос в канале hardware сколько процентов хоть раз собирало хоть что-нибудь под свою конкретную платформу и кому в жизни помешало отстутствие avx512 или кто десктопные камни в серверы пихал, особенно с разгоном AVX до 5.1. Не нравится ods, давайте другое, более релевантное по вашему мнению сообщество опросим.
Зачем мне опрашивать какое-то "сообщество", которое, особенно в случае с питоном, на 95% состоит из студентоты, которое ищет то как сбацать лабу. И никакой ЦА бизнеса интела не является.
Про лимит разгона AVX до 5.1ГГц. Мало ли какие у Интела были причины это сделать? Может там уже сигналы разваливаются при большей частоте? Или локальное тепловыделение настолько высокое, что какие-то части успевают критически нагреться или ещё что угодно? Справедливости ради, в оригинальной статье Игорь упоминает, что эти лимиты и раньше были и возможные причины перечисляет и предлагает как было бы лучше коммуницировать эту информацию со стороны Интела, вовсе не брызжет кислотой о том, какой Интел "грязный".
Причины тому очевидны и они правильно описаны в статье. Никаких иных причин нет и быть не может. Частота ни на что не влияет, при прочих равных. Сказки про перегрев не работают, потому как есть генерируемое, а есть отводящиеся тепло. Нет смысла ограничивать первое, когда второе изменяется. Т.е. при более худшем охлаждении будут всё те же эффекты на более низкой частоте.
Так про то и речь — ваши примеры не имеют никакого смысла и являются прямой подменой тезиса.
Ну зачем же так позориться. Я понимаю, что группа поддержки меня заминусует в любом случае, а никто даже разбираться не будет, но.
Если они являются подменой и смысла не имеют, то зачем вы наделяли их смыслов, утверждая, что что я утверждал "вывод типа возврата - это сфинае". Как так вышло? Вначале было одно, а когда я доказал несостоятельность этих обвинений вдруг смысл потерялся? Как же так?
Далее пошла типичная игра в отрицание. Примеры не примеры. "вы всё врёти" и прочие куллстори. Почему, в чём? Он попытался один раз, не смог и всё? Можно об этом забыть.
Мой пример максимально корректен. Именно поэтому против него ничего не выдвигается. Только нелепые оправдания.
То есть, как это всё работало до C++11, вы не знаете? Ну ок, буду иметь в виду и не буду приводить смущающие вас примеры, хорошо.
Типичная методичка "да ты ничего не знаешь". Самое интересное, что вначале он рассказывал "да оно никак не связано", теперь вдруг начал уже доказывать связь. Там нужно определиться. Есть связь, либо нет.
К тому же, даже если бы там была какая-то связь - её нет. Это не более чем нелепая попытка придумать оправдание. Потому что пример взят отдельный. Никакой связи не предполагающий. Любы попытки вывести эту связь - мало того, что не имеют смысла - являются не более чем попыткой забалтывания.
У вас котёнкодверцевые аналогии, чего вы хотели?
Да, да. Это оказывается я виноват в том, что он нёс чушь. Для тех, кто хочет поиграться может задать ему вопрос "если ты утверждаешь, что связь есть. Ты её нашёл потому что мои аналогии плохи - продемонстрируй ту логическую цепочку, которая привела тебя к "вывод типа возврата - сфина"?".
Я вам уверяю - он тут же потеряется. Потому что ответа нет и быть не может. Он просто приучен нести любую херню, потому что есть группа поддержки которая будет мня минусовать в любом случае, а его плюсовать в любом случае.
Поэтому он будет орать "идиот" и прочее, обвиняя меня в том, что я назвал его "адептом" и это его оскорбило. Да.
SFINAE предназначен не только и не столько для вывода возвращаемых значений функции (хотя в до-C++11-ые времена так чаще всего делали SFINAE — обновите свои методички).
На этом можно закончить. Здесь без диагноза не обойтись.
Читаем что я писал:
Представьте что у вас есть механизм возвращающий тип возврата функции, допусти get_return_type(f);
И что перед этим:
Но даже максимально далёкий от C++ человек знает чем по сути является sfinae в данном контексте - это механизм интроспекции кода.
Здесь где-то сказано, что сфинае является неким механизмом, механизмом А. Далее я сообщил, что представим, что есть другой механизм, возвращающий тип возврата функции. Я привёл в пример другой механизм, которого даже в C++ не существует, потому как функция в C++ не может возвращать тип. И в принципе такого механизма нет, даже если бы и могли.
Далее там даже есть:
Как в ситуации get_return_type(foo)
Здесь идёт явно противопоставление двух ситуаций. Т.е. никаким образом имея хоть что-то в голове невозможно вывести то, что я где-то связывал эти два явления и сообщал о том, что get_return_type это сфинае.
Он просто несёт рандомную херню. Максимальную чушь.
Мне просто интересно - кто ЦА данного персонажа? Он ведь даже в логику на уровне начальной школы не может.
и SFINAE по
О пишет что-то по sfinae, ладно он нихрена не понимает что это и как работает. Какие-то лозунги уровня qt-джуна есть, не более.
Но даже максимально далёкий от C++ человек знает чем по сути является sfinae в данном контексте - это механизм интроспекции кода.
А теперь просто подумайте о том какую чушь он несёт. Он обвиняет сфинае как механизм интроспекции кода за то, что он ловит изменение семантики языка.
Это, наверное, сложно. Представьте что у вас есть механизм возвращающий тип возврата функции, допусти get_return_type(f); Есть в языке функция foo, которая возвращает int. Пациент где-то зарадкодил этот int, а после у функции поменяли возвращаемый тип на size_t и get_return_type(foo) стал возвращать size_t.
И теперь пациент обвиняет get_return_type в том, что он не возвращает старый тип. Хотя он делает то, что нужно.
А почему он несёт подобную херню? Потому что это адепт с магическим сознанием. Он взял из интернета какой-то лозунг. Взял своё нелепое представление о sfinae. Т.е. для него это какая-то магия, которая непонятно что делает.
Как в ситуации get_return_type(foo) - он просто спастил это из интернета и воспринимает как "всегда возвращает int". Ему там неважно что и почему. В его пустом сознании это просто алиас на инт. А когда он перестал быть интом - у него возникли проблемы. Противоречия именно между его представления и реальность. При этом в реальности противоречий они есть лишь в его методичке.
Концепты времён 0x были максимально примитивным мусором. Сложно там было то, что они были убожество + вводили всякую рантайм-херню.
Про то, что там были какие-то проверки до - это полнейшая чушь. Там был специальный костыль, который позволял из концепта получить базовый класс, которым уже после наследовать.
Но даже тогда это понималась за полнейший треш и предлагалось ввести всё это автоматически во время инстанцирования.
Так же, тогда ещё не был сформирован С++. Была предпринята попытка описывать интерфейсы как в бездарной скриптухи - т.е. через сигнатуры.
Как только появилось auto/decltype и сформировался язык в современном виде. Сразу стало понятно, что сигнатуры мусорные работают только в помойной скриптухи.
Какая-нибудь универсальный сигнатура с деклтайпами и прочим - создаёт невозможную для описания сигнатуру. Попробуйте написать сигнатуру для какой-то сложной функции - это невозможно.
Поэтому описание интерфейсов декларативны. Мы не описываем сигнатуры как в бездарной скриптухе, а просто использует что-то так, как оно должно использоваться.
Кстати, этот пример максимально показателен. Генерики/интерфейсы в скриптухе обусловлены только одним - её бездарностью и примитивностью. И когда С++ был таким же оно пыталось использовать те же подходы.
И не потому, что скриптуха. А потому что оно примитивное и вариант там один.
При это подобные куллстори ещё кое как работали бы в C++, но в расте - примитивной скриптухи с убогой системой типов. Да и даже в рамках С++ это был бы максимальный мусор, а в расте это х10 мусор.
Нет, anyhow именно затирает типы. Восстановить тип исключения вы тоже можете. Я не понимаю, зачем вы все пытаетесь оправдываться? Есть чёткий критерий - вы либо следуете ему, либо нет.
Можно описать свой собственный большой enum с ошибками, и задать правила конвертации всех возможных в него.
Зачем вы мне пытаетесь рассказывать то, что максимально очевидно, что максимально тупо. И самое важное это то, что этот вариант был описан мною выше.
Почему вы говорите со мною с позиции будто вы что-то знаете а я нет?
По поводу этого ахренительно решения - это полный и тотальный мусор. Во-первых с таким же успехом вы можете создать глобальный общий тип для исключений и кидать везде его. Это уже умножает все рассуждения на ноль.
Во-вторых - это подтверждает мой тезис, что изначальная системы мусор. Что никакой типизации нет. Никакого паттрн-матичинга нет. Никакого тайпсейфа нет. И вы родили то, что используется в сишке уже тысячи лет. И это максимально тупое решение.
Третье, как уже выше сказано - в данной модели мы не можем обработать какую-то ошибку выше. Она всё равно останется в типе.
Каждая функция у нас возвращает все возможные типы ошибок. Даже те, которые она никогда не кидает. Здесь сразу же ломается методички result-адептов на тему известности списка ошибок, которые кидает функция. Т.е. мы знаем типы ошибок, которые кидает что угодно, но не конкретная функция.
Как результат наш код не имеет какой-то изоляции. Мы обязаны все ошибки заносить себе. Допустим, у нас есть какая-то функция foo из одного модуля и bar из другого. Мы не можем вызвать foo из bar. Мы будем обязаны захардкодить bar за глобальный тип. Тем самым потерять любую изоляцию.
Ошибок эти может быть миллион. Да, максимально удобно смотреть на помойку из сотен ошибок. Из всей программы и из всех либ.
Без относительно той чуши, что он написал. У шаблонов нет никаких проблем с "понятным". Никогда никакого подобного запроса нет, а те, кто об об этом вопрошают - не понимают не шаблоны, а полиморфизм.
чтобы автодополнение там можно было прикрутить
Они итак прикручивается, для этого никакие концепты не нужны. Это ведь не скриптуха.
Что именно мешало так сделать, это же логично?
То, что это полиморфный язык. Если попроще, то никакие тайпклассы и прочий мусор ненужны для той чуши, которую вам несёт пропаганда.
Генерики работают через стирание типов. Чтобы использовать свойства стёртого типа - их нужно аннотировать типом. Для этого и служат всякие тайпклассы/трейты/интерфейсы и прочие подобные сущности.
Каждая из этих херней мономорфна, когда в том же расте пишется T: A; x: T - то любой доступ к x производится через интерфейс A. Этот А мономорфен, т.е. на все типы там один интерфейс.
Подобная модель максимально примитивна и не требует тайпчекинга. Так же она максимально просто ложится на вывод типов из фп и прочей скриптухи, потому как этот вывод типов не может в полиморфизм by-design.
Т.е. если C++ нужно протайпчекать всё, проверить действительно ли что-то соответствует чему-то. А так же типы не ограничены одним интерфейсом.
То вот в скриптухи ничего этого делать ненужно. Вы сами аннотируете любой тип интерфейсом. И только тогда нужно проверить, что он соответствует. Проверка там максимально тупая - достаточно просто сравнения сигнатур+имени. Сигнатуры там максимально примитивны.
Внутри самих генериков так же ничего тайпчекать ненужно. Просто проверяется есть ли нужное свойство у интерфейса.
Когда вы передаёте что-либо в генерик-функцию проверка ещё более тривиальна - просто посмотреть список того, что имплементировано для типа. Есть ли там такой же интерфейс.
В С++ есть подобная модель - это виртуальные методы + базовые классы в качестве интерфейсов.
Подобная модель ваяется любым студентов на коленке. Крестовая же модель настолько сложна, что её реализовать для него уже в принципе невозможно. А именно подобные и пишут всякие хаскели/расты.
Аналогичная ситуация с тем же синтаксисом в C/C++. Распарсить синтаксис хаскеля, раста и прочей скриптухи - с этой задачей справивиться любой студент. Там грамматика максимально примитивная, нет какой-либо контексто-зависимости, либо сложной контексто-зависимости.
Распарсить же даже сишный синтаксис достаточно нетривиально. Не говоря уже о крестовом. Именно поэтому вы не увидите ничего, кроме паскалятины, в любых академических поделках. Да и 99% языков.
Именно потому, что это проще. Именно потому, что это доступно. Это единственная и основная причина. Всё остальное - оправдания.
Потому что с чего оно должно возвращать 0, если ноль - это пустая строка?
Заменять 2-3строчки на одну - это всегда такая себе затея. Она превращает язык в помойку. Когда бездумно добавляется сахар ради сахара.
Если на языке можно реализовать ? - это хорошо. Если же ? это просто костыль на уровне компилятор, то это плохо. В язык нужно добавлять возможности через которые уже реализуется сахар. А не просто сахар.
Потому добавление сахара - это проблема. И потому, что весь не добавишь. И потому что это идёт в ущерб фичам. Здесь достаточно посмотреть на раст. Где примитивного саха много, а фичей мало.
На уровне пропаганды заявляет о "сохранении типов", в реальности практически любой код на расте использует затирание типов в ошибок.
Есть маргинальные решения где через костыли на макросах пытаются мержить емамы, но это никто не использует в реальности. По крайней мере я такого не видел.
Это то самое box dyn err.
Везде, особенно в раст. Да, в более-менее адекватных фп-языках уже давно эмулируют перегрузку через pm. Это куда удобнее, чем искатаь match в лапше. Но там есть всё те же проблемы с тем, что их нельзя расширять из пользовательского кода.
Проблема только в том, что на функциональных языках программирования ничего не написано. А что пишется - там уже работает естественный отбор.
Допустим, каждый последователь расскажет, что у него там "чистый фп-язык" - все дела. Но в реальности, когда он идёт писать код - всё забывается. И уже язык становиться мультипарадигмальным, а массив всегда был в фп.
Неважно что "ты" считаешь и как думаешь. Есть то, что работает, а что не работает. И когда кто-то начинает что-то делать - реальность всегда вносит коррективы. И вот фп уже не фп. И пм уже не пм.
Не больше. fn в отличии от auto в цпп - это костыль, который обусловлен слабостью "парсера". -> в цпп имеет смысла, когда как в расте - это просто костыль, потоу как лево всегда занято костылём ввиде fn/let и прочего.
Право используется потому, потому как это даёт возможность использовать парметры как часть типа. Допустим `(auto x) -> decltype(x.err)`
Поэтому, допустим, сущуествует template<>. Оно нужно для того, чтобы можно было определить теплейт-параметр до типа возврата. `T <T>f` - такое написать нельзя. Более-менее смышлёные последователи права ссылаются на то, что право у них по этой причине. Нет. Право там именно потому, что fn.
Про fn - это пошло ещё с паскаля, как пример максимально примитивного парсинга. Суть там простая. У нас есть описание неких грамматических правил и нам нужно узнать то, какому правилу соответствует набор токенов, в простом случае.
Вот самый просто способ - это максимально сильно упрощать грамматику, уменьшая коллизии в правилах. А когда от них уйти нельзя - просто тупо писать идентификатор правила слева.
Т.е. все эти fn/let и прочее - это синтаксический мусор, который не имеет никакого смысла, кроме как для упрощения разбора. Упрощение разбора никогда актуальным не являлось. Поэтому все сказки "это для оптимизации" - являются чушью. Достаточно посмотреть на время компиляции раста. Это экономия на спичках, которая крайне сомнительна.
Подобный подход - удел студентов, которые только начинают писать языки.
Сейчас очень часто можно видеть использование auto -> в цпп. Это просто пропагандисткий причём призваный сместить внимание с отстутствия вывода типа возврата в расте. Потому как писать подобным образом смысла не имеет, а когда имеет - аналога в расте существовать не может в силу его скудных возможностей.
Нет, просто раст куда более ограничен. От этого там существует тысячи костылей, где никакой компилятор ничего не энфорсит, кроме обёрток над ансейф-костылями.
sv - это какая-то часть строки. Этих частей много. С чего вдруг это должно "энфорсить" иммутабельность на исходную строку? Ни с чего.
Это вью на кусок памяти и, очевидно, что никаким образом ничего не говорит и не должно говорить о том, что этот кусок памяти меняться не должен.
А почему там что-то "энфорсится" - потому что это максимально примитивная реализация. Более примитивного ничего придумать невозможно. И причина этого не в том, что это какое-то "человеколюбие" - как раз таки всё наоборот. Его там нет. На человека там сброшена задча мучится с этими костылями.
Используется подобная максимально примитивная схема потому, что она элементарно реализуется, а возможности реализовать что-то больше не было. Да и нет.
Такая же ситуация с -> и остуствием вывода типа возврата. Просто не смогли, а все рассуждения "чтобы видеть типы" - это сказки для бедных и оправдания. Почему же тогда у лямбды есть вывод типов?
И сказки про "лямбда это лямбда" - такие же сказки, потому как вывод типов в лямбде есть потому, что костылём эта лямбда просто воспринимается как кусок кода. Т.е. она не-полиморфна.
Поэтому, даже если принять оправдание "лямбда это лямбда", то почему же лямбда не полноценно? Почему я не могу написать `let id = |x| x; id(10); id(10.);`
? - это костыль, который лишь говорит о том, где все сказки "удобно, пм - круто" были фейком. Можно почитать то, что пели последователи result до ?.
Если говорить о реальном коде, особенно о C++(где есть полиморфизм и куда более мощная ситема типов, нежели в раст), то ? становиться бесполезным.
Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать
{first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.pm достаточно слабая концепция, которая во много неполноценна. А уж тем более в C++, если есть полиморфизм и перегрузка.
Поэтому в том же расте за пределами очевидных учебных примеров pm используется редко. Везде используются трейты.
Одна из причин - не расширяемость. pm работает всегда только по закрытому типу, который зачастую объявлен где-то в кишках какой-то библиотеки. Расширить его нельзя. Никак.
Трейт/перегрузку(трейты в расте это такая попытка реализовтаь перегрузку из цпп) это делать позволяют. Т.е. где-то в пользовательском коде можно написать impl чего-то, либо перегрузку.
Тем, что он влияет на анализатор. Точно так же как и throw. https://godbolt.org/z/fshW7Wodz - максимально простой пример. Конечно, в реальности контексты использования более сложные, но суть такая же.
Т.е. мы точно знаем, что код сюда не дойдёт, но это нигде не отражено на уровне типов. Не написать код мы не можем - это будет не-полное использование и компилятор будет ругаться.
Так же в некоторых случаях компилятор просто не может вывести это из кода. Допустим из произвольного asm. Тот же noreturn применяется для того же.
Конечно, куда лучше было бы ограничить это где-то сверху и далее информацию передать через типы, но такого нет.
Предположим, что код с интами работает быстрее, а отрицательные числа нам ненужны. Заменить на uint32_t нельзя - будет медленее. Но компилятор всегда будет предполагаеть наличие их.
Поэтому можно сделать if(x < 0)
__builtin_unreachable(); либо if(x >= 0) else __builtin_unreachable()Это поможет куда лучше оптимизировать код.
Это обёртка над тем, что уже тысячи лет в нормальных компиляторах, а именно
__builtin_unreachableКакую лексику? Подробнее. Какой троллинг? Насколько же интел/невежества-боты предсказуемы. Ещё под какого-то наблюдателя косит. Очевидно подобному персонажу "без разницы" прав кто-то либо нет, в том числе и он сам.
Как же усиленно интел-боты и фанаты невежества гадят в карму. Что им ещё делать, кроме как затыкать неугадных и даже не пытаться что-то ответить.
И никак же они усиленно плюсуют того, кто попросту врёт и враньё кого опровергается за 2минут использования гагла(привете avx и numpy).
Фиксирую так же то, как они будут оправдываться, раскказывая, что гадят они потому, что я как-то их оскорбил. И это будет очередным враньё, потому как об этом:
Да, именно называние оппонентов обиженными подростками - это то самое глушилово неугодных. При этом ладно бы этому были какие-то пруфы, как это сделал я в случае с "терминальными невежеством".
Мне максимально похрен на их попытки, поэтому просто сообщаю о ситуации тем, кто будет не разбираясь бежать минусовать заминованной и плюсовать заплюсованной.
Опять же, терминальное невежество и любимые сказки про "бесконечные циклы". Надо ещё про наносекунды с казать. Только в avx512 мы получили доступ к нормальному умножению из плавучки, а не костылю. С учётом fma и x2 шириной - это даёт даже не 2 и не 4 раза.
Я не понимаю кто и зачем начал это плюсовать? Ведь здесь каждое откровение - невежество в терминальной стадии.
Вот опять же, кто хочет и чего подешевле? Вот мне нужена железяка с avx512. Я не хочу платить 500-2k баксов в месяц за дедик на aws, который к тому же, неудобно использовать.
Покупать хеоны мне неупало, потому что это мусор. Хеоны с настящим avx512 не бывают с нормальной частотой, а использовать 2-3гцц днище на десктопе, да ещё и с мусорной памятью невозможно.
Я бы купил ака-декстопный интеловский огрызок, но он мёртвый. Интел под него новое железо не выпускает. Это моя вина?
Опять же, очередной пример невежества и отствия дружбы с логикой. Интел как раз таки и отключает это, потому что это как раз таки очень много кому нужно. Если было бы ненужно - не отключал бы, очевидно. Зачем делать что-то, если можно не делать с тем же результатом? Это тупо невыгодно.
Кстати, я помню таких же фанбоеев, которые мне рассказывали куллстори про "у интела были причины", когда интел прокидал меня с z270.
Нет, никаким образом. Кстати, как то быстро меняется история. То вдруг "это никому ненужно", а теперь уже "защищает". Зачем защищать?
Ничего бы не случилось. Ситуация с видеокартами никак не связана с майнингом. Она связана с глобальными проблемами и созданием искусственного дефицита. При этом кому нужно всё вполне отгружается.
Но рассуждения глупость не поэтому. Есть количество процессоров, где интел продаёт n + m, есть два рынка. Есть все резко свичнутся в n, то ничего не изменится. Просто m никто не будет покупать и интел не будет выпускать m.
Только интел этого делать не будет и будет специально создавать дефицит, именно потому, что это невыгодно.
Вот просто пример с видеокартами. Себестоимость производства любых чипов практически одинакова, как минимум она одинакова для одинаковых чипов. Внимание вопрос - зачем нвидия выпускает всякий мусор, если можно выпускать только топ-карты? Будут покупать столько же, а навара больше.
Правильно, потому что нвидии невыгодно, чтобы у пользователя были жирные видюхи. Они хотят в это время как можно больше заматать дерьма, чтобы в последующем у купившик какой-то огрызок был стимул купить новое.
Поэтому нвидия будет продавать те же чипы, только максимально обрезанные. Рассказывая эти сказки про "брак" и прочую чушь.
Причём тут сервера и он нужен нетолько на сервере, к тому же нужно начать с изучения вопроса. Там на половине этих хеонов никакого реального авх512 нет.
Если говорить про десктоп, то никаких авх512 здесь нет вообще. Это была единственная надежа. Единственное, где можно что-то получить - это на мёртвой платформе с протухшем скайлеком.
Терминально невежество. Симды используются везде. Даже с таком днище как веб-серверы, которыми мир не ограничивается. Как минимум там есть криптография, типичный дефолт чача+поли раза в 2 быстрее скалярных аналогов. И то лишь потому, что в интелел есть циклический сдвиг, а всимдах нет. Всё это скейлится линейно практически. Там есть работа со строками, которые либо реалузются симдами, либо форвардятся в glibc.
Не говоря уже о всяких мемсетах/мемкопи, которые процентов 20 времени месят эти "серверы".
Ради идентереса можете пойти посмотреть бенчмарки glibc vs ембедед-поделки, в том числе и в чём-то реальном. Основная разница - это симды.
Ещё более терминальное невежество. Нормальный компилятор умеет в сборку под множество таргетов и выбор нужного клона в рантайме. Так это сделано в той же glibc. Так же это, скорее всего, сделано и в numpy. В любом случае, кому нужно - тот накатит.
Мне уже откровений выше достаточно, но я не поленился погуглить:
Там максимально невнятно написано, но судя по всему это есть. Опять же, специалиста видно издалека.
Зачем мне опрашивать какое-то "сообщество", которое, особенно в случае с питоном, на 95% состоит из студентоты, которое ищет то как сбацать лабу. И никакой ЦА бизнеса интела не является.
Причины тому очевидны и они правильно описаны в статье. Никаких иных причин нет и быть не может. Частота ни на что не влияет, при прочих равных. Сказки про перегрев не работают, потому как есть генерируемое, а есть отводящиеся тепло. Нет смысла ограничивать первое, когда второе изменяется. Т.е. при более худшем охлаждении будут всё те же эффекты на более низкой частоте.
Ну зачем же так позориться. Я понимаю, что группа поддержки меня заминусует в любом случае, а никто даже разбираться не будет, но.
Если они являются подменой и смысла не имеют, то зачем вы наделяли их смыслов, утверждая, что что я утверждал "вывод типа возврата - это сфинае". Как так вышло? Вначале было одно, а когда я доказал несостоятельность этих обвинений вдруг смысл потерялся? Как же так?
Далее пошла типичная игра в отрицание. Примеры не примеры. "вы всё врёти" и прочие куллстори. Почему, в чём? Он попытался один раз, не смог и всё? Можно об этом забыть.
Мой пример максимально корректен. Именно поэтому против него ничего не выдвигается. Только нелепые оправдания.
Типичная методичка "да ты ничего не знаешь". Самое интересное, что вначале он рассказывал "да оно никак не связано", теперь вдруг начал уже доказывать связь. Там нужно определиться. Есть связь, либо нет.
К тому же, даже если бы там была какая-то связь - её нет. Это не более чем нелепая попытка придумать оправдание. Потому что пример взят отдельный. Никакой связи не предполагающий. Любы попытки вывести эту связь - мало того, что не имеют смысла - являются не более чем попыткой забалтывания.
Да, да. Это оказывается я виноват в том, что он нёс чушь. Для тех, кто хочет поиграться может задать ему вопрос "если ты утверждаешь, что связь есть. Ты её нашёл потому что мои аналогии плохи - продемонстрируй ту логическую цепочку, которая привела тебя к "вывод типа возврата - сфина"?".
Я вам уверяю - он тут же потеряется. Потому что ответа нет и быть не может. Он просто приучен нести любую херню, потому что есть группа поддержки которая будет мня минусовать в любом случае, а его плюсовать в любом случае.
Поэтому он будет орать "идиот" и прочее, обвиняя меня в том, что я назвал его "адептом" и это его оскорбило. Да.
На этом можно закончить. Здесь без диагноза не обойтись.
Читаем что я писал:
И что перед этим:
Здесь где-то сказано, что сфинае является неким механизмом, механизмом А. Далее я сообщил, что представим, что есть другой механизм, возвращающий тип возврата функции. Я привёл в пример другой механизм, которого даже в C++ не существует, потому как функция в C++ не может возвращать тип. И в принципе такого механизма нет, даже если бы и могли.
Далее там даже есть:
Здесь идёт явно противопоставление двух ситуаций. Т.е. никаким образом имея хоть что-то в голове невозможно вывести то, что я где-то связывал эти два явления и сообщал о том, что get_return_type это сфинае.
Он просто несёт рандомную херню. Максимальную чушь.
Мне просто интересно - кто ЦА данного персонажа? Он ведь даже в логику на уровне начальной школы не может.
О пишет что-то по sfinae, ладно он нихрена не понимает что это и как работает. Какие-то лозунги уровня qt-джуна есть, не более.
Но даже максимально далёкий от C++ человек знает чем по сути является sfinae в данном контексте - это механизм интроспекции кода.
А теперь просто подумайте о том какую чушь он несёт. Он обвиняет сфинае как механизм интроспекции кода за то, что он ловит изменение семантики языка.
Это, наверное, сложно. Представьте что у вас есть механизм возвращающий тип возврата функции, допусти get_return_type(f); Есть в языке функция foo, которая возвращает int. Пациент где-то зарадкодил этот int, а после у функции поменяли возвращаемый тип на size_t и get_return_type(foo) стал возвращать size_t.
И теперь пациент обвиняет get_return_type в том, что он не возвращает старый тип. Хотя он делает то, что нужно.
А почему он несёт подобную херню? Потому что это адепт с магическим сознанием. Он взял из интернета какой-то лозунг. Взял своё нелепое представление о sfinae. Т.е. для него это какая-то магия, которая непонятно что делает.
Как в ситуации get_return_type(foo) - он просто спастил это из интернета и воспринимает как "всегда возвращает int". Ему там неважно что и почему. В его пустом сознании это просто алиас на инт. А когда он перестал быть интом - у него возникли проблемы. Противоречия именно между его представления и реальность. При этом в реальности противоречий они есть лишь в его методичке.
Типичный слив.
Какие фичи? Рассуждения уровня слышал звон? Перечисляй 90%.
Концепты времён 0x были максимально примитивным мусором. Сложно там было то, что они были убожество + вводили всякую рантайм-херню.
Про то, что там были какие-то проверки до - это полнейшая чушь. Там был специальный костыль, который позволял из концепта получить базовый класс, которым уже после наследовать.
Но даже тогда это понималась за полнейший треш и предлагалось ввести всё это автоматически во время инстанцирования.
Так же, тогда ещё не был сформирован С++. Была предпринята попытка описывать интерфейсы как в бездарной скриптухи - т.е. через сигнатуры.
Как только появилось auto/decltype и сформировался язык в современном виде. Сразу стало понятно, что сигнатуры мусорные работают только в помойной скриптухи.
Какая-нибудь универсальный сигнатура с деклтайпами и прочим - создаёт невозможную для описания сигнатуру. Попробуйте написать сигнатуру для какой-то сложной функции - это невозможно.
Поэтому описание интерфейсов декларативны. Мы не описываем сигнатуры как в бездарной скриптухе, а просто использует что-то так, как оно должно использоваться.
Кстати, этот пример максимально показателен. Генерики/интерфейсы в скриптухе обусловлены только одним - её бездарностью и примитивностью. И когда С++ был таким же оно пыталось использовать те же подходы.
И не потому, что скриптуха. А потому что оно примитивное и вариант там один.
При это подобные куллстори ещё кое как работали бы в C++, но в расте - примитивной скриптухи с убогой системой типов. Да и даже в рамках С++ это был бы максимальный мусор, а в расте это х10 мусор.
Нет, anyhow именно затирает типы. Восстановить тип исключения вы тоже можете. Я не понимаю, зачем вы все пытаетесь оправдываться? Есть чёткий критерий - вы либо следуете ему, либо нет.
Зачем вы мне пытаетесь рассказывать то, что максимально очевидно, что максимально тупо. И самое важное это то, что этот вариант был описан мною выше.
Почему вы говорите со мною с позиции будто вы что-то знаете а я нет?
По поводу этого ахренительно решения - это полный и тотальный мусор. Во-первых с таким же успехом вы можете создать глобальный общий тип для исключений и кидать везде его. Это уже умножает все рассуждения на ноль.
Во-вторых - это подтверждает мой тезис, что изначальная системы мусор. Что никакой типизации нет. Никакого паттрн-матичинга нет. Никакого тайпсейфа нет. И вы родили то, что используется в сишке уже тысячи лет. И это максимально тупое решение.
Третье, как уже выше сказано - в данной модели мы не можем обработать какую-то ошибку выше. Она всё равно останется в типе.
Каждая функция у нас возвращает все возможные типы ошибок. Даже те, которые она никогда не кидает. Здесь сразу же ломается методички result-адептов на тему известности списка ошибок, которые кидает функция. Т.е. мы знаем типы ошибок, которые кидает что угодно, но не конкретная функция.
Как результат наш код не имеет какой-то изоляции. Мы обязаны все ошибки заносить себе. Допустим, у нас есть какая-то функция foo из одного модуля и bar из другого. Мы не можем вызвать foo из bar. Мы будем обязаны захардкодить bar за глобальный тип. Тем самым потерять любую изоляцию.
Ошибок эти может быть миллион. Да, максимально удобно смотреть на помойку из сотен ошибок. Из всей программы и из всех либ.
Без относительно той чуши, что он написал. У шаблонов нет никаких проблем с "понятным". Никогда никакого подобного запроса нет, а те, кто об об этом вопрошают - не понимают не шаблоны, а полиморфизм.
Они итак прикручивается, для этого никакие концепты не нужны. Это ведь не скриптуха.
То, что это полиморфный язык. Если попроще, то никакие тайпклассы и прочий мусор ненужны для той чуши, которую вам несёт пропаганда.
Генерики работают через стирание типов. Чтобы использовать свойства стёртого типа - их нужно аннотировать типом. Для этого и служат всякие тайпклассы/трейты/интерфейсы и прочие подобные сущности.
Каждая из этих херней мономорфна, когда в том же расте пишется
T: A; x: T- то любой доступ к x производится через интерфейс A. Этот А мономорфен, т.е. на все типы там один интерфейс.Подобная модель максимально примитивна и не требует тайпчекинга. Так же она максимально просто ложится на вывод типов из фп и прочей скриптухи, потому как этот вывод типов не может в полиморфизм by-design.
Т.е. если C++ нужно протайпчекать всё, проверить действительно ли что-то соответствует чему-то. А так же типы не ограничены одним интерфейсом.
То вот в скриптухи ничего этого делать ненужно. Вы сами аннотируете любой тип интерфейсом. И только тогда нужно проверить, что он соответствует. Проверка там максимально тупая - достаточно просто сравнения сигнатур+имени. Сигнатуры там максимально примитивны.
Внутри самих генериков так же ничего тайпчекать ненужно. Просто проверяется есть ли нужное свойство у интерфейса.
Когда вы передаёте что-либо в генерик-функцию проверка ещё более тривиальна - просто посмотреть список того, что имплементировано для типа. Есть ли там такой же интерфейс.
В С++ есть подобная модель - это виртуальные методы + базовые классы в качестве интерфейсов.
Подобная модель ваяется любым студентов на коленке. Крестовая же модель настолько сложна, что её реализовать для него уже в принципе невозможно. А именно подобные и пишут всякие хаскели/расты.
Аналогичная ситуация с тем же синтаксисом в C/C++. Распарсить синтаксис хаскеля, раста и прочей скриптухи - с этой задачей справивиться любой студент. Там грамматика максимально примитивная, нет какой-либо контексто-зависимости, либо сложной контексто-зависимости.
Распарсить же даже сишный синтаксис достаточно нетривиально. Не говоря уже о крестовом. Именно поэтому вы не увидите ничего, кроме паскалятины, в любых академических поделках. Да и 99% языков.
Именно потому, что это проще. Именно потому, что это доступно. Это единственная и основная причина. Всё остальное - оправдания.
Не может полиморфная концепция быть ближе к мономорфной.