All streams
Search
Write a publication
Pull to refresh
34
0
Антон Гуща @NCrashed

User

Send message
Спасибо, добавил в пост про GC и структуры. Встроенные юниттесты не влезли в оригинальную структуру статьи, добавлю чуть позже доп. пунктом.
Уже использовал его в реальных проектах (сильно больше 1к строк), на серьезные баги не натыкался. Были проблемы с контрактами, они просто во многих случаях не вызывались, а должны были. Еще довольно жестокие грабли — __gshared модификатор, лучше его не использовать. Неаккуратное его использование может приводить к утечкам памяти и боли при синхронизации (ну это его назначение).
В D есть такие ассоциативные мапы:
string[float] map0;
double[string][string] map1;
bool[bool][string][float] map2;

map0[42.0] = "foo";
assert(42.0 in map0);

map1["foo"]["bar"] = 42.0;
foreach(k1, submap; map1)
    foreach(k2, val; submap)
        std.stdio.writeln(k1, " ", k2, " ", val);

assert(map0.keys == [42.0]);
assert(map0.values == ["foo"]);


Также можно в качестве ключей использовать свои типы, для этого нужно перегрузить операторы:
const hash_t toHash();
const bool opEquals(ref const KeyType s);
const int opCmp(ref const KeyType s);


Полные доки: dlang.org/hash-map.html
Можно написать две программы, по одной из задач benchmarksgame.alioth.debian.org/. Я пытаюсь специализироваться в D, нужен еще спец. по Rust. Тогда можем и сравнить.
Сказывается малочисленность русскоязычного коммьюнити…
Никто кстати не желает забабахать подобное сравнение про D?


Сохранил первичную структуру поста. habrahabr.ru/post/225507/
Сравнение получается не сильно честным, примеры подобраны под сильный статический анализатор, встроенный в Rust, а D в этой области слабее.
Идеал недостижим, это не означает, что не надо к нему двигаться. Заметили часто встречающиеся грабли — исправили, обратили внимание на следующие (которые могут появиться и из-за такого исправления). Вся полезность высокоуровневых языков очевидна при сравнении, например, асма и тех же плюсов.

Однако высокую квалификацию никто не отменял, без нее и грабли не классифицируешь и не уберешь их с дороги, чтобы другим больше не мешались.
Как я понимаю пока только есть поддержка чтения/записи BMP и записи PNG?


При загрузке через SDL_image (модуль ae.utils.graphics.sdlimage) поддерживаются след. форматы (из доков sdl_image):
ICO(Icon)/CUR(Cursor)/BMP, PNM (PPM/PGM/PBM), XPM, LBM(IFF ILBM), PCX, GIF, JPEG, PNG, TGA, TIFF, and XV thumbnail formats.
Этот модуль я не тестировал, лучше спросить у автора.

А сохранение идет в BMP и PNG

Допустим, код поддерживает чтение PNG. И если main принимает в качестве аргумента имя файла, который является либо BMP, либо PNG — как реализовать чтение такого файла и его последующую обработку?


Скорей всего, я вопрос понял неправильно. Если использовать sdlimage, то часть определения формата дается на откуп либе, которая уже по расширению выбирает нужный декодер.

Если реализовывать самому, то полностью compile-time'a тут достичь нельзя. Итого все равно будет явный-неявный switch с вызовом нужного декодера. Но можно генерировать его через mixin'ы для всех поддерживаемых расширений. А получив View, уже все как в статье.
Разработчик на D.

github.com/NCrashed

Производительный веб, игрострой, эволюционные алгоритмы.
Появляется все больше и больше инструментов для финансирования открытого ПО. Но как это все оформить легально?

Допустим, у меня в голове вертится возможная схема разработки:
  • Весь код на github под copy-left лицензией, любой может собрать из исходников сам, поучаствовать в разработке, форкнуть.
  • Пользователи «покупают» продукт и получают регистрацию. На специальном разделе сайта зарегистрированные пользователи могут проголосовать за необходимые им фичи.
  • В каждый момент времени отображается текущий бюджет проекта.
  • На основе голосов пользователей бюджет проекта перераспределяется на Bountysource по каждой фиче. Любой, кто реализует фичу — получает это вознаграждение.

Скорей всего, эта схема ущербна, не подходит для большинства проектов и пр. Но вопрос в том, как такое реализовать и не наполучать от налоговой потом по голове?
А хабы данного поста были проверены тулзой? Интересно увидеть диаграмму. Я просто слепой жук.
Михалков их лично встретит и разберется.
Все же шаблоны больше подходят для операций над типами, проверки их свойств и т.п. Но для генерации кода тоже подходят:

// Через variable length arguments можно в шаблон
// передавать практически что угодно
template GenSwitch(E1, E2, TS...)
{
    // Но лучше проверять, что именно пользователь передал
    static assert(TS.length == 1);
    static assert(is(typeof(TS[0]) == string));
    enum var = TS[0];

    enum E1Members = __traits(allMembers, E1);
    enum E2Members = __traits(allMembers, E2);
    static assert(E1Members.length == E2Members.length);

    // Циклы заменяем рекурсией через nested templates
    private template GenBody(TSS...)
    {
        // через TSS передаем текущий номер итерации
        enum i = TSS[0];
        // и оставшийся кусок от E1Members
        alias TS = TSS[1..$];

        static if(TS.length == 0) // Дно рекурсии
        {
            // Процедура 'возврата значения/типа' из шаблона
            // нужно объявить enum или alias,
            // имя которого совпадает с именем шаблона
            enum GenBody = "";
        }
        else
        {
            enum GenBody = "\tcase("~E1.stringof~"."~TS[0]~"):\n\t{\n"
                         ~ "\t\twriteln("~E2.stringof~"."~E2Members[i]~");\n"
                         ~ "\t\tbreak;\n\t}\n"
                         ~ GenBody!(i+1, TS[1..$]);
        }
    }

    enum GenSwitch = "final switch("~var~")\n{\n" 
                    ~GenBody!(0, E1Members)
                    ~"}";
}
А про D очень мало информации (в книге Александреску этого нет, на официальном сайте простейший пример). Конструкция mixin — там просто строки, в которых код. Непонятно, можно ли эти строки конструировать программно, если можно — какие операции разрешены для времени компиляции и т.д.


Можно, причем двумя разными способами. Первый — выполнение функций в compile time, второй — через шаблоны. Для примера рассмотрю первый вариант. Практически любые функции, которые не используют IO, указатели и другие низкоуровневые фичи языка можно выполнять на этапе компиляции. Для этого нужно просто использовать функцию в контексте, в котором у нее нет выбора, кроме как выполниться при компиляции (например, присвоить результат к константе enum).

Иллюстрация: есть два энума A и B, нужно сгененрировать switch по элементам первого энума, который поставит в соответствие каждому элементу A элемент в B.
import std.stdio;

enum A
{
    a1,
    a2,
    a3
}

enum B
{
    b1,
    b2,
    b3
}

// Берем два энума и название переменной, для которой будет
// сгенерирован switch
string genSwitch(E1, E2)(string var)
    if(is(E1 == enum) && is(E2 == enum))
{
    // Просим компилятор выдать нам tuple всех элементов типа
    enum E1Members = __traits(allMembers, E1);
    enum E2Members = __traits(allMembers, E2);
    // Проверяем, чтобы их длинны совпадали, проверка во время компиляции
    static assert(E1Members.length == E2Members.length);

    // Используем все обычные средства для работы со строками
    // для генерации свитча
    string s = "final switch("~var~")\n{\n";
    foreach(i, member; E1Members)
    {
        s ~= "\tcase("~E1.stringof~"."~member~"):\n\t{\n";
        s ~= "\t\twriteln("~E2.stringof~"."~E2Members[i]~");\n";
        s ~= "\t\tbreak;\n\t}\n";
    }
    return s~"}";
}

void main()
{
    auto a = A.a2;
    
    // Способ вывести что-нибудь во время компиляции в консоль
    pragma(msg, genSwitch!(A, B)("a"));
    // Встраиваем сгенеренный свитч
    mixin(genSwitch!(A, B)("a"));
}


Во время компиляции увидим:
final switch(a)
{
    case(A.a1):
    {
        writeln(B.b1);
        break;
    }
    case(A.a2):
    {
        writeln(B.b2);
        break;
    }
    case(A.a3):
    {
        writeln(B.b3);
        break;
    }
}


P.S. Это просто иллюстрация. Генерацию через шаблоны того же кода, если интересно, то тоже приведу.
На самом деле я встречал очень мало проектов, где namespace использовали не в качестве имуляции модульной системы. Но в остальных случаях с открытыми namespace можно будет говорить уже об автоматичекой генерации байндингов.
Очень двоякое ощущение. С одной стороны — организация и защита «электронного правительства» должна быть именно такой. С другой стороны — белые списки программ, перепрошивка ОС (что автоматом снимает гарантии производителя), свой собственный сорм на каждый комп — это снова разделит мир железным зановесом и убьет местную коммерцию.
Предполагается, что это будет просто синтаксис для static struct (т.е. closed scope) или открытые namespace? В последнем случае это облегчит написание bindings к C++ либам.
Мелькали заявления, что маркетингом должно заниматься сообщество. Но оно все же еще очень маленькое, и пока в игру не вступили крупные компании, D будет сидеть в своей темной нише.

Этот язык с самого начала развивался стихийно, только силами небольшой кучки специалистов. Меня поражает проделанная на сей момент работа и предстоящие проблемы (например, дальнейшая разработка и адаптация инструментов).
Для дальнейших извращений рекомендую А.Александреску «Modern C++ Design», а если этого будет мало, то можно обратить взор на D (в который и ушел автор этой книги), в нем не проблема сделать compile-time raytracer, да и скорость компиляции на порядок выше C++.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity