Comments 178
Эхх, хочется компилируемый язык с легковесным синтаксисом в стиле Go, управлением ресурсами и безопасностью в стиле Rust и лаконичностью (без этих var, func, mut) C...
Оказалось, что сеть научается быстрее играть, если дать ей партии чемпионов… но также «научается плохому».
Как известно переучиться — сложнее, чем изначально научиться всё делать правильно… к нейронным сетям это, как оказалось, тоже относится…
Программисты всегда нужны, они знают суть. А от кодеров можно и избавиться, они всё равно только говнокод рождают, потому что не знают, как оно работает.
А этого никто не знает — обе сети чемпионов выносят «всухую».
И обе при этом иногда делают ходы, которые до этого десятилетиями считались «слабыми». Но одна-таки играет лучше, другая — хуже.
Это-то мы можем понять: для того, чтобы сказать, что Ма́гнус Ка́рлсен играет сильнее Васи Пупкина не нужно даже правил игры знать — достаточно посмотреть на резлуьтаты матчей… но вот почему так — достоверно неизвестно.
привет из будущего!
кто тут про нейронки скепсис сеял?
Если у вас слишком большие и сложные программы — то, может быть, вам нужно делать менее запутанный дизайн, а не искать более лаконичный язык?
Во-первых, абстрактная интерпретация. Во многих компиляторах Lisp и Scheme ей пользуются для оптимизации, в том числе и для выяснения, будет переполнение или нет в тех или иных случаях. Кстати, проверка и вывод типов — частный случай абстрактной интерпретации.
Во-вторых, некоторые JIT-компиляторы тоже проводят такой анализ переполнений.
Концептуальный вопрос языкотворчества, конечно, тут в том, а нужны ли программисту просто числа для работы (которые потом компилятор может реализовать в машинном представлении, если видит, что разрядности хватает), или ему обязательно нужны кольца вычетов по модулю 2^N для некоторых N?
Расскажите пожалуйста, как абстрактная интерпретация залезет в голову программисту и поймет, что каст с переполнением является умышленным или программист ошибся?
Что до лиспа, то учитывая что это бестиповое лямбда-счисление то там таких вопросов вообще не стоит: это уже в расширения System F надо смотреть. Нет типов — нет и проблем с кастами.
А зачем абстрактной интерпретации залезать в голову программиста? Обычно есть примитивные операции, вроде number->u8/saturating
, которые абстрактный интерпретатор понимает. При помощи таких операций программист может выразить своё намерение.
Lisp - это не чистое бестиповое Lambda-исчисление, а как минимум расширенное большим набором примитивных операций, поэтому динамическая типизация есть, вопросы возникают, и их решают теми или иными способами.
Но вообще статья странноватая. Взять два языка разного уровня и рассказывать, чего не хватает в низкоуровневом. Дык — коню понятно, чего не хватает: того, что добавлено в высокоуровневые языки. Думаю, в рекламке Rust все его преимущества описаны лучше и полнее, чем у товарища Федерико.
На чистом С еще много где нужно программировать — например, драйверы ядра писать.
Или на микроконтроллерах ковыряться — интернет вещей же, вычовычо.
Можно и на Rust. Ладно, патч в ядро не примут, а с AVR лучше переходить на STM32 и компанию.
Никто ведь не произнес слова AVR
Кое-кто произнёс "микроконтроллеры". Разве STM32 и AVR это не самое первое, что вспоминается на эту тему? Ну у меня так.
Чем он такой чудесатый, что нужно все бросать и на него переходить?
ТТХ либо сравнимо, либо сильно лучше при более низкой цене. Речь больше о том, что под AVR на Rust только при помощи костыльного https://github.com/avr-rust можно что-то делать. Могу ответить вам как фанбой фанбою: AVR ненужен ибо для прогания на оном при использовании Rust будет слишком много костылей. Вас устроит такой ответ? Лично для меня подобной проблемы вообще не существует. Ящитаю, что выбирать инструменты стоит из характера задач, а не по религиозным причинам.
У stm32, как и многих arm cortex-m очень всё богато с периферией, даже на самых мелких stm32f0 и stm32l0 (которые бывают как в tssop-20/tssop-14, который паяется относительно легко, так и в lqfp, qfn/qfpn и в bga-подобном wlcsp), в dip-корпусах, скорее всего что-то из cortex-m0/m0+ есть у других производителей. Для breadboard'ов вполне подходит вариант простой платы-переходника с tssop/soic на обычные 100mil/2.54, покупается где угодно (начиная от китайцев и заканчивая крупными радиорынками/чипидипом).
Например, stm32f031, который стоит 100-120 рублей, имеет:
- ядро arm cortex-m0 с нормальным интерфейсом внутрисхемной отладки swd (можно дебажить из ide, ставить полноценные аппаратные breakpoint'ы, смотреть регистры и память и т. п.), NVIC (nested vector interrupt controller);
- 9 таймеров (1x 24-bit systick; 1x advanced 7-ch 16-bit с PWM и deadtime generation; 1x 32-bit general purpose; 4x 16-bit general purpose; 2x watchdog);
- внутренний генератор (т. е. можно использовать crystal-less вариант);
- модуль расчёта crc32;
- spi/i2s, i2c/smbus/pmbus, usart;
- 12-bit ADC (12 каналов, из них 9 внешних, есть датчик температуры кристала);
- 15 GPIO;
- RTC;
- 5-ch DMA (могут использоваться как для обмена память-память, так и для обмена с периферией в обе стороны: spi, usart, i2c, adc, timers);
- управление питанием (различные варианты сна), включая поддержку питания RTC от батареи.
Чуть более мощные чипы имеют аппаратный usb.
Из важных особенностей:
- питание 2.0..3.6v (против более привычных 5v для avr);
- при использовании внутреннего генератора необходимо замыкать пару контактов на землю;
- крайне рекомендуются блокировочные конденсаторы по 100nF около каждого входа питания (на avr они тоже желательны, но он может быть менее чувствителен, но не всегда).
Стандартно в линейке у них есть группы одинаковых контроллеров с разным количество rom и, иногда, ram. Пример: stm32f103 в lqfp64 бывает в 7 вариантах от 6/16 до 64/512 kB RAM/ROM с постепенным увеличением количества периферии и функциональности.
Плюс есть почти pin2pin совместимость между чипами различных линеек в рамках некоторых групп (при том, что там будут разные процессорные ядра). Для этих случаев у них есть подробные application notes по совместимости. Например AN4904 подробно рассказывает что надо иметь на плате, чтобы можно было легким движением паяльника заменить stm32f1 на stm32f4, плюс описывает отличия в периферии, которые подробно описаны. Как минимум, легко переключаться между линейками f1, f2 и f4.
Вот все так напирают на дешевизну STM32, что попахивает манией.
И скажите сколько будет стоить аналогичная простеньким stm32f031 или stm32f103 mega/xmega? Всё-таки даже младшие f0 — это ни полраза не аналог attiny, которые имеют свою нишу.
А что насчет EEPROM?… Ставить отдельным корпусом? Серьезно? Или эмулировать флешом?
Кто вам мешает посмотреть на чипы другого производителя? NXP, Linear, TI? У некоторых на младших моделях вполне есть eeprom. Или использовать battery backup + глубокий сон, если хочется сидеть на stm32?
Переходник на DIP тоже совсем не бесплатный, кстати. В результате в сумме уже выходит дороже сравнимой атмеги. А гемору со сборкой больше в два с половиной раза просто сходу ни за что.
Сначала скажите что вы понимаете под "сравнимой атмегой". Обычно стоимость переходника/девборда и т. п. совсем нерелевантны, т. к. в готовое изделие это не пихается от слова совсем. Кто будет распаивать сначала tssop на переходник, напаивать ноги и потом паять получившийся dip вместо того, чтобы распаять сразу tssop?
И потерять два GPIO? Все ATtiny умеют работать xstal-less, а тот же 13 вообще не требует ни одной навесной детали для работы: только питание и прошивка. Из восьми ног 6 в распоряжении разработчика (5 если нужен RESET и/или ISP).
xstal-less — это только про отсутствие кристала (например, варианты с RC-цепочкой тоже можно назвать crystal-less), но это ничего не говорит про внешнюю коммутацию. Вы же не жалуетесь, что теряете две ноги на питание и землю? Так к чему переживать, что вам доступны 16 ног вместо 18, если на вашей attiny доступны всего 6?
Короче, из реально крутого вижу только отладку и DMA. В противовес — отсутствие EEPROM в нижне-средних линейках и крайне неприятные для ручного монтажа корпуса.
Если вам хватает attiny или аналогичных мелких pic'ов, то вообще не смотрите на мир за пределами 8 бит.
Обычно противопоставление avr/pic против cortex-m всплывает, когда народ начинает городить atmega328 в lqfp48+ или подобные большие xmega, реализует spi/i2c или тем более usb ногодрыгом и далее по тексту. И паять atmega в lqfp или stm32f1 — нет никакой разницы.
У меня складывается ощущение, что здесь есть только фанатичные защитники avr, которые игнорируют всю фактуру. Спрашивают про преимущества, но тут же их игнорируют. И их прям заставляют выкинуть все спроектированные устройства, все подобранные библиотеки и под дулом автомата перейти на сторону врагаstm32.
Если у вас плохо с памятью, процитирую (выделение моё):
AVR лучше переходить на STM32 и компанию
И что это за компания? На каком основании идет объединение производителей в компанию? А STM8 входит в эту компанию, или как?
Я предполагаю, что речь всё-таки шла о Cortex-M, можем спросить lain8dono. Из примеров: NXP, Atmel/Microchip, ST, TI, AD/Linear, Infineon. Приличное community по моим ощущениям у ST, NXP и TI.
От того, что «полностью разряженный» элемент разрядится еще на 0.2 вольта, никто не умрет, а устройство, между прочим, проработает лишний час. Вы, блин, еще заявите, что более высокий порог — это преимущество.
Откуда цифра в час? При каком потреблении? Вы это измеряли и можете привести пруф (и заодно опровергнуть разрядные кривые производителей)?
Элемент Ni-Cd/Ni-MH считается разряженным как раз при 0.9 вольта. Давайте, расскажите что это никому не нужно и какой я дурак.
При чём здесь NiCd/NiMH аккумуляторы? Вы в современном мире питаетесь от двух банок оного барахла? Так поставьте buck-boost + линейный ldo, если так приспичило и питайтесь хоть от одной банки.
Устройства с батарейным питанием коины не майнят, тактовую частоту при этом зачатую ставят в 32 килогерца, ибо больше не нужно.
Ага, и какой baudrate на usart/spi будет при 32kHz? 16 kbit/s в пределе (реально меньше, паузы, старт/стоп-биты и т. п.), все счастливы. А если вдруг нужно что-нибудь на обычный растровый tft вывести, так 32kHz вообще спасение. Поржал.
Прошивка подразумевает подключение к компьютеру, с которого можно взять 5 вольт абсолютно бесплатно, так что не аргумент.
С каких пор подразумевает? Удалённой прошивки устройств не бывает? Прошивки с sd-карты не бывает?
Вы забыли сказать, что до 1.95 вольта. Не напомните мне тип химического элемента, укладывающегося в данный диапазон?
Вы все устройства питаете без стабилизаторов? У вас у всех компонент высокая толерантность по питанию и входам/выходам? Вам очень повезло или у вас очень простые задачи. Радуйтесь. Но не стоит считать, что у всех в мире так.
Большинство ATtiny начинаются с 1.8 вольта.
Если для вас не проблема использовать 1.8, то не будет и проблемой использовать 3.3. Обычно у народа проблема использовать низкие напряжения, т. к. нужен внешний линейный стабилизатор, а вы выше очень негативно отзывались не только о внешних компонентах, но и о любых внешних соединениях.
Рекомендую заглянуть всё-таки в даташиты, которые я привёл выше, и посмотреть на специализированный вход для батарейного питания.
порог в 1.8 дает возможность использовать литивую таблетку на все 100%
Вы разрядную кривую литиевых элементов (стандартных Li-SOCl2 и Li-MnO2) видели? У Li-MnO2 при полном разряде малым током (0.001-0.005 C) при полном разряде 2v. У Li-SOCl2 — выше.
Вы понимаете разницу между полноценной работой от источника 1.8 вольта
Правильнее будет сказать, что attiny4/5/9/10, attiny13a, attiny102/104, attiny212/412 и подобные, либо низковольтные модификации типа attiny25v/45v/85v имеют возможность работать в ограниченном режиме от 1.8v. С пониженной частотой, не всегда с возможностью перепрошивки при таком питании (т. е. необходимо усложнять плату для возможности перепрошивки, чтобы дать внешние 3.3-5v).
Теперь вернёмся к вашим воплям, где вы старательно подменяете питание от батареи питанием от источника 1.8v. Вы понимаете, что при батарейном питании кроме V_BAT эту же батарейку можно подключить в V_DD и V_DDA? Т. е. питать весь чип от батарейки? И вполне укладываться в необходимые параметры для питания чипа при использовании обычного литиевого первичного элемента?
V_BAT даёт вам дополнительные возможности (мониторинг напряжения на батарее, независимые от V_DD регистры и RTC).
Добавлю, что если вам реально нужно (т. е. не при питании от литиевой батарейки), то всегда есть низковольтная серия stm32f0x8, поддерживающая питание от 1.8v.
Ну так Rust это вам не Go. Он нацелен на убийство C, у него нулевой рантайм и прочие фичи.
Строго говоря, у всего, что не ассемблер — рантайм не нулевой. Даже у C.
Другое дело, что в стандартном рантайме там нет тяжелых вещей вроде сборщика мусора, но раскрутка стека, выделение/освобождение памяти — это тоже рантайм.
Так что какой-то рантайм там есть, то он небольшой.
В Расте нет исключений, поэтому раскрутка стека происходит лишь перед смертью программы и происходит для удобства поиска багов. Можно вызвать backtrace руками, но опять же, сам вызвал, сам готовься за это платить.
Освобождение и выделение памяти в ассемблере требует столько же времени, сколько и в Расте. Можно отключить std с динамическими контейнерами и хипом, получите stack-only язык, с 0 накладных расходов на абстракции.
В Расте нет исключений, поэтому раскрутка стека происходит лишь перед смертью программы и происходит для удобства поиска багов.
Не совсем верно, по умолчанию при раскрутке умирает поток, а не всё программа. Такая естественная граница. Но никто не мешает включить abort
при панике, а на некоторых таргетах подсунуть свой panic_fmt
и eh_personality
.
Освобождение и выделение памяти в ассемблере требует столько же времени, сколько и в Расте.
Зависит от аллокаторов. В текущий момент обычно это jemalloc
или стандартные аллокаторы из libc
.
Rust — низкоуровневый язык. Уровень определяется близостью к железу, а не фичами языка.
Ведь по определению, низкоуровневый язык — это язык, позволяющий работать непосредственно с сущностями системы типа регистров. Согласно такому определению, низкоуровневыми языками могут быть только ассемблеры, а все остальные языки, включая Rust — высокоуровневые, потому что они абстрагируются от конкретной архитектуры.
Я думаю, что это пережиток того времени, когда считалось, что высокий уровень абстракции и полный контроль над железом не совместимы. Иначе в таком делении просто нет никакого практического смысла.
Но про ассемблер неверно, так все такие языки позволяют писать платформозависимый код. В том же Rust inline assembly планируется как часть языка (емнип уже есть в nightly, но не stable сборках). В С на практике тоже, хотя это и не часть стандарта.
Для меня сейчас понятие "уровня" полностью сводится к наличию/отсутствию обязательного рантайма и возможности unsafe работы с памятью.
Для меня сейчас понятие "уровня" полностью сводится к наличию/отсутствию обязательного рантайма и возможности unsafe работы с памятью.
Ага, я для себя на 4 уровня делю языки:
- Низкий уровень — уровень железа: ассемблер, включая ассемблерные вставки из более высокоуровневых языков и интринсики.
- Средний уровень: прямой доступ к памяти, машинозависимые типы.
- Высокий уровень: отсутствие прямого доступа к памяти, языковые абстракции типа классов.
- Сверхвысокий уровень: скриптовые языки.
Современные языки довольно сложны, и они занимают сразу несколько уровней. Тот же C++ может быть как низкоуровневым (смесь шаблонов с векторными инструкциями в обработке изображений), так и высокоуровневым (код не использует сырые указатели вообще — только умные указатели).
С растом такой проблемы нет
В расте же придётся отключить манглинг не так ли? Так и в C++ можно, если extern "C"
написать.
Да в расте тоже придется сделать некоторые телодвижения, но значительно меньше.
И что делать с исключениями с++ вобще не понятно… Хотя если функция rust возвращает Result или Options, то наверно тоже есть нюансы как с ней работать в С.
Но в правы, я был слишком категоричен, забыл что можно использовать extern для получения возможности вызывать код написанные на c++ из с путем создание оберток, в самом коде
Завернуть его в С++ фасад с простым интерфейсом — не вариант?
adapting a ~1000 lines python monster (which to 90% covers weird edge cases) might look daunting, but on the other hand, doing things manually, like those folks try will result in a «toy example», that only covers the 5% most used cases. (which again IS cool, too, don't get me wrong. problem is, if you deviate only a millimeter from it, you're staring into an open abyss)
То есть изучить генератор в тыщу строк на питоне (которого я, кстати, не знаю) и написать свой генератор оказывается самый простой способ это осуществить. Если это не показывает сложность FFI вызова плюсового кода — то я даже не знаю…
Если это не показывает сложность FFI вызова плюсового кода — то я даже не знаю
Т.е. если написать систему аналогичного масштаба на чистом идиоматичном Rust (с RAII и компайл-тайм полиморфизмом), то реализовать биндинги к, например, Python, будет тривиальной задачей?
Что вы там делаете на нем? Напишите кусок кода (то, что я назвал «С++ фасад с простым интерфейсом») на С++, который торчит наружу API-ем попроще, и используйте его в своем растовом коде.
Я вот использую ffmpeg в проекте на C++, но мне и мысли не приходит завернуть весь весь ffmpeg в С++.
Если бы я решал какую-то прикладную задачу, где надо фигак-фигак и должно быть готово уже вчера, я бы конечно не стал подобным маяться. Но я это делаю для коммьюнити и для опыта.
Или я не прав и написать враппер на C++ для библиотеки на Rust — ничего не стоит?
Или я не прав и написать враппер на C++ для библиотеки на Rust — ничего не стоит?Вообще вся эта ситуация и весь бред, происходящий в индустрии — это какая-то трагикомедия.
Вызвать функцию хоть на C++, хотя на rust — задача, блин, давно и успешно решённая! gdb и lldb её успешно решают. Может стоит в эту сторону копать?
Оно, правда, не будет на Windows работать — ну так и чёрт с ней.
У меня была простая задача: написать бота, который бы мог сравнивать картинки, на расте, потому что хотел обучиться языку на примере реального проекта. Но оказалось, что для этого нужен opencv. Можно конечно было бы написать полтора враппера над конкретными функциями, но я нашел библиотеку, где было реализовано уже почти все. Потом я добавил туда пару нужных врапперов. Потом еще пару. И заверте…
В итоге, сейчас есть понимание, что нужно пошаманить кодогенерацию — на основании плюсовых хедеров генерировать растовый код. Это сложно, но реально. Так работают описаные мной врапперы на питоне и джаве. Так сейчас пишут враппер на Go.
Так что
Или я не прав и написать враппер на C++ для библиотеки на Rust — ничего не стоит?
Не понял, с чего такой вывод. Нужно дать пользователям Rust возможности, которые предоставляет OpenCV, хотя бы потому, что не все любят писать на плюсах. Остальное — следствие и мои приоритеты на трату свободного времени.
В итоге, сейчас есть понимание, что нужно пошаманить кодогенерацию — на основании плюсовых хедеров генерировать растовый код. Это сложно, но реально. Так работают описаные мной врапперы на питоне и джаве. Так сейчас пишут враппер на Go.
а что с mangling'ом?
а что с mangling'ом?
Посмотрел исходники. Никакой магии там нет, честно руками конвертируют плюсовые типы в питоньи и обратно, а для методов скриптом генерятся питоньи обёртки, которые кастят питоньи типы обратно в плюсовые и вызывают плюсовые функции. Поскольку питоний модуль компилируется плюсовым компилятором, проблема манглинга решена.
А что с классами из с++ делать?
А что делать с RAII-структурами в Rust?
И что делать с исключениями с++ вобще не понятно
Ловить вcё в сишных обёртках и конвертировать в коды возврата. С растовыми статусами этого не придётся делать?
А что делать с RAII-структурами в Rust?
Т.е. если написать систему аналогичного масштаба на чистом идиоматичном Rust (с RAII и компайл-тайм полиморфизмом), то реализовать биндинги к, например, Python, будет тривиальной задачей?
Ну, явно попроще. Вот тут пример небольшой есть.
Ловить вcё в сишных обёртках и конвертировать в коды возврата. С растовыми статусами этого не придётся делать?
Код возврата это просто Union, проблем с ним нет. А вот эксепшны намного опаснее:
To implement this we must think about emulation of C++ exceptions in C, classes/methods/objects, etc, including some «runtime library» to support this.
For example, you could take a look on «golang» approach from here: #10129 (but they completely lost C++ exceptions handling).
Also you could take a look on OpenCV Python bindings, there are exceptions are re-wrapped into Python «exceptions» leaving message string only. Classes are emulated via Python runtime.
OpenCV 3.x doesn't not support C compilation mode officially. There are still legacy C API calls (from OpenCV 1.x) but they should be compiled in C++ compilation mode.
Even if you succeeded to build code with C compiler (and avoid cvRound problem: #6585) it would lead to terrible behavior like #6221 or silent crashes in case of raised C++ exceptions.
Гарантирую, что из-за использование растовых статусов silent crash'а произойти не может.
Код возврата это просто Union, проблем с ним нет.
Что значит "проблем с ним нет"? Обёртки для си всё равно писать надо. Что если в этом юнионе объекты с деструкторами лежат? Если нужно писать обёртки, то и в плюсах можно написать catch(...) и конвертировать исключения в коды возврата.
Попрошу минусующих показать, как вызвать из C rust-функцию, возвращающую Result<Resource, Error>
без написания специальных сишных обёрток. C++ исключения — это проблема, но как вы убеждаетесь, что panic! не прилетит из глубин сторонней библиотеки, которой вы пользуетесь? Может, так? Чем это отличается от catch(...)
?
Я ничего не имею против Rust, мне просто непонятно, как принципиальные семантические проблемы могут решиться сами собой при смене языка на аналогичный.
Вот тут пример небольшой есть
Там владение объекта не передаётся в сторонний код. Сторонний код видит только указатель на объект, создаваемый и уничтожаемый в rust. Если стороннему коду нужно создавать и уничтожать экземпляры RustObject, нужно написать функции-обёртки для конструктора и деструктора. Один-в-один как в C++.
Если стороннему коду нужно создавать и уничтожать… нужно написать функции-обёртки для конструктора и деструктора
Это даже не обсуждается, это азы. Так нужно делать каждый раз при взаимодействии модулей с разными рантаймами, даже если язык один и тот же...
Кстати у раста тоже есть под windows две вариации тулчейна msvc и gnu.
интересно какое interopability между msvc и gnu версиями?
Проблемма в том что вам могут дать бинарник собранный другим компилятором.
Маловероятно, что вам кто-то пришлёт бинарники написанные на расте, поэтому это высосанный из пальца пример.
Так же, разные версии раста несовместимы между собой. За примерами ходить не надо, мне уже кто-то рассказывал о том, что «в расте добавили супер-оптимизацию, которой нет в С/С++, потому что это супер-язык», а оказалось — просто врубили флажок существовавший в llvm уже сотни лет, который уже давно реализован в гцц/шланге(-fpack-struct). Естественно, что эти изменения породили бинарно-несовместимые версии компилятора раст.
Ну и во имя справедливости. Шланг спокойно линкуется с гцц, а значит и наоборот. Остаётся только один альтернативно-одарённый компилятор, но даже с ним гцц должен линковаться, но тут я не эксперт и данную платформу никогда в глаза не видел. Но в любом случае, он же как-то собирается с крестовым мсным рантаймом, а значит совместим.
Поэтому, подобная проблема существует только на одной платформе и с одним компилятором, и то кейс нереалистичный. Никто не будет под эту платформу собирать бинари gcc, а если будут собирать, то они должны быть совместимы с msvs.
По поводу подобного:
Для c/c++ у нас есть msvc/gcc/llvm/Green Hills/keil/iar/borland список можно долго продолжать.
Зачем эта глупя подмена понятий? Во-первых — откуда тут взялся си? Во вторых, с каких пор эти «компиляторы» стали уметь в С++?
Живых кросслпатформенных компилятора существует только два — гцц/шланг. Под одну платформу существует альтернативно-одарённый компилятор, который недавно только начал хоть как-то «уметь» в С++. Про их совместимость я уже написал выше.
даже бинарники из-под разных версий msvc не могут друг с другом слинковаться
И? Что же из этого следует? Да мало того, что ничего не следует и это очередной бред, да к тому же — я уже разобрал эту тему выше.
а с gcc и подавно
Заявления противоречат реальности. gcc должен уметь линковаться с msvs, и я на 99% уверен, что это именно так.
Про шланг/гцц я уже говорил, и тут я уже точно знаю, что это работает.
Рантайм то он может быть и поддерживает
Что же вам так хочется везде лезть со своей невероятность глупостью. Поддержка рантайма и есть поддержка левого аби, в противном случае вызвать нужную функцию попросту невозможно.
но скорее всего только если gcc собрать студией
Как комментировать подобную ахинею я просто не знаю. Это ведь не просто ошибка — это отборный бред.
Сборка компилятора другим компилятором не меняет логику работы компилятора. Хотя данный пример показателен, ведь зачем что-то понимать — надо прийти в комменты и нести ахинею. Хотя, судя той реакции и тем ответам, что получаю я — это норма для данного ресурса. С умным видом спамить полную ахинею.
Заявления противоречат реальности. gcc должен уметь линковаться с msvs, и я на 99% уверен, что это именно так.
Спешу вас расстроить. Берете Qt'шные библиотеки собранные для msvc, берете gcc компилируете код и удачи вам с линковкой. Когда слинкуетесь прихотиде расскажите.
Или можно на оборот библиотеки собранные под gcc а линковать msvc. Разультат тотже.
Шланг c gcc может и слинкуются, так-как шланг старается мимикрировать под gcc. Но гарантий нету никаких. Да и то пока вы не будете передавать что-то через классы стандартной библиотеки. Так-как она у них по разному реализована.
Спешу вас расстроить.
Это меня никак не расстраивает, т.к. а) это ничего не меняет, б) я и не утверждал подобного.
Берете Qt'шные библиотеки
С чего я должен их брать? Когда на вы мне кути на расте покажите — тогда приходите. Для проверки достаточно любого С++ кода.
Или можно на оборот библиотеки собранные под gcc а линковать msvc. Разультат тотже.
Это я вообще не обсуждал, т.к. не нужно.
В любом случает, мне не интересна эта «платформа» и её проблемы. Все эти рассуждения ничего не доказывают, ведь за ними ничего не стоит.
Точно известно, что шланг пытается поддерживать msvs abi. Этого уже достаточно для моей правоты. Я не верю, что за десятки лет в гцц так и не реализовали msvs abi, а по ключевым словам гуглится всякий шлак.
Шланг c gcc может и слинкуются, так-как шланг старается мимикрировать под gcc.
Не может, а слинкуются.
Но гарантий нету никаких.
Пустые рассуждения. Вам не нужно забывать о контексте, а в рамках него вероятнее произойдёт ситуации отсутствия хоть какого-то бинарного кода на расте. Все остальные рассуждения не имеют смысла, ведь мы не обсуждаем какие-то гарантии, а сравниваем раст и кресты.
Да и то пока вы не будете передавать что-то через классы стандартной библиотеки. Так-как она у них по разному реализована.
Шланг почти всегда существовал с гнутой stdlib, да и сейчас существует. Если понадобиться линковаться к гцц, то никто не будет использовать libc++.
Только вот незадача, у раста нет «другого компилятора»
Я тоже так думал, но потом случайно наткнулся на https://github.com/thepowersgang/mrustc
Он не production-ready, но какие-то усилия в этом направлении прилагаются.
Наверное, стоит пояснить мысль.
В C++ есть множество методов, которые инвалидируют объект — обычные сценарии использования объекта после такого вызова ведут к UB или ошибке времени выполнения (по крайней мере, до повторной инициализации).
Среди них — std::unique_ptr::release
, std::thread::detach
и std::thread::join
, std::future::share
и std::future::get
, перемещение через std::move
.
Язык не имеет механизмов для предотвращения дальнейшей работы с объектом после вызова подобных методов.
На C++ можно программировать микроконтроллеры. C++ не обязательно тяжелее — никто не заставляет использовать его работу с памятью, STL, виртуальное наследование, исключения. Без всего этого он не тяжелее С, а жизнь упрощает существенно. Начиная от банальной перегрузки функций и заканчивая HAL на шаблонах без единого лишнего байта.
причудливой объектной ориентации в С
На мой взгляд — это костыли и извращения.
Пришлось найти реализацию stdlib для AVR, и даже немного её дополнить свежими фичами из С++11/14. А вот в тулчейне Arduino Due, например, stdlib уже есть их коробки, и довольно свежий и полный.
Если вы об этом
my_func(Fubarize(true), Frobnify(false), Bazificate(true));
то так никто не пишет, потому что это громоздко. Именованных аргументов нет, поскольку и без них не хватает рук на все запланированное (хотя периодически намеки на них приплывают). Кроме того, против вызовов методов в стиле do(a, b, c, true, false)
существует и поощряется использование билдеров и типажей для эмуляции перегрузки функций.
По моему опыту добавление именованных аргументов часто приводит к появлению функций с запредельно большим количеством аргументов там, где по хорошему нужно передавать структуру.
напишите на этом супер Rust нейронку с умножением матриц, конволюцией и паралелизмом для CPU и потом сравните с производительностью на C
Написать-то можно что угодно на чем угодно, даже с учетом требований производительности.
Вопрос в стоимости:
- написания
- поддержки написанного
В чем-то соглашусь. Вот делают какой-то язык с рядом новых фич (Rust, Kotlin). Фичи-фичами, но зачем вы отказываетесь от привычного впитанного с молоком матери си-подобного синтаксиса объявления переменных, функций...
К тому же привычный — не значит лучший.
Современные языки массово используют var: type вместо type var, благодаря чему тип можно опустить.
Хотя в целом Rust выглядит неряшливо, на мой вкус.
К тому же привычный — не значит лучший.
Это не имеет смысла, ведь работает подобное и в обратную сторону. Если привычный — не значит лучший, то и «не привычный» — не значит лучший, а значит подобные заявления друг друга компенсируют.
Современные языки массово используют var: type вместо type var, благодаря чему тип можно опустить.
Нельзя. Именно для этого и существуют let-кастыли, т.к. выражение без типа — неоднозначно.
Я видел очень мало людей, которые понимают сишный синтаксис. 99% вообще напишет тут void f(int f(void)) указатель на функцию. То же самое с type qualifiers, то же самое с теми же указателями. Люди не понимают, что тип у переменной не type *, а *, а type и всё что слева — относится к операции разыменования.
Квалификаторы справа — дефолт, квалификатор слева в случае с * неоднозначен, а значит не может относится к *. Квалификаторы слева — так же никаких проблем, ведь всё логично.
Дано я уже не видел объективной критики сишного синтаксиса. Кроме возврата указателя на функцию я вообще не видел ничего.
char * const (*(* const bar)[5])(int )
Дано я уже не видел объективной критики сишного синтаксиса. Кроме возврата указателя на функцию я вообще не видел ничего.
Да пожалуйста.
Оператор "запятая". Зачем она вообще нужна? Я не могу представить случая, где она была бы полезна. А вот ограничения на синтаксис при этом накладываются довольно сильные.
Оператор
switch
крайне непродуман. Переход управления из одной ветви в другую — ситуация, которая случается крайне редко. Писать каждый разbreak
малость напрягает. Поэтому логичнее было бы отbreak
полностью отказаться, а переход в следующую ветку реализовать черезgoto
. Ну и группировать несколько подряд идущихcase
в один, указывая условия через запятую.
Объявления типов с квалификаторами и слева, и справа — затруднение чтения кода. Я бы предпочёл, чтобы мухи (тип) и котлеты (объявление переменной) были отдельно:
Type a, b;
, причём указатели относятся к типу, а не к переменной, т.е. в объявленииint * a, b
обе переменные будут должны типint *
. Объявление массивов фиксированного размера:int[10] a
, а неint a[10]
.
Про указатели на функции: аналогично п. 3. хотелось бы видеть что-то типа:
int function(int, int) * variable_name
вместоint (*variable_name)(int, int)
.
Имена типов в виде крокодилов
unsigned long long
.
- [C++] Неоднозначности между определением функции и инициализацией объекта, костыль в виде двух видов записи вызова конструктора — с обычными и фигурными скобками.
Нельзя. Именно для этого и существуют let-кастыли, т.к. выражение без типа — неоднозначно.
Угу, в C++ это костыль в виде auto
, именно потому, что обявление без типа не предусмотрено синтаксисом. Особенно смешно выглядят лямбды: [](auto x, auto y) { return x + y; }
, когда можно было бы написать (x, y) -> x + y;
Угу, в C++ это костыль в виде auto, именно потому, что обявление без типа не предусмотрено синтаксисом.Кому-то этого показалось мало. Теперь бывает не только
auto
, но еще и decltype(auto)
!Кто из «знатоков» C++ способен пояснить где в функции
foo
— неопределённое поведение:decltype(auto) foo() {
int i = 1;
return (i);
}
И почему в функции bar
его нету:decltype(auto) bar() {
int i = 1;
return i;
}
Кто не смог — сходите на godbolt…
Отличный язык, тщательно спроектированный для попадания в ногу…
Да пожалуйста.
Перво наперво — нужно осилить понятие «контекст», а уже потом приходить со своими пожалуйста. Но я помогу, контекстом был синтаксис описания типов, а не синтаксис вообще. Тем более, половина тут вообще не касается синтаксиса.
Оператор «запятая». Зачем она вообще нужна? Я не могу представить случая, где она была бы полезна. А вот ограничения на синтаксис при этом накладываются довольно сильные.
Везде, особенно в однострочниках. Вон пару сообщений назад мне кто-то пастил крестовый код, и там именно запятая.
Оператор switch крайне непродуман.
Продуман. Это банальная логика третий класс. Есть семантика перехода, есть переходы в свиче. Переходы не ограничены ничем.
Переход управления из одной ветви в другую — ситуация, которая случается крайне редко.
Каждая вторая — подобная ситуация.
Ну и группировать несколько подряд идущих case в один, указывая условия через запятую.
Т.е. для тех ситуаций, которых две строчки назад «крайне редко»? Сильно.
Это итак работает. case: case: case: — сколько угодно.
Объявления типов с квалификаторами и слева, и справа — затруднение чтения кода.
Не объективно. Для меня затрудняет чтение обратное.
Я бы предпочёл, чтобы мухи (тип) и котлеты (объявление переменной) были отдельно
Это не критика. Меня мало должны волновать ваши предпочтения. Они так отдельно.
обе переменные будут должны тип int *
Как мне объявить int v, * p; в вашем супер-синтаксисе? Хотите ограничить типы — есть тайпдеф. Напишите там что угодно и это уже будет типов, а «составным типом».
Объявление массивов фиксированного размера: int[10] a, а не int a[10].
И? С каких пор «хочу» — стало критикой? [10] — это такое же свойство переменной. Хотите определить это на базе типа — есть тайпдефы.
Про указатели на функции: аналогично п. 3. хотелось бы видеть что-то типа:
Зачем нужно это «function» кастыльное непотребство? Мне не хотелось бы, дальше что?
Имена типов в виде крокодилов unsigned long long.
Есть тайпдефы, стандартизированные.
[C++] Неоднозначности между определением функции и инициализацией объекта, костыль в виде двух видов записи вызова конструктора — с обычными и фигурными скобками.
Нету никакой неоднозначности. Конструктор — это вызов функции. Другое дело, что на самом деле конструктор — инициализатор, а в си инициализатор {}. Поэтому всё вернулось на круги своя.
Угу, в C++ это костыль в виде auto
Это не костыль.
именно потому, что обявление без типа не предусмотрено синтаксисом.
Неверно. К синтаксису языка это не имеет никакого отношения — это фундаментальная неоднозначность между использованием и объявлением. И auto в С++ не кастыль, ведь синтаксис определения не изменяется. type var;, а вот в кастыльном var: type; — меняется, ведь нам нужно добавлять ненужность в виде let, как и ненужность в виде function/fn и прочего колхоза.
Особенно смешно выглядят лямбды:
Сишный синтаксис позволяет опускать типы, но в С++ как всегда — решили пойти своим путём.
[](auto x, auto y) { return x + y; }, когда можно было бы написать (x, y) -> x + y;
А как только нам нужно больше логики? И опять же, это примитивный сахар, а не синтаксис. Убогая стрелка, которая ничем не лучше скобок.
Почему вам «лишнее» слово тут «int function(int, int)» не мешает, а тут мешает? Вы уж там определитесь.
А теперь [&]{ x += 1;}. Синтаксис намного мощнее, нежели эти хелворды.
Тем более, этот синтаксис итак есть в крестах [](auto x, auto y) -> auto {}, только синтаксис крестов несоизмеримо мощней, нежели эти хелворды, которые вы пытаетесь выдать за синтаксис.
Вы попробуйте облечь в них все те возможности, что есть в крестах. В этом проблема всех «критиков», помимо основной «я хочу так — это критика», — «я пащу левый синтаксис, который просто не может в ту семантику, которая существует в рамках крестов».
Везде, особенно в однострочниках. Вон пару сообщений назад мне кто-то пастил крестовый код, и там именно запятая.
Подобные однострочники нужно выжигать напалмом.
Каждая вторая — подобная ситуация.
Хм, видимо, вы программируете драйверы? Потому что в прикладном программировании я последние пару лет с такой ситуацией не сталкивался вообще.
Как мне объявить int v, * p; в вашем супер-синтаксисе?
Логично же:
int v;
int * p;
И? С каких пор «хочу» — стало критикой? [10] — это такое же свойство переменной. Хотите определить это на базе типа — есть тайпдефы.
Хочу — значит, что я критикую привязку свойств к переменной, а не к типу.
И да, проблема в том, что typedef для массива — это фактически указатель.
Зачем нужно это «function» кастыльное непотребство?
Чтобы разделить тип и переменную, неужели не понятно?
К синтаксису языка это не имеет никакого отношения — это фундаментальная неоднозначность между использованием и объявлением.
Так может разрешить неоднозначность? Заодно и парсинг станет легче — в случае недостающей/лишней фигурной скобки ошибочное место станет легче искать.
А как только нам нужно больше логики? И опять же, это примитивный сахар, а не синтаксис. Убогая стрелка, которая ничем не лучше скобок.
Самые частые лямбды — именно такие короткие, которые являются аргументами sort, map, reduce и т.д. А раздражают здесь слова auto
и return
, без которых можно было бы обойтись.
Почему вам «лишнее» слово тут «int function(int, int)» не мешает, а тут мешает? Вы уж там определитесь.
Потому что это определение функционального типа. Кстати, в C++ можно писать так: std::function<int(int, int)>
— вполне удобно.
В этом проблема всех «критиков», помимо основной «я хочу так — это критика», — «я пащу левый синтаксис, который просто не может в ту семантику, которая существует в рамках крестов».
Просто я пишу ещё и на C# и вижу, насколько удобнее пользоваться шарповыми лябдами и делегатами.
Это не имеет смысла, ведь работает подобное и в обратную сторону. Если привычный — не значит лучший, то и «не привычный» — не значит лучший, а значит подобные заявления друг друга компенсируют.
У вас проблемы в логике, из A => B никак не следует, что !A => !B.
Нельзя. Именно для этого и существуют let-кастыли, т.к. выражение без типа — неоднозначно.
Костыль — это когда в некоторых случаях тип слева (обычная функция), где-то справа (лямбда), а где-то вообще творится черная магия в стиле выше из-за смешания типов и значений.
К тому же привычный — не значит лучший.
Ну… Люди — многое делают по привычке столетиями.
В области программирование — привычки это великое дело. Вы потратили месяцы, чтобы отточить до автоматизма некий навык. И посему для вас вообще не стоит проблема лучшим методом ли вы пользуетесь или нет.
Цена использования этого метода для вас равна 0,01. А вот изучение нового, затем доведение до такого же автоматизма — это месяцы потерь.
С учетом того, как многие вещи меняются в программировании шустро, лучше подумать сто раз, изучить отзывы коллег, чем тратить свое время на изучение очередной «серебрянной пули», которой как известно не существует (@Ф. Брукс)
Скажу про переменные. В Rust let
— это объявление не переменной, а привязки. Это имеет два последствия. Во-первых, доступен pattern matching и деструктурирование. Во-вторых, привязки могут быть переобъявлены.
struct Foo(u32, u32);
fn main() {
let foo = Foo(2, 3);
let Foo(a, b) = foo;
assert_eq!(a, 2);
assert_eq!(b, 3);
let foo = "hello world";
}
Производительность на 5-10% выше, чем на C++. Знающие люди подсказывают, что это в пррвую очередь благодаря более аггрессивным оптимизациям компилятора, который в Rust имеет точную информацию о том, где используется адресная арифметика (блоки unsafe): тема на reddit
Производительность на 5-10% выше, чем на C++.
Можно увидеть код на rust/C++, который сравнивается? А так же, желательно, код самого бенчмарка.
Производительность на 5-10% выше, чем на C++
Открыли Америку.
Известно же, что С++ не самый быстрый в мире язык. Это заблуждение вызвано всего лишь близким родством с действительно быстрым чистым С.
Разумеется, так и должно быть — у Rust больше возможностей для оптимизации из за большей строгости и требовательности.
В С++ слишком много автоматики, которая принимает решения просто так, на авось зачастую.
Rust тем и отличается, что занудливо просит (нет, не так — требует даже) программиста уточнить намеряния.
Эта требовательность Rust и позволяет произвести более глубокие оптимизации.
Учитывая возраст C++ и возраст Rust — стоит ожидать только увеличения отрыва по мере оптимизации компилятора.
Известно же, что С++ не самый быстрый в мире язык. Это заблуждение вызвано всего лишь близким родством с действительно быстрым чистым С.
В С++ слишком много автоматики, которая принимает решения просто так, на авось зачастую.
«Автоматикой» пользоваться никто не заставляет, с++ всегда оставляет возможность сделать как минимум настолько же быстро, что и чистый си. При этом скорость разработки на плюсах всё равно будет выше.
Учитывая возраст C++ и возраст Rust — стоит ожидать только увеличения отрыва по мере оптимизации компилятора.
вы же понимаете, что почти все оптимизации в компилятор раста пришли из компиляторов тех же си/с++/фортрана? Раст требует от программиста предоставить больше полезной для оптимизаций информации. Но это не значит, что это нельзя сделать в плюсах.
«Автоматикой» пользоваться никто не заставляет, с++ всегда оставляет возможность сделать как минимум настолько же быстро, что и чистый си
Ну да, а с ассемблерными вставками — еще быстрее.
Мы не можем так говорить, как вы предлагаете. Так как это предполагает конкретного программиста, пишущего конкретную программу.
Речь-то же об языке в целом.
вы же понимаете, что почти все оптимизации в компилятор раста пришли из компиляторов тех же си/с++/фортрана?
На низком уровне, например, как оптимизировать циклы или ветвления — да.
На высоком — у разных языков свои особенности.
Полагаю, что более разумное управление памятью, когда лишний раз не производится ее освобождение, — уже способно дать хороший эффект.
Для реализации подобного поведения в С++ — пришлось бы управлять памятью шибко уж вручную, откататься на уровень С фактически.
Ну да, а с ассемблерными вставками — еще быстрее.
Не надо пожалуйста передергивать. В одном месте с++/раст программист злоупотребит строками и получит потерю в 5% производительности GUI, а в другом месте использует библиотечную хеш-таблицу вместо полиномиального решения (потому что универсальных хеш-таблиц для си, насколько я знаю, не существует, а делать их самому долго) и получит выигрыш в 20% в горячем цикле. Кое-где использует динамические контейнеры вместо ручной работы с памятью, но зато сэкономит кучу времени на написании и дебаге для оптимизации боттлнеков.
Речь-то же об языке в целом.
Нет такого понятия как «быстродействие языка», но можно оценить быстродействие инструментария. Можно реализацией на питоне, дергающей куду, обогнать самописное решение хоть на расте, хоть на си. Можно (предметно) говорить о конкретных оптимизациях. Например:
Полагаю, что более разумное управление памятью, когда лишний раз не производится ее освобождение, — уже способно дать хороший эффект.
утечки — не самая хорошая альтернатива освобождению памяти
утечки — не самая хорошая альтернатива освобождению памяти
Речь не об этом.
Полно способов более интеллектуально подходить к использованию памяти: например, о выборе где размещать — на стеке или в куче; об отложенном освобождении; об переиспользовании выделенной уже в куче памяти и т.п. и т.д. и пр.
Кстати неосвобождение памяти — тоже действенный метод, реально применяется для написания высокопроизводительных короткоживущих утилит.
Нет такого понятия как «быстродействие языка», но можно оценить быстродействие инструментария.
Строго говоря, язык программирования — это только синтаксис + API стандартной библиотеки.
Но когда мы говорим «язык программирования» то подразумеваем, вестимо, и среду исполнения и компилятор и реализацию стандартной библиотеки, конечно.
Открыли Америку.
Пока это лишь голословные заявления. Мне всегда было интересно — как люди позволяют себе публиковать результаты бенчмарков без самих бенчмарков. Мы не можем ни воспроизвести результата, ни проверить — реально ли бенчмарк измеряет то, что предполагается и т.д.
Известно же, что С++ не самый быстрый в мире язык. Это заблуждение вызвано всего лишь близким родством с действительно быстрым чистым С.
Действительно — С++ позволяет писать «как на си» и люди любят брать свойства этого «как на си» и натягивать на современные/новомодные С++-реалии. Именно на эту тему много спекуляций, но всё равно — формально это не так, и С++ действительно почти как си.
А «чистый си» — это далеко не «быстрый си». Быстрый си почти никогда не бывает чистым.
Rust тем и отличается, что занудливо просит (нет, не так — требует даже) программиста уточнить намеряния.
Не видел ни единого проявления подобного поведения.
Эта требовательность Rust и позволяет произвести более глубокие оптимизации.
Есть примеры живые примеры?
Учитывая возраст C++ и возраст Rust — стоит ожидать только увеличения отрыва по мере оптимизации компилятора.
У раста нет компилятора — раст это фронтенд к крестовому llvm. И какие там вообще оптимизации на уровне фронтенда?
А разрыва пока никто не показал.
Действительно — С++ позволяет писать «как на си» и люди любят брать свойства этого «как на си» и натягивать на современные/новомодные С++-реалии. Именно на эту тему много спекуляций, но всё равно — формально это не так, и С++ действительно почти как си.
С такой позиции мы будем обсуждать не язык, а конкретного программиста.
У раста нет компилятора — раст это фронтенд к крестовому llvm. И какие там вообще оптимизации на уровне фронтенда?
Например, по алгоритмам работы с памятью (стек, куча). До того как войдет в llvm
Не видел ни единого проявления подобного поведения.
Весь browning, к примеру.
Понятно, что ради благого дела.
Есть примеры живые примеры?
Например вы можете получить две мутабельные ссылки и быть уверенным, что они указывают на разные объекты. Классический случай pointer aliasing'а. В плюсах есть костыль в виде__restrict__ , но компилятор никак не проверяет это, все на совести разработчика. Раст же не заставляет выбирать между производительностью и корректностью.
Например вы можете получить две мутабельные ссылки и быть уверенным, что они указывают на разные объекты.
И? Во-первых это попытка выдать ограничение за фичу.
Во-вторых, алиаситься может не только мутабельное с мутабельным, а так же мутабельное с иммутабельным. Это подлог, либо явное непонимание темы.
Второе, разные объекты ничего не значат. Ссылка на элемент массива и сам массив — являются разными объектами, но они алиасятся. Ссылка на поле и структура — так же. Я сомневаюсь, что нельзя взять ссылку на на поле, либо на елемент и что это идёт в счёт той самой «только одной» ссылки.
Классический случай pointer aliasing'а.
Для разных типов это итак не работает.
В плюсах есть костыль в виде__restrict__
В плюсах нету рестрикта, он есть в си. Хотя раст не имеет никакого отношения к унификации и стандартизации, поэтому мы можем брать любую фишку любого компилятора и приписывать её к С/С++.
но компилятор никак не проверяет это, все на совести разработчика.
Продолжим, как вы ответите на мои вопросы. Но в любом случае — это невозможно.
Раст же не заставляет выбирать между производительностью и корректностью.
Это не производительность, даже близко. Люди, которые ничего о ней не знают — очень любят раст и порассуждать.
Пруфы? Пожалуйста — начало ветки. У автора ансейф через ансейф. Где же мистическая «производительность без выбора»? Как только автор предоставит код — можно будет посмотреть, что именно там намерено и как. Уже потом можно будет и исходный крестовый код посмотреть. Пока что — тут рассуждать не о чём.
Ещё пруфы? Пожалуйста, «предыдущая» тема про раст, которая касалась сравнения раста и С++. 72 плюса, 7 минусов и ноль сообщений о том, что это убогая клоунада, а не сравнение. Множество восторженных сообщений. Как вы это объясните?
Нужны пруфы того, что это клоунада? Пожалуйста — habrahabr.ru/post/344282/#comment_10563198
Банальный пример — проблемы алиасинга почти не существует для инлайна, да что там — даже для статических функций. Она существует только тогда, когда функция торчит наружу, а значит — в неё может прийти что угодно.
Во-вторых, алиаситься может не только мутабельное с мутабельным, а так же мутабельное с иммутабельным. Это подлог, либо явное непонимание темы.Ну да — вы «не понимаете тему», дальше что?
Второе, разные объекты ничего не значат.В C/C++ — да.
Ссылка на элемент массива и сам массив — являются разными объектами, но они алиасятся.И именно поэтому rust не даст вам передать в процедуру одновременно и ссылку на элемент массива и ссылку на массив.
Я сомневаюсь, что нельзя взять ссылку на на поле, либо на елемент и что это идёт в счёт той самой «только одной» ссылки.А вы бы не сомневались, а почитали. «Живая» ссылка на любой элемент может быть одна и только одна. Что значит «живая» — описано в документации.
Это, вообще говоря, сделано для безопасности — но ничто не мешает оптимизатору испольовать эту информацию и для чего-то ещё.
Продолжим, как вы ответите на мои вопросы. Но в любом случае — это невозможно.Ага. Потому что земля плоская и стоит на трёх китах. Или черепахах?
Это невозможно в C++, потому что там нет соотвествующих понятий. В rust — это возможно. Собственно это его основная фишка.
Банальный пример — проблемы алиасинга почти не существует для инлайна, да что там — даже для статических функций. Она существует только тогда, когда функция торчит наружу, а значит — в неё может прийти что угодно.И в инлайн и в статическую функцию в C++ могут придти пара указателей — и всё. Тут же начнутся проблемы с алиасингом. Да, есть так нелюбимый вами
__restrict__
, но нет реальной культуры его применения.Это не производительность, даже близко. Люди, которые ничего о ней не знают — очень любят раст и порассуждать.Где-то частица «не» пропущена. Ибо вы явно ненавидите rust, но берётесь о нём рассуждать не зная и не понимаю его. Типичное «Пастернака не читал, но осуждаю»…
P.S. Я, кстати, не фанат rust'а. И я до сих пор не уверен, что в реальных проектах необходимость всё укладывать в «прокрустово ложе» borrow checker'а не приведёт к проблемам. Но я, в отличие от вас, хотя бы понимаю — чего в этом языке люди пытаются добиться и зачем.
Ну да — вы «не понимаете тему», дальше что?
Кроме трёпа ничего не будет, я правильно понимаю?
В C/C++ — да.
Неверно, это свойства базовой реальности. Почему вы проигнорировали это? Где ответы?
fn main() {
let s1 = String::from("hello");
let mut rs = &s1;
let mut len = calculate_length(&s1, &rs);
len = calculate_length(&s1, &s1) + len;
let mut slice = &s1[..3];
println!("The length of '{}' is {} is {} is {}.", s1, len, slice, rs);
}
fn calculate_length(mut s: &String, mut sl: &String) -> usize {
s.len() + sl.len()
}
Это что такое? Где вообще пруфцы от вас? Почему я вижу только ссылки на хрен пойми что в интернете и пустые заявления?
Это, вообще говоря, сделано для безопасности — но ничто не мешает оптимизатору испольовать эту информацию и для чего-то ещё.
Меня мало интересуют абстрактные обсуждения и ссылки на то, что «может быть». Я вам привёл свои рассуждения, которые вы никак не опровергли и начали ехать в сторону каких-то левых, не относящихся к теме, вещей.
И в инлайн и в статическую функцию в C++ могут придти пара указателей — и всё.
Не могут. Единственная возможность — это экспортировать сразу несколько указателей из внешнего контекста, но это ненужно. И любой, кто претендует на хоть какую-то производительность — так делать не будет.
godbolt.org/g/V3KXCW — шлангу даже рестрикт не помог, а шансом 98% — это проблема в ллвм, в значит расту ничего не поможет.
Да, есть так нелюбимый вами __restrict__, но нет реальной культуры его применения.
Я уже сказал, что его нету. Культуры нет ни его применения, а написания производительного кода.
Где-то частица «не» пропущена. Ибо вы явно ненавидите rust, но берётесь о нём рассуждать не зная и не понимаю его. Типичное «Пастернака не читал, но осуждаю»…
Опять эти глупые попытки меня ловить. Меня мало волнуют ваши «явно» — я вижу ваш уровень, уровень раст-апологетов. Мне этого достаточно. Мнение о языка, о производительности тех, кто ничего в теме не понимает — меня волновать не должно.
А ненавижу я не раст, а рекламный булшит и балаболов.
И заметьте, я привёл чёткие причины моего недовольства — вы ответили что-то на них? Нет, вы всё неудобное вам игнорируете, занимаясь глупыми обвинениями. А чей-то трёп стоит ноль.
P.S. Я, кстати, не фанат rust'а.
Фанат. Без понимания чего-то лезть куда-то и что-то вещать — это типичная фанатичная глупость. Я где-то услышал какие-то лозунги — и пошел вещать об этом в комментах.
Достаточно посмотреть ваши подобные попытки, когда вы пытались вещать мне про ГЦ. Фанатизм во все поля, ссылки на левые хелворды, отсутствие ответов. А это первое, что я вспомнил. Подобных наших баталий помню больше одной, но мне лень их искать.
И я до сих пор не уверен, что в реальных проектах необходимость всё укладывать в «прокрустово ложе» borrow checker'а не приведёт к проблемам.
Это типичный пример кастылей, когда проблема не решается, а хайп нужен. Да и подобные рассуждения не имеют смысла — без bc потеряется основной лозунг, а кроме них ничего и нет.
Да что там далеко ходить, оно даже слайс на константную(времени компилтайма) строку borrow checker'ом ловит. Колхоз колхоза.
Но я, в отличие от вас, хотя бы понимаю — чего в этом языке люди пытаются добиться и зачем.
Нет, вы не понимаете. И в этом проблема. Вы лезете в тему производительности, в тему лоулевел и С/С++, в которых ничего не понимаете. Как и все остальные адепты.
Хотите делать свои супер-языки? Делайте, но не лезьте в эти темы и не рассказывайте мне о том, что ваш колхоз хоть как-то заменяет С/С++.
А для чего мозилла производит этот хайповый булшит? График популярности броузеров за последние года — вам должен дать ответ на этот вопрос.
Почему весь хабр заспамлен этим булшитом? Пример я уже приводил(а вы его проигнорировали. Хотя это типичное, для вас, поведение). Всё просто — халявные инвайты, халявные плюсы. Пиши любую ахинею в рамках «руст так же быстр» — получай халяву от фанатиков.
Это что такое?Ну… я бы назвал это незнанием rust'а. Вы, в своём примере, наплодили миллион изменяемых ссылок на один неизменяемый обьект. Так как обьет неизменяем, то, разумеется, никаких проблем алиасинга нет и быть не может.
Чего вы этим хотите доказать и кому — я не знаю. Смею предположить, что вы просто не понимаете (или делаете вид, что не понимаете) в чём разница между
mut s: &String
и s : &mut String
.Почему я вижу только ссылки на хрен пойми что в интернете и пустые заявления?Потому что там, по этим ссылкам — всё подробно описано. А поскольку вы демонстрируете вопиющее непонимание вообще всей концепции, то обсуждать какие-то детали с вами — несколько бессмысленно.
Я вам привёл свои рассуждения, которые вы никак не опровергли и начали ехать в сторону каких-то левых, не относящихся к теме, вещей.Вы написали кучу бреда. А когда вас «припёрли к стенке» и потребовали конкретики — жидко обделались.
Вот прямо по порядку:
Во-вторых, алиаситься может не только мутабельное с мутабельным, а так же мутабельное с иммутабельным.В вашей программе этого не происходит, а если бы произошло — была бы зафиксирована ошибка компиляции.
Ссылка на элемент массива и сам массив — являются разными объектами, но они алиасятся.Однако использование этих ссылок — не является проблемой в случае, если обе ссылки указывают на неизменяемый объет. Что, собственно, в вашей программе и происходит.
Я сомневаюсь, что нельзя взять ссылку на на поле, либо на елемент и что это идёт в счёт той самой «только одной» ссылки.Вы всё также не сделали то, что грозились сделать.
Так чего обсуждать-то?
godbolt.org/g/V3KXCW — шлангу даже рестрикт не помог, а шансом 98% — это проблема в ллвм, в значит расту ничего не поможет.Не очень понятно что и как должен был помочь сделать
__restrict__
в данном примере, так что неясно чего вы вообще тут пытаетесь доказать.Да что там далеко ходить, оно даже слайс на константную(времени компилтайма) строку borrow checker'ом ловит.Ещё одно невнятное утверждение, не имеющее смысла.
Вы хоть иногда пытаетесь за деревьями лес увидеть? Или только подгоняете примеры под нужные вам ответы не обращая внимание ни на что другое?
У автора ансейф через ансейф
Шесть слов на весь проект. По сравнению с С++ — это очень мало (потому что в С++ весь код unsafe в понимании Rust)
и более строгой типизации.
А можете пояснить, в чём заключается строгость типизации C++ по сравнению с C?
почему написал про API и DSL, например «сравнивать грёбаные строки» в производительном коде не надо так как сравнение по всей строке долго и заместо этого юзаем просто тип или enum или обходимся вообще без свича.
а с каким кодом С++ вы сравниваете, этот ваш раст может компилить в sse инструкции или в несколько ядер, как это прописывается в языке?
автор книги «Язык программирования Rust»
Товарищ Федерико автором книги не является, и соответственно во это
Я ещё не закончил работу над главой о «бесстрашном параллелизме»
тоже интерпретировано неверно. Он имеет в виду что c многопоточностью в Rust еще не работал, а не то что главу не дописал.
Нет целочисленного переполнения
Сказано достаточно.
Хочу уточнить: переполнения проверяются при компиляции на debug, в release этого нет, ибо оверхед.
Внутренние функции зачастую статические. Это значит, что их нельзя вызвать за пределами исходного файла, где их объявили. Программа теста должна или сделать #include исходного файла с этими статическими функции, или использовать директивы #ifdef для удаления статики только на время тестирования
Очень странно слышать подобные вещи из уст опытного разработчика на С. Как будто о вызове по указателю он никогда не слышал.
--my.h--
typedef struct My
{
int param;
void (*setParam)(struct My *self, int new_param);
} My;
My* MakeMy();
--my.c--
#include "my.h"
static void My_setParam(My *self, int new_param)
{
if(self)
*self->param = new_param;
}
My* MakeMy()
{
My *self = (My*)calloc(1, sizeof(*self));
if(self) {
self->setParam = My_setParam;
return self;
}
return 0x0;
}
--test.c--
#include "my.h"
int main()
{
My *dummy_struct = MakeMy();
dummy_struct->setParam(10500);
if(dummy_struct->param != 100500)
return 1;
else
return 0;
}
Ошибочка: вместо dummy_struct->setParam(10500);
должно быть dummy_struct->setParam(dummy_struct, 10500);
И да, у Rust'а имеется ряд преимуществ над C++. Это и более строгая работа с памятью и нормальное метапрограммирование (а не корявые вычисления на шаблонах) и т.п. Но про это в статье нет ни одного слова…
p.s. я знаю про вечный спор о Rust vs D.
p.s. я знаю про вечный спор о Rust vs D.Не знаю ни о каком «вечном споре». Знаю что rust не пошёл на поводу у моды и вся его библиотека — работоспособна без всякого GC, что ставит его в один ряд с Pascal'ем, C, C++… и в другой класс, нежели D, Go, Java.
Или сейчас у них уже есть не только громкие заявляения о том, что GC можно выключить, но это реально можно сделать?
Ну например, про срезы строк — это просто смешная претензия, пока писал этот текст, уже мысленно набрасал решение. Причем, что и делать-то самому ничего не нужно. Это уже написано до вас. Нужно просто приучиться пользоваться определенным набором любимых библиотек.
Обобщённые типы без проседания производительности на Сях могут быть достигнуты только магией макросов. Но даже такое решение не позволит использовать типажи.
Замыкания — это по определению элемент языка, в Си его просто нет.
Что осталось-то?
80% это всё же не 100%. А главных фич Rust(семантика перемещения, borrow checker, lifetimes, отсутствие UB за пределами синтаксически выделенных участков кода, параметрический полиморфизм, явное приведение типов) в C нет и никакими библиотеками их не прикрутить. А если и прикрутить чем-то, то выйдет в любом случае коряво. Ну и зачем тогда это всё когда есть Rust? Только ради тех, кому лень в течении месяца по несколько часов в неделю тратить на изучение другого ЯП?
А главных фич
Почему в сравнении языков всегда всплывает этот бред?
Разумеется языки разные.
И ожидать от одного почти полного повторения того, что есть в другом — глупо.
Делать язык «точно такой же как С, только синенький» тоже глупо. Языки должны быть сильно разные, чтобы можно было приложить значительные усилия к его развитию.
Когда в команде Evolution всё шло наперекосяк. Нам тогда пришлось купить машину Solaris просто чтобы иметь возможность купить Purify; тогда не было Valgrind.
И всё это время, пока не было Rust, была Ада. Вместо покупки Solaris и Purify можно было бы просто собирать бесплатным GNAT'ом со всеми включенными проверками, да так и оставить в продакшне с проверками. Как учил меня Каменский Никита Викторович в НГУ, 90% кода — проверка ошибок, так пусть генерятся автоматом, если делать их в любом случае нужно. В отличие от Purify и Valgrind, это вполне можно оставить работать в штатном режиме.
Чего из Rust мне не хватает в C