[C# 3.0] Новый алгоритм type argument inference.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 07.09.07 09:40
Оценка: +2
Как известно, в C# 3.0 изменился (по сравнению с C# 2.0) алгоритм для type argument inference. Теперь он стал более "умным", происходит в несколько фаз и учитывает сигнатуры и тип возвращаемого значения для анонимных методов и methods groups, которые переданы в качестве аргументов. Я попытался разобраться в описании этого алгоритма, который присутствует в C# 3.0 Specification Draft, 7.4.2 Type inference.
Сравнение его с актуальными результатами, которые показывает компилятор в Orcas Beta 2, производит впечатление, что поведение компилятора не согласуется со спецификацией. Я предлагаю всем, кого интересует эта тема, проанализировать один простой пример, и решить, прав ли я в своих выводах.

using System.Collections.Generic;

interface IFace : IList<int>, IList<long> { }

class A
{
    static void Foo<T>(IList<T> x, T y) { }
    static void Bar(IFace x)
    {
        Foo(x, 1);
    }
}


Первая фаза.

Для первого аргумента.
Производится output type inference из x для типа IList<T>. Оно сводится к lower-bound inference из типа IFace для типа IList<T>. Так как невозможно определить единственный тип T такой, что существует стандартное неявное преобразование из IFace в IList<T> (подходит и int и long), то на данном этапе ничего не выводится (no inferences are made). Заметим, что это не означает, что выведение типов терпит неудачу целиком.

Для второго аргумента.
Производится output type inference из 1 для типа T. Оно сводится к lower-bound inference из типа int для типа T. Так как T — это незафиксированный (unfixed) тип-параметр, то тип int добавляется к списку границ (bounds) для T.

Вторая фаза.

Type parameter T фиксируется. Так как он имеет единственную границу int, он просто фиксируется как int. Так как больше не осталоь незафиксированнх типов-параметров, выведение типов завершается успешно.

Таким образом, для T должно быть успешно выведено значение int, и программа должна упешно скомпилироваться. Однако, эксперимент показывает, что выдается ошибка компиляции:


error CS0411: The type arguments for method 'A.Foo<T>(T, System.Collections.Generic.IList<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.


Налицо несоответствие.
Re: [C# 3.0] Новый алгоритм type argument inference.
От: Константин Л. Франция  
Дата: 07.09.07 12:23
Оценка:
[]

N>Первая фаза.


[]

тут вроде все правильно.

N>Вторая фаза.


N>Type parameter T фиксируется. Так как он имеет единственную границу int, он просто фиксируется как int. Так как больше не осталоь незафиксированнх типов-параметров, выведение типов завершается успешно.


ага,

All unfixed type variables Xi which do not depend on (§7.4.2.5) any Xj are fixed (§7.4.2.10). -> The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.


N>Таким образом, для T должно быть успешно выведено значение int, и программа должна упешно скомпилироваться. Однако, эксперимент показывает, что выдается ошибка компиляции:


N>

N>error CS0411: The type arguments for method 'A.Foo<T>(T, System.Collections.Generic.IList<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.


N>Налицо несоответствие.


согласен.
Re: [C# 3.0] Новый алгоритм type argument inference.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 08.09.07 16:47
Оценка: 6 (1)
Здравствуйте, nikov, Вы писали:

N>Сравнение его с актуальными результатами, которые показывает компилятор в Orcas Beta 2, производит впечатление, что поведение компилятора не согласуется со спецификацией. Я предлагаю всем, кого интересует эта тема, проанализировать один простой пример, и решить, прав ли я в своих выводах.


Отправил баг-репорт в MS. Проследить его судьбу можно здесь.
Re[2]: [C# 3.0] Новый алгоритм type argument inference.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 12.09.07 15:02
Оценка: 7 (2) :)
Здравствуйте, nikov, Вы писали:

N>Отправил баг-репорт в MS. Проследить его судьбу можно здесь.


А вот и ответ (мной выделены основные моменты):

Hello nikov, once again this is Eric Lippert on the C# Compiler Development Team.
Thank you for your detailed analysis of the method type inference algorithm for the case where you have multiple implementations of a generic interface.
When I implemented the C# 3.0 type inference algorithm back in November of 2006 one of the questions I had was what to do in exactly this situation. We identified three possibilities:

1) Cause type inference to immediately fail. (This is what C# 2.0 did, and it seems somewhat reasonable to throw up ones hands and give up when confronted with such an ambiguity.)
2) Add all the possible inferences to the inference set. Later pick the "best" one when we "fix" the type parameter.
3) Add no inferences to the inference set. Hope that another argument will provide inferences.

After much discussion we decided to implement #1. Unfortunately, when the standard got rewritten, we accidentally wrote #3 into the standard. Therefore your analysis is correct.
Obviously we are now at a point where something probably should change, since the implementation is not in line with the specification. I have discussed this with the language and compiler program managers and we've decided that:

* we will not change the implementation or the standard for the "Orcas" release.
* we will _probably_ fix the implementation to match the standard in some post-Orcas release.

However, it's worth noting that we have a number of ideas for improvements to the method type inference algorithm which we did not have time to get into Orcas. (For instance, we could do a better job of detecting dependency cycles and "breaking" the cycles independently rather than breaking _every_ cycle as soon as it is identified. Or, we could keep track of information about whether a bound in the inference set was a contravariant, covariant or exact bound. And so on.)

It may be that if we decide to implement some of these new ideas in type inference, that this will affect our choice of #1, #2 or #3 when we do experiments and see how the proposed algorithm works in practice.

In any event, many apologies for producing this inconsistency, and many thanks for your bug report.

Eric Lippert

Re[3]: [C# 3.0] Новый алгоритм type argument inference.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 02.09.09 14:21
Оценка:
Здравствуйте, nikov, Вы писали:

N>

N>* we will _probably_ fix the implementation to match the standard in some post-Orcas release.


В C# 4.0 это заработало.
Re: [C# 3.0] Новый алгоритм type argument inference.
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.09.09 15:08
Оценка:
Здравствуйте, nikov, Вы писали:

А это:
N>
N>interface IFace : IList<int>, IList<long> { }
N>

вообще, нормально?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [C# 3.0] Новый алгоритм type argument inference.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 02.09.09 15:21
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>А это:

N>>
N>>interface IFace : IList<int>, IList<long> { }
N>>

VD>вообще, нормально?

В .NET — нормально, т.к. generics не основаны на erasure, и эти интерфейсы полностью различимы. В Scala, напрмер, такое не прокатит.
В Nemerle такое, насколько я помню, не работает. Кажется, авторы говорили, что это для упрощения алгоритмов.

В C# же нельзя делать вот так:
interface I<T> { }
class A<T> : I<int>, I<T> { } // error CS0695: 'A<T>' cannot implement both 'I<int>' and 'I<T>' because they may unify for some type parameter substitutions


, потому что интерфейсы могут стать неразличимыми при некоторых подстановках аргументов. Это описано в 13.4.2 Uniqueness of implemented interfaces.
Re[3]: [C# 3.0] Новый алгоритм type argument inference.
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.09.09 16:32
Оценка:
Здравствуйте, nikov, Вы писали:

N>В Nemerle такое, насколько я помню, не работает. Кажется, авторы говорили, что это для упрощения алгоритмов.


Вот я и гляжу, на то что Nemerle ругается и думаю — это баг или фича?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.