Если я правильно Вас понял, то структуры, подобные двусвязным связным спискам и прочим циклическим графам реализовать в рамках концепции владения не получится. Но как быть если такая структура нужна?
А концепция владения решает проблему замкнутых циклов? Мне казалось, что это её слабое место как раз. Разве можно реализовать в рамках концепции владения, без привлечения подсчёта ссылок какой-нибудь двусвязный список?
По моему мнению шаблоны в плюсах плохи:
1. Временем компиляции
2. Негибкостью (хороши только если одну функцию надо написать для нескольких типов, но как только начинают решаться проблемы из реального мира, приходится изобретать монструозную конструкцию из шаблонов, а то и вообще откатываться к макросам из C)
3. Сообщениями об ошибках (без парсера в них можно утонуть)
В Nim метапрограммирование на порядок лучше плюсового реализовано.
Итак, у нас есть функции, процедуры, дженерики, мультиметоды, шаблоны и макросы. Когда лучше использовать шаблон, а когда процедуру? Шаблон или дженерик? Функция или процедура? Так, а макросы?
Функции, процедуры, дженерики, мультиметоды, шаблоны, макросы.
Именно в таком порядке по приоритету. Если первого пункта недостаточно для реализации необходимого функционала, переходим к следующему и так далее. К сожалению, не могу вспомнить где в документации видел приоритетность, но она была очень похожа на эту. Разве что мультиметодов и функций там не было. Мультиметоды я бы вообще исключил, поскольку они почти всё время были сломаны.
Спасибо! Хотя это не совсем то, что я ожидал. Скорее всего я хочу слишком много.
Говоря «модули» я имел в виду отдельные проекты в терминах CMake. Например проблема в том, что я не могу собрать отдельно проект A, не собирая B и не используя CMakeLists.txt из корня.
А не поделитесь ли опытом, как эти модули потом находить друг относительно друга? Например есть три модуля A, B и С, при том A и B зависят от C: им нужны его инклюды и его нужно слинковать с ними. Вопрос: как организовать структуру проекта без уродливых "../" или модуля D который в правильном порядке выставляет add_subdirectory? При этом A, B и C отдельными проектами не являются (от них зависят другие модули которые потом в сумме могут использоваться в нескольких полноценных проектах), но было бы здорово собирать их в статические библиотеки для тестирования например.
В конце концов, языки программирования пишутся для программистов, а не для парсера.
Конечно это вкусовщина. Я просто привык, что символ пунктуации в тексте программы это своего рода якорь, за который можно уцепиться глазами. Думаю и так понятно, во что превращается текст программы, почти полностью состоящий из таких якорей.
Мне кажется, большая часть перечисленного в статье, уже есть в Nim. Вот несколько примеров:
Макросы поддерживают работу с синтаксическим деревом.
import macros
macro hello(x: untyped): untyped =
result = x
# Сакральный смысл индексов ниже:
# Первый индекс - утверждение (у нас оно одно)
# Второй индекс - часть утверждения (для нашего случая под номером 1 будет первый аргумент
# 0(1, 2...)
# 0: echo("goodbye world")
# 1: ...
result[0][1] = newStrLitNode("hello world")
hello:
echo("goodbye world") # Превратится в echo "hello world"
Кортежи без предварительного объявления
proc x(): (int, int) = (4, 2)
Лямбды:
let f = (x:int)=>x*x
echo(f(2)) # 4
Удобная система сборки: nimble
Не хватает разве что ленивых вычислений из коробки (но можно сделать за счёт макросов) и хорошей интеграции с IDE, но это дело наживное. Ах, да, ещё подсветки синтаксиса хабрадвижком, чтобы не пользоваться питоновской подсветкой.
Отличная статья! Я бы даже сказал: о наболевшем, а именно о мучениях с ABI C++.
Однако, я не смог понять, как Вам удалось справиться с соглашениями о вызовах. Если речь идёт о 32-битном коде, то просто объявления статических функций и заполнения ими таблицы виртуальных методов недостаточно, поскольку виртуальные методы используют соглашение о вызовах thiscall, тогда как функции обычно используют stdcall.
С 64-битным кодом всё несколько проще. Насколько я понял, там спасает ключ компилятора -mabi=ms. Тем не менее, мне очень интересно, что за магия происходит в wrap_handler и как Rust понимает, что нужно использовать соглашения о вызовах MSVC вместо System V без -mabi=ms.
Хорошая статья, однако, у меня есть пару идей, как можно было бы сделать её ещё лучше.
На мой взгляд, первые пункты про запись образа диска и установку CentOS можно было бы и опустить. Думаю, что человек, поставивший себе задачу поднять свой репозиторий, самостоятельно сможет справиться с установкой системы.
Инструкция в виде готового рецепта неплоха, но всегда лучше, когда для каждого действия объяснена причина, последствия, а также случаи, когда можно этим действием пренебречь.
Также, для улучшения восприятия, в примерах хотелось бы видеть большую сфокусированность именно на процессе сборки, а не на особенностях конфигурации tmux'а. Но это уже так, придирки.
Не уверен, что подстановка 0 вместо именованной константы в общем случае хорошая идея. Думаю, что было бы правильнее изучить аналогичные вызовы irequest_irq в других драйверах чтобы найти аналогичную по смыслу именованную константу для нового ядра (если она существует).
Я выкладывал ссылку на github проекта на reddit и один раз это делали за меня. Это, конечно, не профильные сообщества, но хоть какие-то попытки донести информацию. Если у кого-нибудь возникнет желание сделать перевод статьи и опубликовать его (со ссылкой на оригинал, естественно) — я не буду против. Мой английский пока ещё слишком беден для такого, как мне кажется.
К тому же, для реализации библиотеки была проведена обратная разработка, что прямо запрещено соглашением подписчика Steam. Не думаю, что они будут в восторге. Похожая разработка — SteamBridge (которая упоминается в статье) благополучно игнорировалась службой поддержки Valve. Они даже отказывались ответить на вопрос о легальности подобного подхода. Насколько я понял из ответов на запросы в багтрекере Steam для Linux, политика Valve в отношении Wine весьма однозначна: они не слишком стремятся поддерживать запуск игр для Windows из Steam в Linux в таком виде. Тем более, что о возможности собирать steam_api.dll.so для Wine им рассказывали в комментариях (а при наличии исходных кодов им это сделать намного проще).
Вот и я о том же. Соглашусь, что имело место некоторое преувеличение, но в любом случае установка нескольких копий одной программы не очень удобна. Особенно если есть привычка устанавливать каждую игру в отдельный префикс, чтобы исключить взаимное влияние.
Ну надо же, я как раз недавно писал библиотеку для сериализации/десериализации с похожим принципом действия для Nim. Если кому интересно, вот она + краткий мануал.
Пусть обилием поддерживаемых форматов она не может похвастаться, но принцип действия, если я правильно всё понял, тот же. Структура, которую нужно сериализовать передается на вход макросу, а он генерирует соответствующие функции для сериализации/десериализации.
Большое спасибо за Вашу статью. После прочтения её и статьи от Commandos, я стал понимать, почему мой лучший результат был таким не радужным (удалось войти в первую сотню, и то не надолго, в основном на 100-200 местах болтался).
Моя стратегия была намного проще.
Ключевым местом в механизме принятия решений была цепочка правил, которые срабатывали в зависимости от ситуации вокруг или передавали управление дальше по цепочке.
Первые несколько версий вообще не умели в поиск пути, а обход препятствий осуществлялся по факту застревания. Волшебник просто ходил за союзными миньонами, пока не натыкался на противников и не срабатывало более приоритетное правило.
После был прикручен обход препятствий по касательной. Т. е. если луч, построенный от центра волшебника до цели пересекал окружность с центром в центре препятствия и радиусом равном сумме радиусов волшебника и препятствия, то результирующий угол поворота волшебника отклонялся минимальную величину, при которой траектория волшебника шла по касательной к препятствию.
Через несколько игр я обнаружил, что подбор бонусов дает ощутимое преимущество, после чего пришлось реализовывать полноценный поиск пути по путевым точкам в дополнение к обходу препятствий. За основу был взят алгоритм Ли, с добавлением к нему возможности учет веса вершин и ребер графа (вес ребер зависел от длины ребра и наличия на ребре врагов, а вершины только от наличия врагов). Граф состоял всего из 5 точек: углы карты и центр. Для реализации плавного движения, в окрестностях точек результирующее направление движения получалось сложением углов до ближайшей точки и до следующей.
К сожалению, после второго раунда у меня совершенно не осталось времени на стратегию. К тому же, я писал код из расчета на один раз и он, в конце концов, превратился в слабочитаемую лапшу из костылей.
Последнее, изменение при поиске пути было сделано уже после финала. Я попытался воспользоваться методом потенциальных полей вместо обхода пути по касательной, но, к сожалению, такое решение только ухудшило ситуацию.
Не уверен, что кому-то интересны подробности реализации работы моей стратегии, потому, если кому интересно, можете поковырять код по ссылке. За боль в области глаз при взляде на этот код, ответственности не несу. Вы были предупреждены.
Использую awesome на своей машине и xfce4 на домашней.
Awesome выбран из-за его минимализма и сумасшедшей расширяемости.
В xfce4 привлекает сочетание все того же минимализма (пусть и несколько уступающего awesome) и привычного большинству пользователей окружения.
1. Временем компиляции
2. Негибкостью (хороши только если одну функцию надо написать для нескольких типов, но как только начинают решаться проблемы из реального мира, приходится изобретать монструозную конструкцию из шаблонов, а то и вообще откатываться к макросам из C)
3. Сообщениями об ошибках (без парсера в них можно утонуть)
В Nim метапрограммирование на порядок лучше плюсового реализовано.
Функции, процедуры, дженерики, мультиметоды, шаблоны, макросы.
Именно в таком порядке по приоритету. Если первого пункта недостаточно для реализации необходимого функционала, переходим к следующему и так далее. К сожалению, не могу вспомнить где в документации видел приоритетность, но она была очень похожа на эту. Разве что мультиметодов и функций там не было. Мультиметоды я бы вообще исключил, поскольку они почти всё время были сломаны.
Говоря «модули» я имел в виду отдельные проекты в терминах CMake. Например проблема в том, что я не могу собрать отдельно проект A, не собирая B и не используя CMakeLists.txt из корня.
Конечно это вкусовщина. Я просто привык, что символ пунктуации в тексте программы это своего рода якорь, за который можно уцепиться глазами. Думаю и так понятно, во что превращается текст программы, почти полностью состоящий из таких якорей.
Надеюсь, это был сарказм. Разве нагромождение символов пунктуации читабельнее обычных английских слов с редкими вкраплениями пунктуации?
Макросы поддерживают работу с синтаксическим деревом.
Кортежи без предварительного объявления
Лямбды:
Удобная система сборки: nimble
Не хватает разве что ленивых вычислений из коробки (но можно сделать за счёт макросов) и хорошей интеграции с IDE, но это дело наживное. Ах, да, ещё подсветки синтаксиса хабрадвижком, чтобы не пользоваться питоновской подсветкой.
Отличная статья! Я бы даже сказал: о наболевшем, а именно о мучениях с ABI C++.
Однако, я не смог понять, как Вам удалось справиться с соглашениями о вызовах. Если речь идёт о 32-битном коде, то просто объявления статических функций и заполнения ими таблицы виртуальных методов недостаточно, поскольку виртуальные методы используют соглашение о вызовах
thiscall
, тогда как функции обычно используютstdcall
.С 64-битным кодом всё несколько проще. Насколько я понял, там спасает ключ компилятора
-mabi=ms
. Тем не менее, мне очень интересно, что за магия происходит вwrap_handler
и как Rust понимает, что нужно использовать соглашения о вызовах MSVC вместо System V без-mabi=ms
.На мой взгляд, первые пункты про запись образа диска и установку CentOS можно было бы и опустить. Думаю, что человек, поставивший себе задачу поднять свой репозиторий, самостоятельно сможет справиться с установкой системы.
Инструкция в виде готового рецепта неплоха, но всегда лучше, когда для каждого действия объяснена причина, последствия, а также случаи, когда можно этим действием пренебречь.
Также, для улучшения восприятия, в примерах хотелось бы видеть большую сфокусированность именно на процессе сборки, а не на особенностях конфигурации tmux'а. Но это уже так, придирки.
Не уверен, что подстановка
0
вместо именованной константы в общем случае хорошая идея. Думаю, что было бы правильнее изучить аналогичные вызовыirequest_irq
в других драйверах чтобы найти аналогичную по смыслу именованную константу для нового ядра (если она существует).Я выкладывал ссылку на github проекта на reddit и один раз это делали за меня. Это, конечно, не профильные сообщества, но хоть какие-то попытки донести информацию. Если у кого-нибудь возникнет желание сделать перевод статьи и опубликовать его (со ссылкой на оригинал, естественно) — я не буду против. Мой английский пока ещё слишком беден для такого, как мне кажется.
К тому же, для реализации библиотеки была проведена обратная разработка, что прямо запрещено соглашением подписчика Steam. Не думаю, что они будут в восторге. Похожая разработка — SteamBridge (которая упоминается в статье) благополучно игнорировалась службой поддержки Valve. Они даже отказывались ответить на вопрос о легальности подобного подхода. Насколько я понял из ответов на запросы в багтрекере Steam для Linux, политика Valve в отношении Wine весьма однозначна: они не слишком стремятся поддерживать запуск игр для Windows из Steam в Linux в таком виде. Тем более, что о возможности собирать
steam_api.dll.so
для Wine им рассказывали в комментариях (а при наличии исходных кодов им это сделать намного проще).Пусть обилием поддерживаемых форматов она не может похвастаться, но принцип действия, если я правильно всё понял, тот же. Структура, которую нужно сериализовать передается на вход макросу, а он генерирует соответствующие функции для сериализации/десериализации.
Моя стратегия была намного проще.
Ключевым местом в механизме принятия решений была цепочка правил, которые срабатывали в зависимости от ситуации вокруг или передавали управление дальше по цепочке.
Первые несколько версий вообще не умели в поиск пути, а обход препятствий осуществлялся по факту застревания. Волшебник просто ходил за союзными миньонами, пока не натыкался на противников и не срабатывало более приоритетное правило.
После был прикручен обход препятствий по касательной. Т. е. если луч, построенный от центра волшебника до цели пересекал окружность с центром в центре препятствия и радиусом равном сумме радиусов волшебника и препятствия, то результирующий угол поворота волшебника отклонялся минимальную величину, при которой траектория волшебника шла по касательной к препятствию.
Через несколько игр я обнаружил, что подбор бонусов дает ощутимое преимущество, после чего пришлось реализовывать полноценный поиск пути по путевым точкам в дополнение к обходу препятствий. За основу был взят алгоритм Ли, с добавлением к нему возможности учет веса вершин и ребер графа (вес ребер зависел от длины ребра и наличия на ребре врагов, а вершины только от наличия врагов). Граф состоял всего из 5 точек: углы карты и центр. Для реализации плавного движения, в окрестностях точек результирующее направление движения получалось сложением углов до ближайшей точки и до следующей.
К сожалению, после второго раунда у меня совершенно не осталось времени на стратегию. К тому же, я писал код из расчета на один раз и он, в конце концов, превратился в слабочитаемую лапшу из костылей.
Последнее, изменение при поиске пути было сделано уже после финала. Я попытался воспользоваться методом потенциальных полей вместо обхода пути по касательной, но, к сожалению, такое решение только ухудшило ситуацию.
Не уверен, что кому-то интересны подробности реализации работы моей стратегии, потому, если кому интересно, можете поковырять код по ссылке. За боль в области глаз при взляде на этот код, ответственности не несу. Вы были предупреждены.
Awesome выбран из-за его минимализма и сумасшедшей расширяемости.
В xfce4 привлекает сочетание все того же минимализма (пусть и несколько уступающего awesome) и привычного большинству пользователей окружения.