Здравствуйте, Ночной Смотрящий, Вы писали:
HH>>Я так понимаю что шейпы это аналог классов типов из Haskell. НС>Соотв. шейпы это попытка избежать их отказом от static class и введением отдельной специальной сущности. Никакой особой цели кроме как семантически связать набор статических методов с определенным типом оно не преследует.
Здравствуйте, BlackEric, Вы писали:
BE>Еще не успел выйти C#8, а уже пошло обсуждение 9го:
BE>Из значимого UTF8String:
эээ... с каких это пор в 21 веке нужна опять эта муита с кодировками??
Вот что реально интересно:
public class Greeter(name: string)
Наглядный пример уровня интеллекта разрабов C# — в языке десятки неуклюжестей, а им вот всралось проперть сунуть туда, куда даже дедушка не лез!
var x = ["foo":4, "bar": 5];
Наконец-то! Не прошло и 30 лет существования Перла, чтобы доблестные "переделыватели Жабы в C#" наконец додумались — в тысячах программ инициализируются словари и давно уже просился краткий, удобный синтаксис.
А вот что мне лично нехватает, так это удобнейшего паскалевскогоwith. Но видимо, макакам набирать текст привычно, так что никто не торопится это делать.
Да ни насколько. Я в дотнете стори никогда и не перекодировал, кажется.
А в делфе постоянно проверять тип стори и кодировку приходилось, бо одна либа возвращает WideString, другая ANSI, а третья PChar какой-нибудь. Теперь это и в шарпе будет.
Y>>Насколько остра востребованность?
BE>Да ни насколько. Я в дотнете стори никогда и не перекодировал, кажется. BE>А в делфе постоянно проверять тип стори и кодировку приходилось, бо одна либа возвращает WideString, другая ANSI, а третья PChar какой-нибудь. Теперь это и в шарпе будет.
Здравствуйте, Serginio1, Вы писали:
S>C шейпами нам нужно добавить недостающие операторы или их переопределить (используя различные пространства имен как это сделано для расширений). Очень нужная конструкция.
Конструкция нужная, но операторы там не самое главное.
Один человек в одной сборке определяет класс, потом другой человек в другой сборке определяет shape. И уже после этого(!) третий человек может в третьей сборке определить, как данный класс является экземпляром этого шейпа.
То есть эта такая форма ad hoc полиморфизма, альтернативная наследованию.
В Haskell можно сразу после определения типа сказать экземпляры каких классов типов будут созданы автоматически для этого типа (это конечно возможно только для некоторых классов типов).
В примерах приводятся операторы, т.к. товарищи из Haskell (и примкнувшие к ним) очень любят алгебру: моноиды, полугруппы, монады и т.п.
Часто используются классы типов Functor, Applicative и Monad, но все они требуют нормальной системы типов, которой в C# нет.
Но даже если они сделают shape в таком виде, это будет слишком хорошо, чтобы быть правдой.
Как будут различать, какой из нескольких возможных инстансов класса типов применить? Скажем, у меня в скоупе две группы — мультипилкативная и аддитивная, с одинаковым шейпом (в их примере это, скорее, моноид):
public shape SGroup<T>
{
static T Combine(T t1, T t2);
static T Identity { get; }
}
Здравствуйте, Qbit86, Вы писали:
Q>Здравствуйте, BlackEric.
Q>Как будут различать, какой из нескольких возможных инстансов класса типов применить? Скажем, у меня в скоупе две группы — мультипилкативная и аддитивная, с одинаковым шейпом (в их примере это, скорее, моноид):
Полагаю что будут требовать в точности один инстанс в скоупе, иначе ошибка компиляции. Возможно, будет способ указать инстанс шейпа явно.
Здравствуйте, BlackEric, Вы писали:
BE>Еще не успел выйти C#8, а уже пошло обсуждение 9го:
LDT то по восьмерке уже отработал, изменений не будет. Самое время начать работать над девяткой.
BE>Из значимого UTF8String:
Оно значимое на довольно узком классе задач, а уж константы так вообще.
При этом действительно крупные фичи ты не заметил: рекорды, которые уже версии 4 никак не сделают, и шейпы, которые тянутся еще дольше.
Здравствуйте, Kolesiki, Вы писали:
K>эээ... с каких это пор в 21 веке нужна опять эта муита с кодировками??
С тех, с которых есть железки, для которых экономия на размерах сборок и ужоре памяти критична.
K>Наглядный пример уровня интеллекта разрабов C# — в языке десятки неуклюжестей, а им вот всралось проперть сунуть туда, куда даже дедушка не лез!
Здравствуйте, BlackEric, Вы писали:
BE>Еще не успел выйти C#8, а уже пошло обсуждение 9го:
BE>Candidate Features For C# 9
BE>Из значимого UTF8String: BE>
Вот востребованность дефолтового конструктора для структур не ясна, всё равно же var r = (new Rational[1])[0] поломает все инварианты. В остальном логика вроде есть.
--
updated
Но лично я бы — нафиг литералы для словаря выкинул. Где вообще логика, для в разы более часто используемого List<> нету литералов, а для словаря вот нате. Лучше бы вывод типов для generic аргументов классов завезли бы.
var dict = new Dictionary<_, _> { { "key1", 0}, { "key2", 1} };
помогло бы и словарях, и листах и еще в туче вариантов использования.
Здравствуйте, Jack128, Вы писали:
J>Вот востребованность дефолтового конструктора для структур не ясна, всё равно же var r = (new Rational[1])[0] поломает все инварианты.
Да это проще делается:
var r = default(Rational);
Вообще дефолтные конструкторы структур ранее уже добавляли в превью C# 6.0 но перед релизом откатили.
Здравствуйте, Jack128, Вы писали: J>Но лично я бы — нафиг литералы для словаря выкинул. Где вообще логика, для в разы более часто используемого List<> нету литералов
Как это нету????
J>Лучше бы вывод типов для generic аргументов классов завезли бы. J>
J>помогло бы и словарях, и листах и еще в туче вариантов использования.
Имхо, это сложно. В тривиальном случае — например, вызов конструктора — помогло бы:
class Holder
{
public static Holder<T> Create<T>(T value) => new Holder<T>(value); // костыль для type inference
}
сlass Holder<T>
{
private T _value;
public Holder(T value) => _value = value;
}
...
var h1 = Holder.Create(42); // okvar h2 = new Holder<>(42); // низзя, а можно было бы.
Но в ситуации, которая описана в вашем примере, все несколько хуже.
Сейчас компилятор трансформирует код
var dict = new XYZWUI { { "key1", 0}, { "key2", 1} };
в код
var dict = new XYZWUI();
dict.Add("key1", 0); // <- вот здесь у нас появилась информация о типах аргументов.
dict.Add("key2", 1);
Приколов тут сразу несколько.
1. Сначала нам надо научится типизировать весь блок кода, а не отдельные его строчки. То есть пытаться угадать тип-параметры в строчке 1 по типам аргументов в строчках 2 и 3.
2. Далее у нас возникают потенциальные неопределённости. Сейчас валидны обе строчки:
var d1 = new Dictionary<string, int> {{"key"}:1}
var d2 = new Dictionary<string, float> {{"key"}:1}
Нужно правило, по которому мы выберем строчку 1, увидев
var d1 = new Dictionary<,> {{"key"}:1}
3. В пользовательском типе я не обязан ограничиваться ровно 1 методом Add, сигнатура которого однозначно позволяет восстановить сигнатуру класса:
var d2 = new MyClass() { {"A", 2, 3}, { 4, 5, 6 } }; // Ok
...
public class MyClass: IEnumerable
{
public MyClass() {}
public void Add(string a, int b, double c) => Console.WriteLine($"initializing {a}={b}[{c}]");
public void Add(int a, int b, double c) => Console.WriteLine($"initializing {a}={b}[{c}]");
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
Ведь можно же и в маньяка поиграть:
var d3 = new CrazyDict<,> { {"A", 2 } }; // ??
...
public class CrazyDict<K, T>: IEnumerable
{
public CrazyDict() {}
public void Add(K key, T value) => Add((object) key, value);
public void Add(object key, object value) => Console.WriteLine($"initializing {key}={value}");
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Y>?
Потому, что тип Dictionary уже есть, и это совсем не тот же самый тип, что Dictionary<,>.
Y>А лучше: Y>
Y>var dict = { { "key1", 0}, { "key2", 1} };
Y>
Ну, вот примерно это и предлагают. Только прямо такой синтаксис нельзя, т.к. по нему невозможно понять, порождать массив или словарь.
Y>Мы же понимаем так: Y>var arr = new[] { new { s = "a", i = 0 }, new { s = "b", i = 1 } };
Ну так мы это понимаем потому, что new[] гвоздями прибито к типу "массив". Алгоритм выведения типов прост, как угол дома.
А если мы захотим отодрать гвозди и сделать поддержку вот такой инициализации для произвольных типов, то придётся сильно вспотеть, т.к. взаимосвязь между типами фактических параметров и аргументами генерика неочевидна.
Y>1 — Int32 по умолчанию.
Ну, ок. В принципе, это не катастрофа (несмотря на то, что для пользовательских типов там могут быть более интересные случаи предпочтений): в простых случаях — компилируем, в сложных — падаем с ошибкой type inference.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, yenik, Вы писали:
BE>>Из значимого UTF8String: Y>Насколько остра востребованность?
Для чего понадобился UTF8String понятно.
Если в целевой системе весь ввод и вывод в utf8, это избавит от кучи лишних переконвертаций и сопутствующих накладных расходов. Очень актуально для веба.
Это можно было сделать и без вмешательства в язык, но без utf8 литералов инициализация значений выливалась бы в переконвертацию из юникода в utf8.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Jack128, Вы писали: J>>Но лично я бы — нафиг литералы для словаря выкинул. Где вообще логика, для в разы более часто используемого List<> нету литералов S>Как это нету????
Ну я такого не знаю. Есть только универсальный list-initilizer, который работает со всеми коллекциями.
J>>Лучше бы вывод типов для generic аргументов классов завезли бы. J>>
J>>помогло бы и словарях, и листах и еще в туче вариантов использования. S>Имхо, это сложно. В тривиальном случае — например, вызов конструктора — помогло бы:
Сложно или нет — могут только разрабы компилятора сказать. Сложно может быть только с точки зрения текущей архитектуры компилятора
S>Но в ситуации, которая описана в вашем примере, все несколько хуже. S>Сейчас компилятор трансформирует код S>
S>var dict = new XYZWUI();
S>dict.Add("key1", 0); // <- вот здесь у нас появилась информация о типах аргументов.
S>dict.Add("key2", 1);
S>
S>Приколов тут сразу несколько. S>1. Сначала нам надо научится типизировать весь блок кода, а не отдельные его строчки. То есть пытаться угадать тип-параметры в строчке 1 по типам аргументов в строчках 2 и 3.
Ну то есть научиться, то что компилятор сейчас уже делает в таком коде ?
var i = new[] {GetString(),GetString(),GetString()};
S>Ведь можно же и в маньяка поиграть: S>
S> var d3 = new CrazyDict<,> { {"A", 2 } }; // ??
S>...
S> public class CrazyDict<K, T>: IEnumerable
S> {
S> public CrazyDict() {}
S> public void Add(K key, T value) => Add((object) key, value);
S> public void Add(object key, object value) => Console.WriteLine($"initializing {key}={value}");
S> public IEnumerator GetEnumerator()
S> {
S> throw new NotImplementedException();
S> }
S> }
S>
Похожие вещи должны работать похоже. Алго вывода дженерик-аргументов класса должен быть таким же как и для вывода дженерик-аргументов методов.
Представь, что все дженерик-аргументы уровня класса перенесли на уровень методов:
public class CrazyDict2: IEnumerable
{
public CrazyDict() {}
public void Add<K, T>(K key, T value) => Add((object) key, value);
public void Add(object key, object value) => Console.WriteLine($"initializing {key}={value}");
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
var d3 = new CrazyDict2() { {"A", 2 } };
тут компилятор может вывести аргументы K и T. Всё, задача решена.
Нет, я прекрасно понимаю, что приспособить текущий алго под такую задачу может быть не просто, но это лучше чем тянуть специальный синтаксис для конкретно класса Dictionary<,>
Да уж лучше б операторы tolist/todict в linq query syntax запихали, пользы больше было бы.
Здравствуйте, Jack128, Вы писали:
J>Но лично я бы — нафиг литералы для словаря выкинул.
А их и выкидывают регулярно версии с 5. Но хипста-массовка негодуэ, жысончики неудобно писать.
J> Где вообще логика, для в разы более часто используемого List<> нету литералов
Здравствуйте, Ночной Смотрящий, Вы писали:
J>> Где вообще логика, для в разы более часто используемого List<> нету литералов
НС>Есть для массивов потому что.
??
есть такое: var x = new[] {1,2,3}; ну это в общем тот же list-initializer только для захардкоренного типа.
есть такое: int[] y = {1,2,3};
но этот костыль вообще непонятно зачем существует (легаси времен первого шарпа?), его только вот в такой форме использовать можно.
Даже метод так нельзя вызвать
void Test(int[] arg) {}
Test({1,2,3});// ошибка компиляции.
Здравствуйте, Serginio1, Вы писали:
S> Шейпы я так понимаю, это сделать аналог С++ шаблонов c перегрузкой операторов, по аналогии с расширениями.
Я так понимаю что шейпы это аналог классов типов из Haskell.
Но без поддержки Higher Kinded Polymorphism оно будет далеко не таким мощным как в Haskell.
Здравствуйте, HrorH, Вы писали:
HH>Я так понимаю что шейпы это аналог классов типов из Haskell.
Ну в ссылке из стартового сообщения да. Но история совсем иная. Еще с 4, еним, шарпа была идея сделать extension everything. Но она потерпела крах, слишком много конфликтов с существующим функционалом. Соотв. шейпы это попытка избежать их отказом от static class и введением отдельной специальной сущности. Никакой особой цели кроме как семантически связать набор статических методов с определенным типом оно не преследует.
Здравствуйте, HrorH, Вы писали:
HH>Здравствуйте, Serginio1, Вы писали:
S>> Шейпы я так понимаю, это сделать аналог С++ шаблонов c перегрузкой операторов, по аналогии с расширениями.
HH>Я так понимаю что шейпы это аналог классов типов из Haskell. HH>Но без поддержки Higher Kinded Polymorphism оно будет далеко не таким мощным как в Haskell.
В С++ напрополую используют перегрузку операторов в шаблонах. Для дженериков не было конструкций которые бы использовали уже существующие перегрузки операторов или которые можно было бы добавить. Проблема даже с обычными числовыми данными. Нужно добавлять интерфейс и для каждого типа добавлять Add, Div итд
C шейпами нам нужно добавить недостающие операторы или их переопределить (используя различные пространства имен как это сделано для расширений). Очень нужная конструкция.
public shape SGroup<T>
{
static T operator +(T t1, T t2);
static T Zero {get;}
}
This declaration says that a type can be an SGroup<T> if it implements a+ operator over T, and a Zero static property.
public extension IntGroup of int: SGroup<int>
{
public static int Zero => 0;
}
And the extension.
public static AddAll<T>(T[] ts) where T: SGroup<T> // shape used as constraint
{
var result = T.Zero; // Making use of the shape's Zero property foreach (var t in ts) { result += t; } // Making use of the shape's + operator return result;
}