В C# 4.0 наконец-то появился вывод типов из аргументов, которые сами являются method groups. Это позволяет писать всякие хитрые комбинации generic методов, нигде явно не указывая типов-аргументов.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var y = new List<int> {1, 2, 3};
var z = y.ConvertAll(ConvertToString);
}
static string ConvertToString<T>(T x)
{
return x.ToString();
}
static string ConvertToString(Guid x)
{
return x.ToString("N");
}
}
Здравствуйте, nikov, Вы писали:
N>В C# 4.0 наконец-то появился вывод типов из аргументов, которые сами являются method groups. Это позволяет писать всякие хитрые комбинации generic методов, нигде явно не указывая типов-аргументов.
А что они вывод типов для конструкторов то не сделают?
Кривотень ведь еще та.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, nikov, Вы писали:
N>В C# 4.0 наконец-то появился вывод типов из аргументов, которые сами являются method groups. Это позволяет писать всякие хитрые комбинации generic методов, нигде явно не указывая типов-аргументов.
Где можно прочитать описание как это работает/должно работать?
Кстати, есть еще одно интересное изменение в спецификации насчет Fixing'а.
Новый вариант:
• We then examine each bound for Xi in turn: For each exact bound U of Xi all types Uj which are not identical to U are removed from the candidate set. For each lower bound U of Xi all types Uj to which there is not an implicit conversion from U are removed from the candidate set. For each upper bound U of Xi all types Uj from which there is not an implicit conversion to U are removed from the candidate set.
Заметьте, что здесь говорится о необходимости implicit conversion, в то время как старый вариант говорил о standard implicit conversion (более узкое множество). На самом деле компилятор и в предыдущей версии работал, как будто речь идет обо всех implicit conversion — разработчики компилятора забыли передать нужный флаг, а я заметил это уже после релиза. Теперь решили привести спецификацию в согласованное состояние с реализацией.
На самом деле сейчас всё сделали, как и было написано в разделе 7.4.2.6 Output type inferences ещё в спецификации C# 3.0. Overload resolution вполне можно произвести, когда все типы аргументов заданы изначально или выведены ранее. То, что написано на коннекте выглядит просто как не очень серьёзное оправдание.
Здравствуйте, nikov, Вы писали:
VD>>А что они вывод типов для конструкторов то не сделают? VD>>Кривотень ведь еще та.
N>Увы. Даже не слышал, чтобы такое планировалось.
Я тоже. Вообще, не ясно, они там совсем от народа оторвались? Ведь принципиальных проблем с эти не должно быть. Их не не полноценный вывод типов просят сделать, а практически то, что уже есть. Ведь фабричные методы выводятся на раз.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Их не не полноценный вывод типов просят сделать, а практически то, что уже есть.
Ну не совсем то. Классы можно перегружать по количеству типов-параметров. Если мы позволим опускать типы-аргументы при выводе, то множество конструкторов-кандидатов придется собирать из разных, никак не связанных, типов.
Возникает и много других вопросов. А если конструктор вызван с object/collection initializer (как List в моем примере), то учитывать ли типы выражений в этом инициализаторе для вывода типов-аргументов создаваемого класса? А ведь это могут быть аргументы для нескольких разных методов Add, которые в свою очередь могут быть generic. А учитывать ли иницициализаторы для вложенных объектов? И т.д. и т.п. В общем, нетривиальная задача.
Здравствуйте, nikov, Вы писали:
N>Ну не совсем то. Классы можно перегружать по количеству типов-параметров. Если мы позволим опускать типы-аргументы при выводе, то множество конструкторов-кандидатов придется собирать из разных, никак не связанных, типов.
N>Возникает и много других вопросов. А если конструктор вызван с object/collection initializer (как List в моем примере), то учитывать ли типы выражений в этом инициализаторе для вывода типов-аргументов создаваемого класса? А ведь это могут быть аргументы для нескольких разных методов Add, которые в свою очередь могут быть generic. А учитывать ли иницициализаторы для вложенных объектов? И т.д. и т.п. В общем, нетривиальная задача.
Вопрос возникают только у тех, кто хочет найти отговорки для того чтобы ничего не делать.
А на практике, в случаях неоднозначности можно выдавать сообщения об ошибках. А 99% кода будет работать как надо.
Еще раз повторюсь, что раз фабричные методы прокатывают, то и конструктор можно рассматривать как такой фабричный метод.
Погляди на кортежи из .NET 4.0. Методы Create() — это же форменные костыли.
Я бы со стыда сгорел от такой халтуры.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Вопрос возникают только у тех, кто хочет найти отговорки для того чтобы ничего не делать. VD>А на практике, в случаях неоднозначности можно выдавать сообщения об ошибках. А 99% кода будет работать как надо.
Да я, в общем-то, не возражаю. Пусть сделают.
А когда в Nemerle появится вывод сигнатуры для приватных методов класса? А то всё пишет, что not yet implemented, мол.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, VladD2, Вы писали:
VD>>Их не не полноценный вывод типов просят сделать, а практически то, что уже есть.
N>Ну не совсем то. Классы можно перегружать по количеству типов-параметров. Если мы позволим опускать типы-аргументы при выводе, то множество конструкторов-кандидатов придется собирать из разных, никак не связанных, типов.
Этого ни в коем случае допускать нельзя, можно же просто ввести синтаксис для различия generic overloads:
var dict = new Dictionary<,> {
{ 1, "abc" },
{ 2, "def" }
};
Другое дело в том, насколько это будет непонятно
Получается что "Dictionary<,>" будет иметь сильно разный смысл в зависимости от контекста: в typeof() и new expression...
N>Возникает и много других вопросов. А если конструктор вызван с object/collection initializer (как List в моем примере), то учитывать ли типы выражений в этом инициализаторе для вывода типов-аргументов создаваемого класса? А ведь это могут быть аргументы для нескольких разных методов Add, которые в свою очередь могут быть generic. А учитывать ли иницициализаторы для вложенных объектов? И т.д. и т.п. В общем, нетривиальная задача.
Здравствуйте, nikov, Вы писали:
N>Да я, в общем-то, не возражаю. Пусть сделают. N>А когда в Nemerle появится вывод сигнатуры для приватных методов класса? А то всё пишет, что not yet implemented, мол.
Это сильно усложнит работу интеграции. Если не ошибаюсь, в одном из комитов я поправил предупреждение.
Вывод будет доступен только для параметров имеющих значения по умолчанию.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Пельмешко, Вы писали:
N>>Ну не совсем то. Классы можно перегружать по количеству типов-параметров. Если мы позволим опускать типы-аргументы при выводе, то множество конструкторов-кандидатов придется собирать из разных, никак не связанных, типов.
П>Этого ни в коем случае допускать нельзя, можно же просто ввести синтаксис для различия generic overloads: П>
Другое дело в том, насколько это будет непонятно П>Получается что "Dictionary<,>" будет иметь сильно разный смысл в зависимости от контекста: в typeof() и new expression...
Не нужно ничего подобного делать. Если параметры типа не выводятся по простому, то можно просто попросить программиста задать их явно.
В прочем, приведенный пример — это вывод типов из использования, так как данный синтаксис переписывается в присвоение свойств или полей. Но и тут в МС могли бы просто захардкодить этот солучай.
N>>Возникает и много других вопросов. А если конструктор вызван с object/collection initializer (как List в моем примере), то учитывать ли типы выражений в этом инициализаторе для вывода типов-аргументов создаваемого класса? А ведь это могут быть аргументы для нескольких разных методов Add, которые в свою очередь могут быть generic. А учитывать ли иницициализаторы для вложенных объектов? И т.д. и т.п. В общем, нетривиальная задача.
П>А вот это пипец..
Если алгоритм вывода типов грамотный, то все будет ОК. Для шарпа можно тупо ругаться на не однозначные (с его точки зрения) случаи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Пельмешко, Вы писали:
N>>>Ну не совсем то. Классы можно перегружать по количеству типов-параметров. Если мы позволим опускать типы-аргументы при выводе, то множество конструкторов-кандидатов придется собирать из разных, никак не связанных, типов.
П>>Этого ни в коем случае допускать нельзя, можно же просто ввести синтаксис для различия generic overloads: П>>
Другое дело в том, насколько это будет непонятно П>>Получается что "Dictionary<,>" будет иметь сильно разный смысл в зависимости от контекста: в typeof() и new expression...
VD>Не нужно ничего подобного делать. Если параметры типа не выводятся по простому, то можно просто попросить программиста задать их явно.
Интересно, почему тогда в F# приходится использовать placeholder чтобы руками указать, что создавать будем?
let foo =
let d = new Dictionary<_,_>()
d.Add(1, "abc")
d.Add(2, "def")
d
Здравствуйте, Пельмешко, Вы писали:
П>Интересно, почему тогда в F# приходится использовать placeholder чтобы руками указать, что создавать будем? П>
П>let foo =
П> let d = new Dictionary<_,_>()
П> d.Add(1, "abc")
П> d.Add(2, "def")
П> d
П>
П>Мне всё же кажется, что это неспроста
Я не уверен, что ты вообще прав. Но если это так, то это вопрос к его разработчику и тем кто хочет протолкнуть в массы такой язык. В Nemerle никакихъ проблем с этим нет:
using System.Collections.Generic;
using System.Console;
module Program
{
Main() : void
{
def d = Dictionary();
d.Add(1, "abc");
d.Add(2, "def");
foreach (x in d)
WriteLine($"$(x.Key)=$(x.Value)");
}
}
Более того работает автодополнение при воводе, хинты и т.п. (в IDE).
Вот если будут неоднозначности, то надо будет или плэйсхолдеры задать (как в F#-примере) или даже реальные типы. В прочем, вероятность того, что такая неоднозночность возникнет, на практике, весьма мала. Так что это не более чем теоритические рассуждения цель которых отмазаться от сложной работы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Но на практике такого я не встречал. Типы создаются для конкретных нужд и эти нужды сами определяют разичия между ними.
Например, таплы обычно различают по количеству элементов. Можно, конечно же количество добавляь к имени класса Tuple2<,>; Tuple3<,,> но просто Tuple<,>; Tuple<,,> ИМХО, эстетичнее.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Например, таплы обычно различают по количеству элементов. Можно, конечно же количество добавляь к имени класса Tuple2<,>; Tuple3<,,> но просто Tuple<,>; Tuple<,,> ИМХО, эстетичнее.
С кортежами никогда никаких проблем не было. У них разные списки параметров типов. В примере приведенно выше было намеренно смоделирована ситуация когда есть два типа конфликтующих при выводе (с типом и такой же без него). У кортежей же всегда разное количество параметров типов которые всегда определяются конструктором.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
_FR>>Например, таплы обычно различают по количеству элементов. Можно, конечно же количество добавляь к имени класса Tuple2<,>; Tuple3<,,> но просто Tuple<,>; Tuple<,,> ИМХО, эстетичнее.
VD>С кортежами никогда никаких проблем не было. У них разные списки параметров типов. В примере приведенно выше было намеренно смоделирована ситуация когда есть два типа конфликтующих при выводе (с типом и такой же без него). У кортежей же всегда разное количество параметров типов которые всегда определяются конструктором.
Ах да, точно
На самом деле оригинальный вариант так же не редкость (по аналогии с дженерик-методами и методами с тем же именем, но без дженерик-аргументов), но в шарпе это не причиняет неудобств, пока нет вывода типа в вызове конструктора.
Help will always be given at Hogwarts to those who ask for it.