Здравствуйте, Sinix, Вы писали:
S>Не, это
S>S>if (dict.TryGetValue(key, out var value)
S>{
S> // do smth with value
S>}
S>
S>Мелочь, но в куче мест сводит необходимость тюплов к нулю.
Вот в F# методы out-параметрами интерпретируются как возвращающие кортеж. Если представить такую фичу в C#, то можно было бы писать следующим образом:
if ((true, var value) = dict.TryGetValue(key))
{
// do smth with value
}
а лучше:
if (var (true, value) = dict.TryGetValue(key))
{
// do smth with value
}
так как пихать var в каждую переменную в кортеже не очень разумно.
S>Так ты не с знатоками общайся, а с design team. Они вот тут перечислены.
Они меня среди "знатоков" просто не заметят. В общем, проверено. Это то место откуда информация доходит до кого надо

.
S>С теорией всё более-менее ок. А вот ничего близкого к
S>S>type switchstate =
S> | On
S> | Off
S> | Adjustable of float
S>
S>в шарпе на сегодня нет. Конечно, можно выразить ч/з наследование, но это всё-таки слегка не то.
То, то. F#, просто еще несколько старомоден (унаследовал много от ML и далек от ОО-мира).
В Немерле это выглядит так:
variant SwitchState
{
| On
| Off
| Adjustable { Value : float; }
}
И переписывается в:
[Variant("SwitchState.On,SwitchState.Off,SwitchState.Adjustable")]
internal abstract class SwitchState
{
[ConstantVariantOption]
public class On : SwitchState
{
public static readonly SwitchState.On _N_constant_object;
public static SwitchState.On _N_constant_object_generator()
{
return SwitchState.On._N_constant_object;
}
static On()
{
SwitchState.On._N_constant_object = new SwitchState.On();
}
public override int _N_GetVariantCode()
{
return 0;
}
[RecordCtor]
private On()
{
}
}
[ConstantVariantOption]
public class Off : SwitchState
{
public static readonly SwitchState.Off _N_constant_object;
public static SwitchState.Off _N_constant_object_generator()
{
return SwitchState.Off._N_constant_object;
}
static Off()
{
SwitchState.Off._N_constant_object = new SwitchState.Off();
}
public override int _N_GetVariantCode()
{
return 1;
}
[RecordCtor]
private Off()
{
}
}
[VariantOption]
public class Adjustable : SwitchState
{
public readonly float Value;
public override int _N_GetVariantCode()
{
return 2;
}
[RecordCtor]
public Adjustable([MappedMember("Value")] float value)
{
this.Value = value;
}
}
public abstract override int _N_GetVariantCode();
public static int _N_GetVariantCodeSafe(SwitchState x)
{
return ((object)x != null) ? x._N_GetVariantCode() : -1;
}
public static int _N_GetVariantCodeObject(object x)
{
int arg_1E_0;
if (x is SwitchState)
{
SwitchState switchState = (SwitchState)x;
arg_1E_0 = switchState._N_GetVariantCode();
}
else
{
arg_1E_0 = -1;
}
return arg_1E_0;
}
}
Если абстрагироваться от оптимизаций, то это чистое наследование.
В Скале так вообще сделано так же как в шарпе планируется.
S>Ну да. Но нbкто не запрещает сделать тип с primary ctor но без is operator.
1. Зачем это нужно?
2. Я вообще не вижу смысла в этом операторе is. Точнее то не плохая фича для расширяемости ПМ, но по умолчанию ПМ должен работать и без наличия этого метода. В Немерле информация о связи между полями и параметрами конструктора записывается в атрибут Variant (видно в примере декомпилята).
S>Или использовать PM на любом типе дотнета. Эти фичи ортогональны. record просто позволяет получить типовую реализацию без лишнего кода.
Рекорд просто лишний. Очередная ошибка дизайна, на мой взгляд.
S>Ну блин, это opt-in возможности. Можно добавлять, можно не добавлять. Без модификатора record такое поведение красиво не сделать.
Возможности которые всегда полезны можно добавлять по умолчанию не думая. Если кому-то нужно вручную что-то реализовать, то они могут переопределить нужные методы врунчую.
Тебя ведь не смущает, что для объектов по молчанию работает GetHashCode и т.п.?
А для ПМ не нужно ничего из перечисленного выше. Только первичный конструктор. Да и тот, если хочется пользоваться более лаконичным паттерном конструктор. А для матчинга по свойствам/полям и сойдет любой класс.
S>Что-то я не заметил. Как насчёт чего-нить вот такого
S>S>type switchstate =
S> | On
S> | Off
S> | Adjustable of float
S>
S>на шарпе? Со всеми прелестями discriminated unions типа контроля со стороны компилятора "проверили все варианты".
См. выше. А для контроля полноты нужно иметь возможность предотвратить создание наследников. В Скале это называется sealed, но смысл отличается от шарповского.
sealed abstract class LogMessage
case class StringMessage(message:String) extends LogMessage
case class ExceptionMessage(exception:Throwable) extends LogMessage
case class BothMessage(message:String, exception:Throwable) extends LogMessage
class Logger {
def debug(l:LogMessage) = log(10,l)
def info(l:LogMessage) = log(5,l)
def error(l:LogMessage) = log(1,l)
def log(level:Int, l:LogMessage):Unit = l match {
case StringMessage(msg) => println(msg)
case ExceptionMessage(exception:Error) => exception.printStackTrace
case ExceptionMessage(ex) => println(ex.toString)
}
}
S>Нету этого на сегодня. По крайней мере в публичных источниках.
Сегодня ничего нет. Мы же говорим о C# 7. Смотри на Немерл. Его в C# 5 пророчили многие, но он, похоже, C# и в десятой версии всех фичь не реализует.
S>Авральными темпами пилят поддержку всего, от дотнета в docker-контейнерах и до интеропа с android и objective-c кодом. Ага, обе платформы поддерживаются в win 10, на build пару часов назад сознались всё-таки. Занятые они, короче.
Ну, да. 10 лет это ведь так мало для МС.
S>Ну а как equals и хэшкод для таких типов определять? Это надо или нормальные макросы впихивать, или не страдать фигнёй и один раз в жизни сгенерить однотипный код. Т.е. или макросы, или кодогенерацию в compile-time.
Посмотри примеры на С++. Там конечно многе на метапрограммирование завязано, но кое-что можно и более простыми темпами.
Ну, и вы говорите об МП, как о чем-то плохом (ц)

МП — это очень даже хорошо. Когда-нибудь они и до этого дорастут. Но это уже будет C# 10, наверно.
VD>>Ну, и до кучи надо ввести замену этому убогому delegate — функциональный тип.
S>В другой жизни разве что. Слишком многое завязано.
Это можно даже не меняя рантйм сделать. В Nemerle и F# такие типы есть.
Ну, да. У МС процесс озревания идет десятилетиями. Когда-нибудь и до этого дозреют. А жаль, так как такие типы нужны именно в рантайме, а не в отдельных языках.