Сообщение Re[10]: Опциональные типы от 27.02.2017 2:38
Изменено 27.02.2017 6:44 vdimas
Re[10]: Опциональные типы
Здравствуйте, meadow_meal, Вы писали:
_>ИМХО, ClanId — должен быть int, а не Optional<int>. Скажем сервисная функция GetClanInfo(ClanId clan_id) не должна принимать NotSet, а GetPlayerInfo может вернуть NotSet в поле ClanId, и я бы предпочел, чтобы в обоих случаях это было отражено в сигнатуре.
Ну и какие проблемы, делаем так:
У вас на прямо сейчас примерно так же и выглядит. Потому что публичный интерфейс у struct ClanId и struct Optional<int> идентичный (я ориентировался на Nullabl<int>, бо вашего Optional в глаза не видел, но не суть).
_>Одна из возможных мотиваций для констант после where — экономия трафика — тоже не проходит, так как если не использовать variable encoding, то для NonSet получим 4 байта вместо 1 байта (а часто — бита)
Обычно int передают в 7-мибитной кодировке.
А когда речь о передаче бита, то это обычно речь о передаче больших структур или массива структур через автогенеренный код, который точно так же в теле сериализации ветвится через точно такое же HasValue.
_>а с variable encoding мы стараемся быть осторожнее, так как в случае частого использования и большого числа мелких пакетов нагрузка на cpu может дать больше вреда, чем минимальная экономия трафика — пользы (впрочем, если до этого дойдет, нужно конечно замерять, задумываться об этом имеет смысл лишь для очень частых событий).
Еще раз.
Да какая разница, если код сериализации ориентируется на HasValue?
_>Здесь мы тоже не можем по типу отличить обязательно наличествующее значение от опционального.
Не понял, почему не можете, если в DSL описано:
Кто не может отличить?
Код сериализации?
Или программист, которому студия подскажет интиллисенсом?
Ты же сам говорил, что в пакете обновлений тебе придет Optional.
Ну вот пришло Optional<ClanId>, где сам ClanId — тоже эдакий optional.
Программист в вашем стиле пишет:
_>Небольшая экономия памяти не кажется достаточной компенсацией.
Для простых int это экономия вдвое.
И для игр экономия памяти и эффективная её разметка — это первое дело.
Просто у вас объектов в играх, похоже, немного или активность объектов низкая, поэтому вы не паритесь.
_>Ну и не работает обобщенный код для Nullable и ??, что может быть или не быть неудобством в конкретных случаях.
Тю.
В заголовке пакета идёт биты для nullable-полей, далее сами поля.
_>Но честно говоря, я не понимаю, зачем нужно искать замену Optional в случае его использования по самому что ни на есть прямому назначению.
Потому что есть только негодный Nullable в системной библиотеке, с отсутствующей инфраструктурой и нулевой функциональностью.
Посмотри сюда:
https://github.com/nlkl/Optional/blob/master/Optional/Option_Maybe.cs
ValueOr/Or/Else/Filter/FlatMap — и т.д.
Утилитный код по ссылке можно организовать в виде методов-расширений для INullable<T>.
А вот это: Contains/Exists/GetEnumerator — весьма остроумно, ИМХО.
Позволяет рассматривать Option<> в том числе как пустой список (нет значения), либо как список с единственным элементом (есть значение).
Тоже для обхода/сериализации подойдёт.
Такие вещи можно и нужно пробовать. Глядишь, понравится всяко больше, чем встроенный Nullable.
_>Нужно ли что-то менять в системе апдейт-рекордов — вопрос для нас еще открытый.
Задача правильно поставленного процесса разработки — это наработки и циркуляция полезных практик в коллективе.
К сожалению, в среднем коллективе есть производители практик, а есть только лишь потребители.
Т.е., кому-то надо за своё счет (автомотивация) исследовать, испытывать, внедрять и распространять практики.
Разумеется, твоя задача не бросаться сходу делать как подсказывают, а лишь коллекционировать идеи, среди которых потом обычно "выстреливает" не какая-то одна, а удачная комбинация их.
_>ИМХО, ClanId — должен быть int, а не Optional<int>. Скажем сервисная функция GetClanInfo(ClanId clan_id) не должна принимать NotSet, а GetPlayerInfo может вернуть NotSet в поле ClanId, и я бы предпочел, чтобы в обоих случаях это было отражено в сигнатуре.
Ну и какие проблемы, делаем так:
struct ClanId {
public int Value { get {
if(HasValue)
return value_;
throw ...
}}
public bool HasValue { get { return Value != 0; }}
}
ClanInfo GetClanInfo(int clan_id) {}
class PlayerInfo {
ClanId clanId;
...
}
...
PlayerInfo pi = ...
ClanInfo ci;
if(pi.clanId.HasValue)
ci = GetClanInfo(pi.clanId.Value);
У вас на прямо сейчас примерно так же и выглядит. Потому что публичный интерфейс у struct ClanId и struct Optional<int> идентичный (я ориентировался на Nullabl<int>, бо вашего Optional в глаза не видел, но не суть).
_>Одна из возможных мотиваций для констант после where — экономия трафика — тоже не проходит, так как если не использовать variable encoding, то для NonSet получим 4 байта вместо 1 байта (а часто — бита)
Обычно int передают в 7-мибитной кодировке.
А когда речь о передаче бита, то это обычно речь о передаче больших структур или массива структур через автогенеренный код, который точно так же в теле сериализации ветвится через точно такое же HasValue.
_>а с variable encoding мы стараемся быть осторожнее, так как в случае частого использования и большого числа мелких пакетов нагрузка на cpu может дать больше вреда, чем минимальная экономия трафика — пользы (впрочем, если до этого дойдет, нужно конечно замерять, задумываться об этом имеет смысл лишь для очень частых событий).
Еще раз.
Да какая разница, если код сериализации ориентируется на HasValue?
_>Здесь мы тоже не можем по типу отличить обязательно наличествующее значение от опционального.
Не понял, почему не можете, если в DSL описано:
type ClanId = Optional<int> where NotSet = 0;
Кто не может отличить?
Код сериализации?
Или программист, которому студия подскажет интиллисенсом?
Ты же сам говорил, что в пакете обновлений тебе придет Optional.
Ну вот пришло Optional<ClanId>, где сам ClanId — тоже эдакий optional.
Программист в вашем стиле пишет:
void UpdateXXX(PlayerPDU pdu) {
if(pdu.clanId.HasValue) {
player.clanId = pdu.clanId.Value;
player.clanInfo = GetClanInfo(player.clanId);
}
...
}
class ClanInfo {...}
ClanInfo GetClanInfo(ClanId clanId) {
if(!clanId.HasValue)
return null;
return RetrieveClanInfoFromCacheOrServer(clanId.Value);
}
_>Небольшая экономия памяти не кажется достаточной компенсацией.
Для простых int это экономия вдвое.
И для игр экономия памяти и эффективная её разметка — это первое дело.
Просто у вас объектов в играх, похоже, немного или активность объектов низкая, поэтому вы не паритесь.
_>Ну и не работает обобщенный код для Nullable и ??, что может быть или не быть неудобством в конкретных случаях.
Тю.
interface INullable<T> {
bool HasValue { get; }
T Value { get; }
}
struct ClanId : INullable<int> {...}
void SerializeHeader(T nullable, Formatter<bool> f) where T : INullable<T>
{
f.Write(nullable.HasValue);
}
void SerializeBody(T nullable, Formatter<T> f) where T : INullable<T>
{
if(nullable.HasValue)
f.write(nullable.Value);
}
В заголовке пакета идёт биты для nullable-полей, далее сами поля.
_>Но честно говоря, я не понимаю, зачем нужно искать замену Optional в случае его использования по самому что ни на есть прямому назначению.
Потому что есть только негодный Nullable в системной библиотеке, с отсутствующей инфраструктурой и нулевой функциональностью.
Посмотри сюда:
https://github.com/nlkl/Optional/blob/master/Optional/Option_Maybe.cs
ValueOr/Or/Else/Filter/FlatMap — и т.д.
Утилитный код по ссылке можно организовать в виде методов-расширений для INullable<T>.
А вот это: Contains/Exists/GetEnumerator — весьма остроумно, ИМХО.
Позволяет рассматривать Option<> в том числе как пустой список (нет значения), либо как список с единственным элементом (есть значение).
Тоже для обхода/сериализации подойдёт.
Такие вещи можно и нужно пробовать. Глядишь, понравится всяко больше, чем встроенный Nullable.
_>Нужно ли что-то менять в системе апдейт-рекордов — вопрос для нас еще открытый.
Задача правильно поставленного процесса разработки — это наработки и циркуляция полезных практик в коллективе.
К сожалению, в среднем коллективе есть производители практик, а есть только лишь потребители.
Т.е., кому-то надо за своё счет (автомотивация) исследовать, испытывать, внедрять и распространять практики.
Разумеется, твоя задача не бросаться сходу делать как подсказывают, а лишь коллекционировать идеи, среди которых потом обычно "выстреливает" не какая-то одна, а удачная комбинация их.
Re[10]: Опциональные типы
Здравствуйте, meadow_meal, Вы писали:
_>ИМХО, ClanId — должен быть int, а не Optional<int>. Скажем сервисная функция GetClanInfo(ClanId clan_id) не должна принимать NotSet, а GetPlayerInfo может вернуть NotSet в поле ClanId, и я бы предпочел, чтобы в обоих случаях это было отражено в сигнатуре.
Ну и какие проблемы, делаем так:
У вас на прямо сейчас примерно так же и выглядит. Потому что публичный интерфейс у struct ClanId и struct Optional<int> идентичный (я ориентировался на Nullabl<int>, бо вашего Optional в глаза не видел, но не суть).
_>Одна из возможных мотиваций для констант после where — экономия трафика — тоже не проходит, так как если не использовать variable encoding, то для NonSet получим 4 байта вместо 1 байта (а часто — бита)
Обычно int передают в 7-мибитной кодировке.
А когда речь о передаче бита, то это обычно речь о передаче больших структур или массива структур через автогенеренный код, который точно так же в теле сериализации ветвится через точно такое же HasValue.
_>а с variable encoding мы стараемся быть осторожнее, так как в случае частого использования и большого числа мелких пакетов нагрузка на cpu может дать больше вреда, чем минимальная экономия трафика — пользы (впрочем, если до этого дойдет, нужно конечно замерять, задумываться об этом имеет смысл лишь для очень частых событий).
Еще раз.
Да какая разница, если код сериализации ориентируется на HasValue?
_>Здесь мы тоже не можем по типу отличить обязательно наличествующее значение от опционального.
Не понял, почему не можете, если в DSL описано:
Кто не может отличить?
Код сериализации?
Или программист, которому студия подскажет интиллисенсом?
Ты же сам говорил, что в пакете обновлений тебе придет Optional.
Ну вот пришло Optional<ClanId>, где сам ClanId — тоже эдакий optional.
Программист в вашем стиле пишет:
_>Небольшая экономия памяти не кажется достаточной компенсацией.
Для простых int это экономия вдвое.
И для игр экономия памяти и эффективная её разметка — это первое дело.
Просто у вас объектов в играх, похоже, немного или активность объектов низкая, поэтому вы не паритесь.
_>Ну и не работает обобщенный код для Nullable и ??, что может быть или не быть неудобством в конкретных случаях.
Тю.
В заголовке пакета идут биты для nullable-полей, далее сами поля.
_>Но честно говоря, я не понимаю, зачем нужно искать замену Optional в случае его использования по самому что ни на есть прямому назначению.
Потому что есть только негодный Nullable в системной библиотеке, с отсутствующей инфраструктурой и нулевой функциональностью.
Посмотри сюда:
https://github.com/nlkl/Optional/blob/master/Optional/Option_Maybe.cs
ValueOr/Or/Else/Filter/FlatMap — и т.д.
Утилитный код по ссылке можно организовать в виде методов-расширений для INullable<T>.
А вот это: Contains/Exists/GetEnumerator — весьма остроумно, ИМХО.
Позволяет рассматривать Option<> в том числе как пустой список (нет значения), либо как список с единственным элементом (есть значение).
Тоже для обхода/сериализации подойдёт.
Такие вещи можно и нужно пробовать. Глядишь, понравится всяко больше, чем встроенный Nullable.
_>Нужно ли что-то менять в системе апдейт-рекордов — вопрос для нас еще открытый.
Задача правильно поставленного процесса разработки — это наработки и циркуляция полезных практик в коллективе.
К сожалению, в среднем коллективе есть производители практик, а есть только лишь потребители.
Т.е., кому-то надо за свой счет (автомотивация) исследовать, испытывать, внедрять и распространять практики.
Разумеется, твоя задача не бросаться сходу делать как подсказывают, а лишь коллекционировать идеи, среди которых потом обычно "выстреливает" не какая-то одна, а удачная комбинация их.
_>ИМХО, ClanId — должен быть int, а не Optional<int>. Скажем сервисная функция GetClanInfo(ClanId clan_id) не должна принимать NotSet, а GetPlayerInfo может вернуть NotSet в поле ClanId, и я бы предпочел, чтобы в обоих случаях это было отражено в сигнатуре.
Ну и какие проблемы, делаем так:
struct ClanId {
public int Value { get {
if(HasValue)
return value_;
throw ...
}}
public bool HasValue { get { return Value != 0; }}
}
ClanInfo GetClanInfo(int clan_id) {}
class PlayerInfo {
ClanId clanId;
...
}
...
PlayerInfo pi = ...
ClanInfo ci;
if(pi.clanId.HasValue)
ci = GetClanInfo(pi.clanId.Value);
У вас на прямо сейчас примерно так же и выглядит. Потому что публичный интерфейс у struct ClanId и struct Optional<int> идентичный (я ориентировался на Nullabl<int>, бо вашего Optional в глаза не видел, но не суть).
_>Одна из возможных мотиваций для констант после where — экономия трафика — тоже не проходит, так как если не использовать variable encoding, то для NonSet получим 4 байта вместо 1 байта (а часто — бита)
Обычно int передают в 7-мибитной кодировке.
А когда речь о передаче бита, то это обычно речь о передаче больших структур или массива структур через автогенеренный код, который точно так же в теле сериализации ветвится через точно такое же HasValue.
_>а с variable encoding мы стараемся быть осторожнее, так как в случае частого использования и большого числа мелких пакетов нагрузка на cpu может дать больше вреда, чем минимальная экономия трафика — пользы (впрочем, если до этого дойдет, нужно конечно замерять, задумываться об этом имеет смысл лишь для очень частых событий).
Еще раз.
Да какая разница, если код сериализации ориентируется на HasValue?
_>Здесь мы тоже не можем по типу отличить обязательно наличествующее значение от опционального.
Не понял, почему не можете, если в DSL описано:
type ClanId = Optional<int> where NotSet = 0;
Кто не может отличить?
Код сериализации?
Или программист, которому студия подскажет интиллисенсом?
Ты же сам говорил, что в пакете обновлений тебе придет Optional.
Ну вот пришло Optional<ClanId>, где сам ClanId — тоже эдакий optional.
Программист в вашем стиле пишет:
void UpdateXXX(PlayerPDU pdu) {
if(pdu.clanId.HasValue) {
player.clanId = pdu.clanId.Value;
player.clanInfo = GetClanInfo(player.clanId);
}
...
}
class ClanInfo {...}
ClanInfo GetClanInfo(ClanId clanId) {
if(!clanId.HasValue)
return null;
return RetrieveClanInfoFromCacheOrServer(clanId.Value);
}
_>Небольшая экономия памяти не кажется достаточной компенсацией.
Для простых int это экономия вдвое.
И для игр экономия памяти и эффективная её разметка — это первое дело.
Просто у вас объектов в играх, похоже, немного или активность объектов низкая, поэтому вы не паритесь.
_>Ну и не работает обобщенный код для Nullable и ??, что может быть или не быть неудобством в конкретных случаях.
Тю.
interface INullable<T> {
bool HasValue { get; }
T Value { get; }
}
struct ClanId : INullable<int> {...}
void SerializeHeader(T nullable, Formatter<bool> f) where T : INullable<T>
{
f.Write(nullable.HasValue);
}
void SerializeBody(T nullable, Formatter<T> f) where T : INullable<T>
{
if(nullable.HasValue)
f.write(nullable.Value);
}
В заголовке пакета идут биты для nullable-полей, далее сами поля.
_>Но честно говоря, я не понимаю, зачем нужно искать замену Optional в случае его использования по самому что ни на есть прямому назначению.
Потому что есть только негодный Nullable в системной библиотеке, с отсутствующей инфраструктурой и нулевой функциональностью.
Посмотри сюда:
https://github.com/nlkl/Optional/blob/master/Optional/Option_Maybe.cs
ValueOr/Or/Else/Filter/FlatMap — и т.д.
Утилитный код по ссылке можно организовать в виде методов-расширений для INullable<T>.
А вот это: Contains/Exists/GetEnumerator — весьма остроумно, ИМХО.
Позволяет рассматривать Option<> в том числе как пустой список (нет значения), либо как список с единственным элементом (есть значение).
Тоже для обхода/сериализации подойдёт.
Такие вещи можно и нужно пробовать. Глядишь, понравится всяко больше, чем встроенный Nullable.
_>Нужно ли что-то менять в системе апдейт-рекордов — вопрос для нас еще открытый.
Задача правильно поставленного процесса разработки — это наработки и циркуляция полезных практик в коллективе.
К сожалению, в среднем коллективе есть производители практик, а есть только лишь потребители.
Т.е., кому-то надо за свой счет (автомотивация) исследовать, испытывать, внедрять и распространять практики.
Разумеется, твоя задача не бросаться сходу делать как подсказывают, а лишь коллекционировать идеи, среди которых потом обычно "выстреливает" не какая-то одна, а удачная комбинация их.