Re[9]: Опциональные типы
От: alex_public  
Дата: 22.02.17 19:22
Оценка:
Здравствуйте, WolfHound, Вы писали:

_>>Ну вообще то ссылочные типы гораздо менее эффективны по определению, из-за введения дополнительной косвенности. Т.е. грубо говоря, если ты сравнишь проход по vector<int*> и vector<optional<int>>, то первый будет в разы медленнее. ) Так что как раз засилье ссылочных типов — это и есть инженерный идиотизм. Но да, если уж это бредовое засилье есть (причём как в Java и C#, безальтернативно — без возможности скажем разместить объект на стеке), то тогда смысла в отдельном классе типа optional действительно уже мало.

WH>1)В .НЕТ есть возможность создавать value типы которые живут в стеке, в массиве или в полях объектов. И там, где они подходят используются именно они. Но часто нужны именно ссылочные типы.

Я вроде как вполне ясно написал: "без возможности разместить объект на стеке". Объект — это общепризнанное название для экземпляра класса. И их в Java и C# никак не разместить на стеке. Кстати, в случае C# сюда стоило бы ещё добавить массивы, строки и делегаты.

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

WH>2)Если мы пытаемся получить производительность любой ценой, то массив структур за который ты тут агитируешь тоже инженерный идиотизм.

WH>Вот такой код будет работать медленней и занимать больше памяти
WH>
WH>struct Foo
WH>{
WH>  int32 field1;
WH>  int32 field2;
WH>  int32 field3;
WH>  int32 field4;
WH>  int32 field5;
WH>  int32 field6;
WH>  int8  field7;
WH>  int2  field8;
WH>}
WH>Foo array[64*1024];
WH>

WH>Чем такой
WH>
WH>struct Foo
WH>{
WH>  int32 field1[64*1024];
WH>  int32 field2[64*1024];
WH>  int32 field3[64*1024];
WH>  int32 field4[64*1024];
WH>  int32 field5[64*1024];
WH>  int32 field6[64*1024];
WH>  int8  field7[64*1024];
WH>  int2  field8[64*1024];
WH>}
WH>

WH>Посчитай промахи кэша в первом и во втором случае если нам нужно пройтись в цикле по полю field1.
WH>Также посчитает сколько памяти съест выравнивание.

Не очень понял какое отношения эти примеры имеют к данной теме. Ведь в C/C++ (а у тебя стоит для этого кода подсветка именного этого языка) эти два примера не имеют абсолютно никакой разницы в уровне косвенности — тут же нет вообще ссылочный данных.

Кстати, я что-то ничего не слышал про тип данных int2 в C++. Ну точнее я и про int32 не слышал, но подозреваю что тут у тебя просто опечатка и имелось в виду int32_t. Но вот int2_t просто не существует.

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

WH>В случае с Option<int32> мы в первом случае получим перерасход памяти и увеличение промахов кэша почти в 2 раза.


Верно. Но и во втором случае будет абсолютно тоже самое.

WH>А если в массиве много None, то промахов кэша будет ещё больше.


Эээ что? С чего это? )

WH>Причем руками можно это всё и не писать.

WH>Можно сделать что-то типа такого:
WH>
WH>aos<Foo> array[64*1024];
WH>aos<option<int32>> array[64*1024];
WH>

WH>А компилятор сам разобьёт это всё по массивам и уберёт с глаз долой все эти преобразования.
WH>Но С++ так не умеет. Там только руками.

Не очень понял что ты имеешь в виду.
Re[10]: Опциональные типы
От: Klikujiskaaan КНДР  
Дата: 22.02.17 19:25
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Я вроде как вполне ясно написал: "без возможности разместить объект на стеке". Объект — это общепризнанное название для экземпляра класса. И их в Java и C# никак не разместить на стеке. Кстати, в случае C# сюда стоило бы ещё добавить массивы, строки и делегаты.


А какое же общепризнанное название экземпляра структуры?
Re[11]: Опциональные типы
От: alex_public  
Дата: 22.02.17 20:06
Оценка:
Здравствуйте, Klikujiskaaan, Вы писали:

_>>Я вроде как вполне ясно написал: "без возможности разместить объект на стеке". Объект — это общепризнанное название для экземпляра класса. И их в Java и C# никак не разместить на стеке. Кстати, в случае C# сюда стоило бы ещё добавить массивы, строки и делегаты.

K>А какое же общепризнанное название экземпляра структуры?

Никакого) А с чего ты решил, что оно должно быть? Как бы наличие у понятия "экземпляр класса" синонима "объект" не означает обязательного наличия какого-то синонима у "экземпляра структуры".
Re[8]: Опциональные типы
От: vdimas Россия  
Дата: 22.02.17 20:17
Оценка: :)))
Здравствуйте, D. Mon, Вы писали:

V>>А если ты имел ввиду, что "ссылочность" значения прячется от системы типов, то ты в этом случае НЕ можешь рассуждать о ссылочном типе — это будет просто некая тонкость реализации.

DM>Ничего не понял тут.

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

А семантика у ссылочного типа одна — это хранить в себе т.н. "индекс" (или ключ) некоего значения.
Прикладное применение — организация абстракций, — работаем со значением не напрямую, а через индекс/ключ.

Если язык Rust контролирует значение этого индекса через систему типов, то поздравляю — это зачатки зависимых типов в языке.
А если нет, то это не ссылочный тип.


DM>Еще раз: что именно у тебя здесь означает Т+1?


Тоже, что у тебя — сумма типов, т.е. алгебраик {A t:T | B}, где A и B произвольные идентификаторы, например Just и Nothing.


V>>Правда, в этом случае не нужен промежуточный Box<T>, т.е. достаточно лишь Option<T>, не?

DM>Для чего достаточно?

Для семантики Option<Box<T>>.
Это твои слова?

Например, в Расте Box<T> и Option<Box<T>> представлены в памяти одинаково

Ты в них уверен?
Просто я залез, таки, в доку к Rust и вижу:
pub enum Option<T> {
    None,
    Some(T),
}

Обычный алгебраик, но как он реализован в Rust?

Есть же куча способов, например :
struct OptionHolder {
    TypeId discriminator_;    // или int discriminator_
};

struct None : OptionHolder {};

template<typename T>
class Some : OptionHolder { T value_; };

struct Option { OptionHolder * value_; };


— никакого null, значение None будет представлено ссылкой на единственное значение.

Но да, учитывая возможность оптимизации именно такого сценария, когда у нас сумма из двух типов, причем, один из них представлен единственным значением, то кодируем это единственное значение через null, и тогда Some(T) будет хранится в памяти как T*, а None будет просто 0.

Точно ли Rust умеет оптимизировать такие сценарии до описанного?

Потому что вот с таким определением:
pub enum Option2<T> {
    None,
    None2,
    Some(T),
}

уже такой фокус не получится.


DM>Это разные вещи получатся с разным поведением и разным представлением в памяти.


Ты же выше писал, что Option<Box<T>> и Box<T> имеют одинаковое представление?


V>>Ссылочный тип по-определению — это зависимый тип.

V>>Тот самый, угу.
V>>Т.е., тип, зависящий от значения:
V>>* валидный адрес — тип T
V>>* нулевой адрес — тип None.

DM>Стоп-стоп, во-первых у тебя тут Т уже что-то другое начал обозначать.


Почему "другое"?
T — это тип некоего значения по адресу.


DM>Во-вторых, ссылочный тип не обязательно содержит null, я ж об этом говорю. См. тот же Котлин или Раст.


Ссылочный тип обязательно содержит.

Я, таки, посмотрел на Rust только что.
Так вот, Box<T> — это НЕ ссылочный тип ни в одном из мест. Ты меня обманул. ))
Это почти точный аналог моего Strong<T>, который я давал выше.

Вот тебе твой растовский Box<T>, переписанный на Шарпе:
    // ссылочный тип-указатель
    class Ptr<T> where T : struct {
        public T Value;
    }

    // тип-обертка над ссылочным типом, хранящим value-тип
    struct Box<T> where T : struct {
        public Ptr<T> Value { get; private set; }

        public Box(T value) {
            Value = new Ptr<T> { Value = value };
        }
    }

    // тип-обертка над обычным ссылочным типом
    struct Strong<T> where T : class {
        public T Value { get; private set; }

        public Strong(T value) {
            if(value == null) throw ...;
            Value = value;
        }
    }

Обрати внимание на struct Box и struct Strong.
Оба типа хранят внутри себя ссылочный тип, но сами НЕ являются ссылочным типом.
Итого, гарантии соблюдаются не на уровне системы типов, а сугубо на прикладном.
Обрати внимания, что в моём случае невозможно добиться того, чтобы значение (Value) у Box или у Strong было равно null.
В Rust аналогично.


DM>Ну вот есть ссылочный тип string в условной джаве или шарпе.

DM>Мы можем написать string s = null;

Можем.


DM>Теперь напиши Option<string> по твоей задумке, да так, чтобы получилось T + 1, а не T.


String в дотнете и джаве — он уже является Option изкаробки, как любой настоящий ссылочный тип.
Если нужен тип, который достоверно не будет nullable, то используй Strong<string>.
Этот Strong<string> можно создать лишь однажды, а потом передавать м/у методами, распространяя однажды полученную гарантию.
Re[10]: Опциональные типы
От: WolfHound  
Дата: 22.02.17 20:18
Оценка: +2
Здравствуйте, alex_public, Вы писали:

_>Не очень понял какое отношения эти примеры имеют к данной теме. Ведь в C/C++ (а у тебя стоит для этого кода подсветка именного этого языка) эти два примера не имеют абсолютно никакой разницы в уровне косвенности — тут же нет вообще ссылочный данных.

Похоже ты не понимаешь почему между vector<int*> и vector<int> есть существенная разница в производительности.
Разница в том, что в первом случае намного больше промахов кэша.
А косвенность, к которой ты прицепился сама по себе особого значения не имеет.

_>Кстати, я что-то ничего не слышал про тип данных int2 в C++. Ну точнее я и про int32 не слышал, но подозреваю что тут у тебя просто опечатка и имелось в виду int32_t. Но вот int2_t просто не существует.

Тут не про С++. Тут про некий похожий язык в которых такие типы есть.
Просто раскраска С++ подходит.

_>Ну и да, т.к. разницы в косвенности между этими примерами нет, то выбирать из этих двух вариантов надо в зависимости от планируемых в будущем итераций.

А разница в потреблении памяти и количестве промахов кеша есть.

WH>>В случае с Option<int32> мы в первом случае получим перерасход памяти и увеличение промахов кэша почти в 2 раза.

_>Верно. Но и во втором случае будет абсолютно тоже самое.
WH>>А если в массиве много None, то промахов кэша будет ещё больше.
_>Эээ что? С чего это? )
Option<int32> занимает 33 бита. 32 на int32 и один для определения есть значение или нет.
Но для выравнивания компилятор добавить ещё 31 бит в которых ничего не будет. Они будут тупо жрать память и увеличивать трафик памяти.
А если Option<int32> преобразовать в структуру массивов, то у нас будут два массива. Один состоящий из int32. А второй состоящий из однобитных значений.
Те компилятор фактически сгенерирует вот такой код:
int32 options_Value[1024*1024];
bool  options_IsValue[1024*1024];//bool однобитный тип. Массив упакован плотно без дырок. 
//Те в каждом байте у нас лежит 8 bool'ов.
for (int32 i = 0; i < 1024*1024; ++i)
{
    if (options_IsValue[i])
    {
        //делаем что-то с options_Value[i]
    }
}

Тут у нас есть два крайних случая.
1)Везде Some(что-то)
2)Везде None
В первом случае мы прочитаем в 33 раза больше памяти чем во втором.
А если без разбиения на массивы, то в 64 раза больше. Причём всегда.
А доступ к памяти удовольствие дорогое.

ЗЫ Следи за цитированием.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Опциональные типы
От: vdimas Россия  
Дата: 22.02.17 20:24
Оценка:
Здравствуйте, fddima, Вы писали:

F>Просто забавно читать как все упёрлись в 0. А как же 1, 2... где же фантазия.


Всё уперлось в некий тип None, у которого будет ровно одно валидное значение.

Итого, тут два варианта:
  • либо использовать единственный инстанс этого None и его адрес как признак этого самого None;
  • либо "сократить его в уме" и вместо ссылки на некое (никому не нужное) единственное значение использовать некий зарезервированный адрес.

    ИМХО, выбор 0 — неплох. Например, FFFF был бы хуже, т.к. проверка была чуть дороже и вообще, значение зависит от битовой ширины адреса.

    А еще язык С (и С++) так хитро устроен, что способен приводить целочисленное значение 0 к типу указателя на любой тип. О как! )) Эдакий хак. В Джава и дотнете для аналогичного ввели специальное ключевое слово, чтобы не насиловать систему типов.
  • Re[12]: Опциональные типы
    От: Klikujiskaaan КНДР  
    Дата: 22.02.17 20:30
    Оценка:
    Здравствуйте, alex_public, Вы писали:

    _>Здравствуйте, Klikujiskaaan, Вы писали:


    _>>>Я вроде как вполне ясно написал: "без возможности разместить объект на стеке". Объект — это общепризнанное название для экземпляра класса. И их в Java и C# никак не разместить на стеке. Кстати, в случае C# сюда стоило бы ещё добавить массивы, строки и делегаты.

    K>>А какое же общепризнанное название экземпляра структуры?

    _>Никакого) А с чего ты решил, что оно должно быть? Как бы наличие у понятия "экземпляр класса" синонима "объект" не означает обязательного наличия какого-то синонима у "экземпляра структуры".


    Т.е. экземпляр структуры — это не объект?
    Re[3]: Опциональные типы
    От: meadow_meal  
    Дата: 22.02.17 22:06
    Оценка:
    Здравствуйте, vdimas, Вы писали:

    V>Здравствуйте, meadow_meal, Вы писали:


    _>>Optional<Optional<ClanID>> clan;

    _>>В этом случае наличие значения clan означает, что информация передана клиенту, наличие значения clan.value означает, что пришел новый клан игрока, а его отсутствие — что игрок больше не состоит в клане.

    V>

    V>За такое увольнять нафик.

    Так предложи альтернативу.

    Задача: имеется сущность Xxx, содержащая следующие свойства:
    T1 field1;
    T2 field2;
    ...

    В IDL нужно объявить протокольный дельта-рекорд XxxUpdate для пересылки изменившихся (и только изменившихся полей). T1, T2 и т.п. могут быть различными типами, в том числе опциональными. Используются дельта-рекорды достаточно часто, поэтому требуется максимально простой паттерн с минимальным количеством частных случаев.

    Решение в лоб:
    record XxxUpdate
    {
        Optional<T1> value1;
        Optional<T2> value2;
        ...
    }

    и если T это какой-нибудь Optional<int>, то так тому и быть. Вот здесь и образуется Optional<Optional<int>>.

    V>Представляю все масштабы "удовольствия" от сопровождения такого кода. ))


    Удовольствие на практике в C# выглядит примерно так:
    public int Field1 { get; private set; }
    public int? Field2 { get; private set; }
    
    void Update(XxxUpdate update)
    {
        if (update.Field1.HasValue)
            this.Field1 = update.Field1.Value; 
        if (update.Field2.HasValue)
            this.Field2 = update.Field2.Value;
    }

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

    (Я все это уже писал вот здесь: http://rsdn.org/forum/philosophy/6702818.1
    Автор: meadow_meal
    Дата: 19.02.17
    — но возможно недостаточно внятно)

    Я ни проблем особых не вижу, ни альтернатив, так что надеюсь, что ты разъяснишь свою позицию.
    Re[11]: Опциональные типы
    От: alex_public  
    Дата: 23.02.17 02:23
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    _>>Не очень понял какое отношения эти примеры имеют к данной теме. Ведь в C/C++ (а у тебя стоит для этого кода подсветка именного этого языка) эти два примера не имеют абсолютно никакой разницы в уровне косвенности — тут же нет вообще ссылочный данных.

    WH>Похоже ты не понимаешь почему между vector<int*> и vector<int> есть существенная разница в производительности.
    WH>Разница в том, что в первом случае намного больше промахов кэша.
    WH>А косвенность, к которой ты прицепился сама по себе особого значения не имеет.

    "Похоже ты не понимаешь, почему машина останавливается. Это происходит потому, что отключается двигатель. А тот факт, что в машине закончилось топливо, особого значения не имеет" (C) ПрактическиТы )))

    _>>Кстати, я что-то ничего не слышал про тип данных int2 в C++. Ну точнее я и про int32 не слышал, но подозреваю что тут у тебя просто опечатка и имелось в виду int32_t. Но вот int2_t просто не существует.

    WH>Тут не про С++. Тут про некий похожий язык в которых такие типы есть.
    WH>Просто раскраска С++ подходит.

    Что-то не припомню языка с реальным (т.е. чтобы массив из 4-ёх штук занимал один байт) двухбитовым типом. Максимум что вспоминается, это битовые поля C++, но они опять же не позволяют задавать массивов. Снова фантазируешь? )

    _>>Ну и да, т.к. разницы в косвенности между этими примерами нет, то выбирать из этих двух вариантов надо в зависимости от планируемых в будущем итераций.

    WH>А разница в потреблении памяти и количестве промахов кеша есть.

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

    WH>Option<int32> занимает 33 бита. 32 на int32 и один для определения есть значение или нет.

    WH>Но для выравнивания компилятор добавить ещё 31 бит в которых ничего не будет. Они будут тупо жрать память и увеличивать трафик памяти.
    WH>А если Option<int32> преобразовать в структуру массивов, то у нас будут два массива. Один состоящий из int32. А второй состоящий из однобитных значений.
    WH>Те компилятор фактически сгенерирует вот такой код:
    WH>
    WH>int32 options_Value[1024*1024];
    WH>bool  options_IsValue[1024*1024];//bool однобитный тип. Массив упакован плотно без дырок. 
    WH>//Те в каждом байте у нас лежит 8 bool'ов.
    WH>for (int32 i = 0; i < 1024*1024; ++i)
    WH>{
    WH>    if (options_IsValue[i])
    WH>    {
    WH>        //делаем что-то с options_Value[i]
    WH>    }
    WH>}
    WH>

    WH>Тут у нас есть два крайних случая.
    WH>1)Везде Some(что-то)
    WH>2)Везде None
    WH>В первом случае мы прочитаем в 33 раза больше памяти чем во втором.
    WH>А если без разбиения на массивы, то в 64 раза больше. Причём всегда.

    Не верно, будет 64 и 32 раза, но это не суть, просто мелкое замечание. )

    WH>А доступ к памяти удовольствие дорогое.


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

    Если мы уходим от использование optional (причём не в сторону ссылочных данных, а наоборот на ещё более низкий уровень битовых полей и т.п.), то возникают уже совершенно другие расклады по производительности (причём это применимо и к варианту без разбиения на массивы — там же тоже можно сделать более интересный код без optional).
    Re[13]: Опциональные типы
    От: alex_public  
    Дата: 23.02.17 02:36
    Оценка:
    Здравствуйте, Klikujiskaaan, Вы писали:

    _>>Никакого) А с чего ты решил, что оно должно быть? Как бы наличие у понятия "экземпляр класса" синонима "объект" не означает обязательного наличия какого-то синонима у "экземпляра структуры".

    K>Т.е. экземпляр структуры — это не объект?

    Смотря в каком языке. Скажем в C и C# — нет, т.к. не удовлетворяют требованиям ООП. А в том же C++, где классы и структуры почти не отличимы, вполне можно обозвать экземпляр структуры объектом.

    P.S. Естественно мы тут говорим о компьютерной терминологии (в частности об ООП), а не о бытовом значение слова объект, которое можно применить почти к любой сущности в коде. )))
    Re[9]: Опциональные типы
    От: D. Mon Великобритания http://thedeemon.livejournal.com
    Дата: 23.02.17 03:13
    Оценка: +1 :)
    Здравствуйте, vdimas, Вы писали:

    DM>>Еще раз: что именно у тебя здесь означает Т+1?

    V>Тоже, что у тебя — сумма типов, т.е. алгебраик {A t:T | B}, где A и B произвольные идентификаторы, например Just и Nothing.

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

    V>>>Правда, в этом случае не нужен промежуточный Box<T>, т.е. достаточно лишь Option<T>, не?

    DM>>Для чего достаточно?
    V>Для семантики Option<Box<T>>.

    Ну так она будет отличаться от Option<T>.

    V>Это твои слова?

    V>

    Например, в Расте Box<T> и Option<Box<T>> представлены в памяти одинаково

    V>Ты в них уверен?

    Вот из доки слова:
    This usage of Option to create safe nullable pointers is so common that Rust does special optimizations to make the representation of Option<Box<T>> a single pointer. Optional pointers in Rust are stored as efficiently as any other pointer type.
    https://doc.rust-lang.org/1.10.0/std/option/index.html

    V>Точно ли Rust умеет оптимизировать такие сценарии до описанного?


    А ты точно читал доку?

    DM>>Это разные вещи получатся с разным поведением и разным представлением в памяти.

    V>Ты же выше писал, что Option<Box<T>> и Box<T> имеют одинаковое представление?

    Я про Option<Box<T>> и Option<T>.

    DM>>Во-вторых, ссылочный тип не обязательно содержит null, я ж об этом говорю. См. тот же Котлин или Раст.

    V>Ссылочный тип обязательно содержит.

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

    V>Обрати внимание на struct Box и struct Strong.

    V>Оба типа хранят внутри себя ссылочный тип, но сами НЕ являются ссылочным типом.

    Почему именно не являются?

    DM>>Ну вот есть ссылочный тип string в условной джаве или шарпе.

    DM>>Мы можем написать string s = null;
    V>Можем.

    DM>>Теперь напиши Option<string> по твоей задумке, да так, чтобы получилось T + 1, а не T.


    V>String в дотнете и джаве — он уже является Option изкаробки, как любой настоящий ссылочный тип.


    Нет. Еще раз напомню про T+1, T+1+1 и т.д.
    Попробуй сформулировать точно определение ссылочного типа и определение Option<T>.
    Re[9]: Опциональные типы
    От: fddima  
    Дата: 23.02.17 03:55
    Оценка: +1
    Здравствуйте, vdimas, Вы писали:

    Эмм, с null/0 то понятно.
    Я говорил, что для ссылочного T некий Option2<T> с None и None2 вполне представим в виде всё того же указателя с двумя спец. значениями.
    Безусловно — проверки дороже, но хотя бы с точки зрения хранения — явно компактнее чем тянуть байт и указатель.
    Re[4]: Опциональные типы
    От: vdimas Россия  
    Дата: 23.02.17 04:01
    Оценка:
    Здравствуйте, meadow_meal, Вы писали:

    _>Так предложи альтернативу.


    Если речь об IDL, то проблемно-ориентированное кодирование всей твоей матрешки идёт вот так:
    enum ClanUpdate { NoUpdate, EnterClan, ExitClan };
    
    union ClanEvent switch (ClanUpdate) { 
           case NoUpdate: ; 
           case EnterClan: int ClanId; 
           case ExitClan: ; 
    };


    Если разновидность IDL с автоопределением типа дискриминанта, то будет даже проще:
    union ClanEvent { 
           case NoUpdate: ; 
           case EnterClan: int ClanId; 
           case ExitClan: ; 
    };

    (не надо явно вводить `enum ClanUpdate`)

    Итого, для случая выхода из клана тоже достаточно одного байта, а не два, как у тебя сейчас.

    Но можно еще проще.
    Считаем, что "игрок больше не состоит в клане" — это тоже клан такой. Эдакий клан бесклановых игроков.
    Выдели для него некий отдельный ID.
    И далее можно унифицировано обновлять поля в плоском сообщении без геммороя со вложенными Nullable в другие Nullable.


    _>Задача: имеется сущность Xxx, содержащая следующие свойства:


    Задача тривиальная.


    _>Решение в лоб:

    _>
    _>record XxxUpdate
    _>{
    _>    Optional<T1> value1;
    _>    Optional<T2> value2;
    _>    ...
    _>}
    _>

    _>и если T это какой-нибудь Optional<int>, то так тому и быть. Вот здесь и образуется Optional<Optional<int>>.

    А вот решение так себе.
    Ты в сетку как передаёшь?
    По байту на признак наличия каждого поля? Если брать IDL, то меньше байта не выйдет, верно? А если не проконтроллировать размер дискриминанта в union, то может легко быть и 2 байта и 4 байта. ))

    В общем, использовать IDL в 2017-м (CORBA IDL небось?) — это вообще признак оторванности от реальности.

    А полей сколько? Предположим, что у тебя 30 полей, а в среднем за раз передаются 2-3 поля?
    И ты на каждое обновление пробегаешься по всем 30-ти полям, что ле, вот в этой манере:
    void Update(XxxUpdate update)
    {
        if (update.Field1.HasValue)
            this.Field1 = update.Field1.Value; 
        if (update.Field2.HasValue)
            this.Field2 = update.Field2.Value;
    ...

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

    Когда полей посылается много, то можно вначале прогнать битовую маску. Сетевые драйвера баз данных, кста, зачастую делают точно так же: для каждой передаваемой записи, если в ней встречаются Nullable-поля, передаётся сначала битовая маска. И да, в этой битовой маске участвуют только Nullable поля. Например, если полей 16, но Nullable из них всего два, то обе стороны знают, что на маску будет выделен 1 байт в потоке.

    Ну или можно взять какой-нить ASN.1 с хорошим профилём упаковки.
    Но можно и самому набросать сериализатор. А еще лучше самому набросать утилиту генерации сериализатора по метаинформации, раз уж речь о дотнете, благо по состоянию на 2017-й год инфраструктура развита сильно (можно брать BLToolkit как маппер), там трудоемкости, скорее всего, будет меньше, чем возни с сопряжением c каким-нить IDL-фреймворком.

    Через BLToolkit можно сделать так, чтобы код обновления полей вообще ручками писать не надо было.
    Отредактировано 23.02.2017 5:00 vdimas . Предыдущая версия .
    Re[10]: Опциональные типы
    От: vdimas Россия  
    Дата: 23.02.17 04:54
    Оценка: :)
    Здравствуйте, D. Mon, Вы писали:

    DM>>>Еще раз: что именно у тебя здесь означает Т+1?

    V>>Тоже, что у тебя — сумма типов, т.е. алгебраик {A t:T | B}, где A и B произвольные идентификаторы, например Just и Nothing.
    DM>Ок. Тогда утверждение о том, что любой ссылочный тип таков, я считаю ошибочным.

    Ты не можешь считать чьи-то утверждения ошибочными или нет, пока не обоснуешь.
    "Пролетарское чутьё" не считается.


    V>>Это твои слова?

    V>>

    Например, в Расте Box<T> и Option<Box<T>> представлены в памяти одинаково

    V>>Ты в них уверен?
    DM>Вот из доки слова:
    DM>This usage of Option to create safe nullable pointers is so common that Rust does special optimizations to make the representation of Option<Box<T>> a single pointer. Optional pointers in Rust are stored as efficiently as any other pointer type.
    DM>https://doc.rust-lang.org/1.10.0/std/option/index.html

    V>>Точно ли Rust умеет оптимизировать такие сценарии до описанного?

    DM>А ты точно читал доку?

    Именно что читал определения Optional и Box. А ты читал?
    В общем, если Rust умеет оптимизировать конкретную связку только этих 2-х типов — то это неинтересно. Это лишь некрасивый костыль.

    Вот если бы он из исходных определений Optional и Box получил то же самое, причем, воспроизводимое на любых других пользовательских Optional_2 и Box_3, то это был бы респект.


    DM>>>Во-вторых, ссылочный тип не обязательно содержит null, я ж об этом говорю. См. тот же Котлин или Раст.

    V>>Ссылочный тип обязательно содержит.
    DM>Нет, это твои иллюзии.

    Опять пролетарское чутьё подсказывает? ))

    Разве тебя не впечатлило, что я еще в глаза не видя этого Rust сразу сказал, где у тебя ошибка?

    Если язык Rust контролирует значение этого индекса через систему типов, то поздравляю — это зачатки зависимых типов в языке.
    А если нет, то это не ссылочный тип.

    Речь шла о твоём Box<T>.

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

    Поэтому, ты и сам должен был бы препроверить, без моей помощи, что там в Rust происходит (зависимые типы в языке или Box<> не является ссылочным типом) — ведь это ты взялся приводить примеры из этого языка, верно? Я ж за тебя столько работы сделал, получается. ))


    DM>Есть немало языков, где это не так.


    Ну, с языком Rust уже разобрались — мимо.

    Котлин не смотрел, а что там? Зависимые типы? Или строки имеют семантику value-type? ))
    Ну вот читаю вводную статью по Котлин:

    Нулевые указатели — одна из наиболее недопонятых концепций в языках программирования. Нет ничего плохого в том, что некоторое значение может быть установлено, а может отсутствовать. Такая концепция есть во многих языках программирования. В Хаскеле она называется Maybe, в F# это option, в T-SQL это null.

    Блин, прямо с языка снимают — я именно это и говорил в предыдущих постах. ))

    Почитал далее — всё ясно. Они разнесли nullable и non-nullable ссылочные типы по ТИПАМ, а не по значениям одного и того же типа.
    ЧТД. Нубы. Ниасилили ЗТ. ))

    Этот трюк полностью аналогичен Box<T> из Rust или любому показанному мною StrongRef<T>, скажем, в С++ или в другом, сколь-угодно "опасном" языке.
    Подтерждается это так же тем, что отсутствует возможность сравнивать сами ссылки.
    И переменные иммутабельны. (я правильно понял?)
    Итого — ссылочного типа в языке нет.


    V>>Обрати внимание на struct Box и struct Strong.

    V>>Оба типа хранят внутри себя ссылочный тип, но сами НЕ являются ссылочным типом.
    DM>Почему именно не являются?

    Потому что RTFM.

    Типы Box и Optional определены средствами языка.
    Первый — это struct Box, второй — enum Optional.
    Ни один из них не является ссылочным типом в системе типов Rust.

    А как конкретная комбинация типов представлена в памяти — да какая разница? Пусть даже займут ячеек размером с указатель, но в системе типов они никогда не станут эквивалентны указателю T*.

    Абсолютно точно так же, если в С++ обернуть структурой указатель:
    template<typename T>
    struct Box { T * ptr_; };

    То представление в памяти этой структуры и указателя будет идентичным. А вот в системе типов — дудки.


    DM>>>Теперь напиши Option<string> по твоей задумке, да так, чтобы получилось T + 1, а не T.

    V>>String в дотнете и джаве — он уже является Option изкаробки, как любой настоящий ссылочный тип.
    DM>Нет. Еще раз напомню про T+1, T+1+1 и т.д.

    Лучше было бы помедитировать, прежде чем опять неткать и опять мимо.
    Потому что T+1 != T+1+1
    Дальше озвучивать или уже догадался?


    DM>Попробуй сформулировать точно определение ссылочного типа и определение Option<T>.


    Я уже дал тебе определения
    тут: http://www.rsdn.org/forum/philosophy/6705938.1
    и тут: http://www.rsdn.org/forum/philosophy/6706396.1

    Ты пока не смог аргументировать ни за, ни против.
    Я могу и подождать.
    Re[10]: Опциональные типы
    От: vdimas Россия  
    Дата: 23.02.17 04:57
    Оценка:
    Здравствуйте, fddima, Вы писали:

    F> Эмм, с null/0 то понятно.

    F>Я говорил, что для ссылочного T некий Option2<T> с None и None2 вполне представим в виде всё того же указателя с двумя спец. значениями.
    F> Безусловно — проверки дороже, но хотя бы с точки зрения хранения — явно компактнее чем тянуть байт и указатель.

    Точно.
    Я как раз примерно такое и предложил рядом:
    http://www.rsdn.org/forum/philosophy/6706569.1
    Re[11]: Опциональные типы
    От: D. Mon Великобритания http://thedeemon.livejournal.com
    Дата: 23.02.17 07:15
    Оценка: +1
    Здравствуйте, vdimas, Вы писали:

    V>>>Тоже, что у тебя — сумма типов, т.е. алгебраик {A t:T | B}, где A и B произвольные идентификаторы, например Just и Nothing.

    DM>>Ок. Тогда утверждение о том, что любой ссылочный тип таков, я считаю ошибочным.
    V>Ты не можешь считать чьи-то утверждения ошибочными или нет, пока не обоснуешь.

    Ну считать-то я могу что угодно, еще как могу. Но обосновать стоит, конечно.

    Сначала несколько примеров.
    Пример первый. Окамл:
    let a = object
      val mutable n = 1
      method say = Printf.printf "n is %d\n" n
      method inc = n <- n + 1
    end;;
    
    let b = a in
    a#say;
    b#inc;
    a#say;;

    Выводит:
    n is 1
    n is 2

    Тут переменные a и b ссылаются на один объект в памяти, это переменные ссылочного типа. Мы вызываем метод, мутирующий объект b, и видим, что метод say у a теперь возвращает другое значение. Теперь попробуй в переменную такого типа записать null (ну или создать новую переменную того же типа и с нулевым значением). Не выйдет, как ни старайся, в языке Окамл ссылки не бывают нулевыми и объекты нуллами.

    Пример второй: типы вроде String и вообще классы в языке Kotlin. Это тоже ссылочные типы, с ссылочной семантикой, и null эти типы не содержат, в отличии от других типов, со знаком вопроса на конце. На уровне системы типов опять же сделаны ссылочные типы без null.

    Пример третий: Раст. Там есть ссылки вроде &T, это тоже ссылочный тип, тоже не включает null. Там есть Box<T> ("A pointer type for heap allocation." — первая же строка в описании), который хоть и описан как struct, на самом деле имеет специальную поддержку со стороны компилятора (см. ключевые слова box, owned_box и пр.) и фактически является указателем с дополнительным поведением. И он тоже всегда ненулевой.

    Короче, давай засунь null в переменную объектного типа в окамле, в &i32 в Расте и в String в Котлине. Или GTFO.

    V>Разве тебя не впечатлило, что я еще в глаза не видя этого Rust сразу сказал, где у тебя ошибка?


    У меня что-то с глазами сегодня. Я что-то не вижу ошибки, извини.

    V>Процитированное ты не переплюнешь вааще никак, бо только языки с поддержкой зависимых типов умеют контролировать строгость указателя на уровне типов.


    Выше три примера, где языки без зависимых типов именно это и делают.

    V>Почитал далее — всё ясно. Они разнесли nullable и non-nullable ссылочные типы по ТИПАМ, а не по значениям одного и того же типа.

    V>ЧТД. Нубы. Ниасилили ЗТ. ))

    Это я тут должен говорить ЧТД и называть тебя нубом. Ибо тут именно ты сел в лужу.


    DM>>>>Теперь напиши Option<string> по твоей задумке, да так, чтобы получилось T + 1, а не T.

    V>>>String в дотнете и джаве — он уже является Option изкаробки, как любой настоящий ссылочный тип.
    DM>>Нет. Еще раз напомню про T+1, T+1+1 и т.д.

    V>Лучше было бы помедитировать, прежде чем опять неткать и опять мимо.

    V>Потому что T+1 != T+1+1
    V>Дальше озвучивать или уже догадался?

    Ты опять вперед забегаешь. Давай сперва начало: Option<T> — это не тип, это конструктор типа, функтор, шаблон типа, генерик (выбери знакомое слово). Покажи, где джавский или шарповый string это генерик.

    DM>>Попробуй сформулировать точно определение ссылочного типа и определение Option<T>.


    V>Я уже дал тебе определения

    V>тут: http://www.rsdn.org/forum/philosophy/6705938.1
    V>и тут: http://www.rsdn.org/forum/philosophy/6706396.1

    Там плохие, неправильные определения. Они не описывают ссылочных типов как минимум в трех упомянутых выше языках. Давай еще подкину:
    4) &int в С++
    5) ref int в D

    Ссылочные типы? Еще как ссылочные. Содержат null / None / Nothing ? Нет.
    Re[5]: Опциональные типы
    От: meadow_meal  
    Дата: 23.02.17 09:49
    Оценка: +1
    Здравствуйте, vdimas, Вы писали:

    V>Если речь об IDL, то проблемно-ориентированное кодирование всей твоей матрешки идёт вот так:

    V>
    V>enum ClanUpdate { NoUpdate, EnterClan, ExitClan };
    
    V>union ClanEvent switch (ClanUpdate) { 
    V>       case NoUpdate: ; 
    V>       case EnterClan: int ClanId; 
    V>       case ExitClan: ; 
    V>}; 
    V>


    Сразу вопросы:

    1) А для обязательных полей ты тоже рекомендуешь объявлять enum и union? Или мы обязательные поля обновляем одним способом, а опциональные другим? Если так, то разве это — не проблема сопровождения? (Для меня одно из базовых требований при выборе паттерна — то, что придет новый человек и сможет сходу решать любую простую задачу "по аналогии".)

    2) Вот эти 6 лишних строк и один-два типа на ровном месте для каждого поля — вот ради чего это? При том, что использоваться в пользовательском коде это богатство и не будет.

    V>Итого, для случая выхода из клана тоже достаточно одного байта, а не два, как у тебя сейчас.


    У меня сейчас 1 бит в хедере + 1 байт для поля. Свести к двум битам — не проблема, только вот единственным наблюдаемым эффектом будет усложнение документации по бинарному протоколу.

    V>Но можно еще проще.

    V>Считаем, что "игрок больше не состоит в клане" — это тоже клан такой. Эдакий клан бесклановых игроков.
    V>Выдели для него некий отдельный ID.

    Это хуже по следующим причинам:
    1) Игрок больше не состоит в клане — это не тоже клан такой. Из него выйти нельзя, он в UI не отображается, у него нет ни одного атрибута клана. Я считаю, что если это различие можно выразить в системе типов, то его нужно выразить.
    2)
    public class Player
    {
        // 1
        public int ClanID { get; private set; }
        // 2
        public int? ClanID { get; private set; }
    }

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

    На самом деле это мы как раз пробовали в первую очередь. Люди плевались и просили Optional<Optional<>>.

    V>И далее можно унифицировано обновлять поля в плоском сообщении без геммороя со вложенными Nullable в другие Nullable.


    Вот это называется унифицированно? Когда на каждый чих нужно придумывать клан который не клан?

    V>Ты в сетку как передаёшь?

    V>По байту на признак наличия каждого поля? Если брать IDL, то меньше байта не выйдет, верно?

    По биту.

    V>В общем, использовать IDL в 2017-м (CORBA IDL небось?) — это вообще признак оторванности от реальности.


    А как в 2017 нужно описывать сетевой протокол с поддержкой сериализации для разных языков и форматов и возможностью генерации схемы?

    IDL внутренней разработки.

    V>И ты на каждое обновление пробегаешься по всем 30-ти полям, что ле, вот в этой манере:

    V>
    V>void Update(XxxUpdate update)
    V>{
    V>    if (update.Field1.HasValue)
    V>        this.Field1 = update.Field1.Value; 
    V>    if (update.Field2.HasValue)
    V>        this.Field2 = update.Field2.Value;
    V>...
    V>


    Да. А что именно смущает? Я уже писал, этот код можно сгенерировать.

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


    Для дельта-рекордов мы так и делаем.

    V>Ну или можно взять какой-нить ASN.1 с хорошим профилём упаковки.


    Нельзя. У ASN.1 крайне неудобный язык и нет возможности удобно контролировать кодогенерацию через атрибуты. С сериализацией в JSON или XML тоже беда. А упаковка у нас компактнее и быстрее.

    V>А еще лучше самому набросать утилиту генерации сериализатора по метаинформации, раз уж речь о дотнете, благо по состоянию на 2017-й год инфраструктура развита сильно (можно брать BLToolkit как маппер), там трудоемкости, скорее всего, будет меньше, чем возни с сопряжением c каким-нить IDL-фреймворком.


    Я писал, что сервер у нас на Эрланге. И вообще, дотнет-клиент (на самом деле Unity3d, у которого до сих пор рантайм 2.0) — лишь один из, кроме него есть большой набор приложений, работающих с данными IDL. Поэтому внешний IDL — это обязательное требование.

    Возни с ним нет. Это отработано годами.

    V>Через BLToolkit можно сделать так, чтобы код обновления полей вообще ручками писать не надо было.


    Так и приведенный код обновления полей я могу сгенерировать скриптом расширения к нашему кодогенератору строк так на восемь. Но хватает и тонкостей, например с обновлением коллекций (а там пока каждый второй случай — частный), поэтому проще в итоге писать руками.

    Резюмируя: я просил привести альтернативы и описать проблемы с текущим решением. Две альтернативы ты привел, одна из них очень многословная и спорная (а компенсирующих преимуществ я пока не вижу). Вторая — грязноватый хак, уже опробованный на практике с негативным эффектом. А вот в чем проблема с текущим решением и его якобы тяжелой поддержкой ты так и не объяснил.
    Re[6]: Опциональные типы
    От: vdimas Россия  
    Дата: 23.02.17 11:30
    Оценка:
    Здравствуйте, meadow_meal, Вы писали:

    V>>Если речь об IDL, то проблемно-ориентированное кодирование всей твоей матрешки идёт вот так:

    V>>
    V>>enum ClanUpdate { NoUpdate, EnterClan, ExitClan };
    
    V>>union ClanEvent switch (ClanUpdate) { 
    V>>       case NoUpdate: ; 
    V>>       case EnterClan: int ClanId; 
    V>>       case ExitClan: ; 
    V>>}; 
    V>>


    _>Сразу вопросы:


    _>1) А для обязательных полей ты тоже рекомендуешь объявлять enum и union? Или мы обязательные поля обновляем одним способом, а опциональные другим?


    Я уже ответил тебе исчерпывающе.

    1. Идея использовать union — она твоя, я лишь показал кривизну этого сценария с Opntional<Optional<ClanId>>.

    2. Затем предложил еще два варианта упаковки сообщений и даже дал тебе как раз сценарий из сетевых дров БД, когда в одном потоке иду обязательные и необязательные поля.


    _>Если так, то разве это — не проблема сопровождения? (Для меня одно из базовых требований при выборе паттерна — то, что придет новый человек и сможет сходу решать любую простую задачу "по аналогии".)


    А я тебе предложил взять BLToolkit и всё что потребуется сделать новому человеку — это правильно расставить атрибуты в добавляемых/исправляемых структурах и их полях.


    _>2) Вот эти 6 лишних строк и один-два типа на ровном месте для каждого поля — вот ради чего это?


    Чтобы пришедшие после тебя не материли тебя, не проклинали, не выбросили нахрен твоё поделие и не писали своё.


    _>У меня сейчас 1 бит в хедере + 1 байт для поля. Свести к двум битам — не проблема, только вот единственным наблюдаемым эффектом будет усложнение документации по бинарному протоколу.


    Если у тебя 1 бит в заголовке, то ты морочишь мне голову и насчет IDL и насчет Optional.
    Получается, насосал из пальца несуществующий сценарий.


    _>Это хуже по следующим причинам:

    _>1) Игрок больше не состоит в клане — это не тоже клан такой. Из него выйти нельзя, он в UI не отображается, у него нет ни одного атрибута клана. Я считаю, что если это различие можно выразить в системе типов, то его нужно выразить.

    Для этого надо, чтобы язык такое позволял, а дотнет тебе такое НЕ позволит. В системе типов дотнета у тебя всегда будет Optional<ClanId> — т.е. алгебраическая сумма всех валидных значений ClanId плюс одно специальное.

    А у тебя точно ВСЕ допустимые значения ClanId будут являться валидными?



    _>2)

    _>
    _>public class Player
    _>{
    _>    // 1
    _>    public int ClanID { get; private set; }
    _>    // 2
    _>    public int? ClanID { get; private set; }
    _>}
    _>

    _>Нужно проверить, состоит ли игрок в клане. В каком из случаев очевидно, как это сделать, а в каком остается чесать репу?


    Вот так будет очевидно:
    enum ClanId {
        NotSet = 0;
    }


    _>3) Теперь для каждого случая обновления опционального по своей природе поля мы будем придумывать новый хак?


    Т.е. ты не понял ни строчки из сообщения, на которое отвечаешь? ))


    _>На самом деле это мы как раз пробовали в первую очередь. Люди плевались и просили Optional<Optional<>>.


    Из пальца вытяжки пошли уже. ))
    Потому что чаще люди плюются на вложенность Optional.
    И вообще на любую вложенность.


    V>>И далее можно унифицировано обновлять поля в плоском сообщении без геммороя со вложенными Nullable в другие Nullable.

    _>Вот это называется унифицированно? Когда на каждый чих нужно придумывать клан который не клан?

    А как же они пользуются методом IndexOf, бедные, если оно возвращает специальное значение -1?


    V>>Ты в сетку как передаёшь?

    V>>По байту на признак наличия каждого поля? Если брать IDL, то меньше байта не выйдет, верно?
    _>По биту.

    ЧТД. Наврал с три короба про IDL.
    Итого, в отсутствии IDL-компилятора ты предлагаешь ручками оперировать с discriminated union?
    И после этого у тебя поднимается рука обвинять кого-то в сложности?


    V>>В общем, использовать IDL в 2017-м (CORBA IDL небось?) — это вообще признак оторванности от реальности.

    _>А как в 2017 нужно описывать сетевой протокол с поддержкой сериализации для разных языков и форматов и возможностью генерации схемы?

    Нет это ты мне ответь, как ты умудрился в IDL закодировать Optional через один бит.


    _>IDL внутренней разработки.


    Т.е. вы разработали синтаксический и семантический анализатор собственной версии IDL, а так же кодогенератор для разных языков, а так же для каждого из языков разработали однозначные правила маппинга типов вашего IDL на типы языка. Я ничего не пропустил?

    Ребят, вы динамите инвестора, реально.
    Занимаетесь не делом, а тем, что вам интересно — побочными какими-то вещами.
    И после этого у тебя хватает совести задавать вопросы из разряда:

    Когда на каждый чих нужно придумывать клан который не клан?




    V>>И ты на каждое обновление пробегаешься по всем 30-ти полям, что ле, вот в этой манере:

    V>>
    V>>void Update(XxxUpdate update)
    V>>{
    V>>    if (update.Field1.HasValue)
    V>>        this.Field1 = update.Field1.Value; 
    V>>    if (update.Field2.HasValue)
    V>>        this.Field2 = update.Field2.Value;
    V>>...
    V>>


    _>Да. А что именно смущает? Я уже писал, этот код можно сгенерировать.


    Смущает, что если это ручной код, то за это вон из профессии.
    ORM слышал?
    Ручками в 2017-м не принято.

    А если это автогенерённый код, то вон из профессии уже за применение Optional в сугубо внутреннем промежуточном типе XxxUpdate, который живет сугубо в недрах вашего сетевого "драйвера".

    В общем, автогенерённому коду никакой Optional и даром не нужен. Автогенерённый код может пробегаться прямо по битовой маске и не допускать ошибок из разряда "опять человеческий фактор подвёл".


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

    _>Для дельта-рекордов мы так и делаем.

    А для обновления отдельных полей или их групп лучше ввести отдельные же сообщения { MessageId, field1, field2 }. Или унифицировать до пар { FieldId, field }, но передавать не попарно, а сначала все FieldId из пакета, а потом все поля. Потому что FieldId можно упаковывать в битовую ширину меньше байта.


    V>>Ну или можно взять какой-нить ASN.1 с хорошим профилём упаковки.

    _>Нельзя. У ASN.1 крайне неудобный язык и нет возможности удобно контролировать кодогенерацию через атрибуты.

    Чего-чего???
    Определение структур и union в ASN.1 практически точно такое же, как в IDL.

    А уж за ручную кодогенерацию на разные языки из своей "версии" IDL на месте инвестора я бы с вами уже судился на компенсацию убытков.


    _>Я писал, что сервер у нас на Эрланге.


    Тем более.
    Можно описать поля в виде того же "JSON без кавычек", и не париться с разработкой парсера.

    Ведь вам из всей функциональности IDL требуется описать только типы данных, но не интерфейсы.
    Так с какого боку вы потратили кучу ресурсов на Interface Definition Language?

    Тем более, что именно под Эрланг и именно под дотнет есть сразу несколько хороших решений ASN.1.
    И твой аргумент насчет XML:

    ASN.1 standard XML Encoding Rules (XER) makes it possible for messages defined using ASN.1 to be encoded in XML format.


    А у вас случился синдром NIH.
    Хотя огромное кол-во именно сетевых протоколов (Bluetooth, обмен SSL-сертификатами и т.д.) юзают ASN.1.
    Он для этого и был придуман.
    И он подходит для сетевого общения НАМНОГО лучше любого мыслимого IDL.

    Ну разве что я бы понял единственный сценарий: разработка совсем простого проблемно-ориентированного языка описания данных (но не IDL) и генерацию из этого самописного языка ASN.1. И ву а ля.


    _>Поэтому внешний IDL — это обязательное требование.


    Насосанное из пальца, а не обязательное.
    Не вы одни сетевые протоколы пишете.


    _>Возни с ним нет. Это отработано годами.


    Кошмар. Вот это поделие стоило годы человеколет?
    Однозначно надо подавать на компенсацию убытков. ))


    V>>Через BLToolkit можно сделать так, чтобы код обновления полей вообще ручками писать не надо было.

    _>Так и приведенный код обновления полей я могу сгенерировать скриптом расширения к нашему кодогенератору строк так на восемь. Но хватает и тонкостей, например с обновлением коллекций (а там пока каждый второй случай — частный), поэтому проще в итоге писать руками.

    Т.е. годы человеколет потрачены, а всё-равно маппинг данных на объекты происходит ручками. ЧТД.


    _>Резюмируя: я просил привести альтернативы и описать проблемы с текущим решением. Две альтернативы ты привел, одна из них очень многословная и спорная (а компенсирующих преимуществ я пока не вижу). Вторая — грязноватый хак, уже опробованный на практике с негативным эффектом. А вот в чем проблема с текущим решением и его якобы тяжелой поддержкой ты так и не объяснил.


    Самая главная у тебя проблема — это много недоговариваний, преувеличений и откровенного вранья в итоге. Вот уже выясняется, что твои Optional<Optional<ClanId>>, оказываются, никуда далее слоя "драйвера сетевого протокола" не пролезают и никому нафик не уперлись. У-у-упс? Причем, это тот слой, который должен быть автогенерён в любом случае, потому что именно там живёт куча ошибок у всех вот этих сетевых приблуд.
    Отредактировано 23.02.2017 11:30 vdimas . Предыдущая версия .
    Re[12]: Опциональные типы
    От: WolfHound  
    Дата: 23.02.17 13:14
    Оценка:
    Здравствуйте, alex_public, Вы писали:

    _>Что-то не припомню языка с реальным (т.е. чтобы массив из 4-ёх штук занимал один байт) двухбитовым типом. Максимум что вспоминается, это битовые поля C++, но они опять же не позволяют задавать массивов. Снова фантазируешь? )

    Я даже в С++ могу сделать шаблон который будет это делать.
    А уж сделать компилятор, который такое может вообще не проблема.

    _>Естественно есть и для эффективного кода надо выбирать правильный вариант, в зависимости от деталей архитектуры приложения (итераций какого вида больше всего). Только опять же оба эти варианта работают на базе нессылочных данных, так что совершенно непонятно какое отношение их сравнение имеет к обсуждаемой нами теме неэффективности ссылочных данных? )

    Структура массивов предпочтительна практически всегда.
    Они только могут сравнится по производительности, когда в цикле используют все поля.

    WH>>Тут у нас есть два крайних случая.

    WH>>1)Везде Some(что-то)
    WH>>2)Везде None
    WH>>В первом случае мы прочитаем в 33 раза больше памяти чем во втором.
    WH>>А если без разбиения на массивы, то в 64 раза больше. Причём всегда.
    _>Не верно, будет 64 и 32 раза, но это не суть, просто мелкое замечание. )
    Не можешь память посчитать, а лезешь рассказывать про низкоуровневые оптимизации.

    _>И какое отношение данный код (кстати вполне реальный и эффективный) имеет даже уже не к нашей дискуссии о неэффективности ссылочных данных,

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

    _>а хотя бы к двум твоим предыдущим примерам? )))

    Это просто примеры одной оптимизации для разных случаев.

    _>Если мы уходим от использование optional (причём не в сторону ссылочных данных, а наоборот на ещё более низкий уровень битовых полей и т.п.), то возникают уже совершенно другие расклады по производительности (причём это применимо и к варианту без разбиения на массивы — там же тоже можно сделать более интересный код без optional).

    Не уходим. Этот код может сделать компилятор из такого:
    soa<option<int32>> values[1024*1024];
    foreach (Some(value) in values)
    {
        //делаем что-то с value
    }

    Совсем фантазии никакой. Всё разжёвывать нужно.
    ... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[11]: Опциональные типы
    От: vdimas Россия  
    Дата: 23.02.17 13:32
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>>>Покрой шаблонами целое неограниченного размера.

    V>>Ну вот я со звуком много работал. Там идёт работа с пачками отсчетов вполне конечного размера.
    WH>Как эти предложения вообще связаны?

    Очевидно так, что для некоторых сценариев трюка эмуляции ЗТ достаточно.
    В упомянутых звуковой предметной области пачки отсчетов не просто конечного размера, а строго по некоей сетке:
    40 байт, 80, 120, 160, 240, 320.

    И как раз трюк с отсутствием необходимости на проверку диапазона работает, потому что эта проверка "схлопывается".


    WH>Ты вообще можешь связно думать? Или у тебя в голове работает рандом, который скачет куда попало.


    Не хами, парниша.
    Ты на удивление несообразителен порой или невнимателен — на выбор. И это раздражает, ты даже не представляешь как.
    Общаешься с коллегами забыв проснуться.
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.