Здравствуйте, Sinclair, Вы писали: S>Это у меня глюки, или компилер еще умнее, чем я ожидал?
Все совершенно правильно. Это т.н. lifted operators плюс (nullable conversions, позволяющие поднять int до int?):
14.2.7 Lifted operators
Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to
also be used with nullable forms of those types. Lifted operators are constructed from predefined and userdefined
operators that meet certain requirements, as described in the following:
• For the unary operators
+ ++ — -- ! ~
a lifted form of an operator exists if the operand and result types are both non-nullable value types. The
lifted form is constructed by adding a single ? modifier to the operand and result types. The lifted operator
produces a null value if the operand is null. Otherwise, the lifted operator unwraps the operand, applies the
underlying operator, and wraps the result.
...
The semantics of the is operator have been changed according to Nullable<T> boxing and unboxing changes. The following two examples equate to true when x is either T or a non-null T?. Otherwise, each example equates to false.
// true when x is T or a non-null T?; otherwise, false.x is T?
// true when x is T or a non-null T?; otherwise, false
x is T
Given the following initialization of x, y, and z, the Boolean values for b1, b2, b3, and b4 are determined as shown in the following example:
//
[c#]
int? x = null;
int? y = 10;
int z = 10;
// False; x is boxed as null, null is
// always false.
bool b1 = (x is int?);
// True; y is boxed as int, new behavior
// ensures this is true.
bool b2 = (y is int?);
// True; z is boxed as int, same as b2
// (cannot differentiate).
bool b3 = (z is int?);
// True; y and z are boxed as int, ordinary
// check applies.
bool b4 = (y is int) && (z is int);
Похоже тееперь в MS считают преобразования между T и T? разновидностью боксинга. С другой стороны, спецификация выделяет такие преобразования в отдельный класс (см. 13.7.2 Nullable conversions), к боксингу отношения не имеющий.
Здравствуйте, VladD2, Вы писали:
VD>А причем тогда doc-файлы?
Еще раз. Вместе с VS2005 ищет doc-файл, описывающий изменения между версиями языка 1.2 и 2.0. Так вот этот doc-файл содержит больше информации по сравнению с ecma.pdf. Скажем, я не могу объяснить исходя из ECMA, почему i is int? дает true в compile-time-е. Если ты можешь, то объясни, как это следует из там написанного -- это действительно интересно.
Одноврменно в doc-файле есть раздел, явно оговаривающий такое поведение is-а.
Здравствуйте, Воронков Василий, Вы писали: ВВ>Как я понимаю, в выражении i is int? значок "?" является частью _названия_ типа.Соответственно, получаем:
Ну ты бы попробовал компилировать свои примеры хотя бы перед тем как писать Знак вопроса и int -- два отдельных токена. Есть между ними пробел или нет -- без разницы.
Подобные примеры не специфицированы потому что при их разборе не возникает неоднозначностей. Да, надо проводить чуть более сложный анализ, но разбор корректного выражения синтаксически всегда однозначен.
Здравствуйте, VladD2, Вы писали:
VD>Однозначен то он однозначен. Но это же требует LL(*)-парсера. VD>Мне нужно азрулить ситуацию на CocoR который строит только LL(1)-парсеры с возможностью ручного заглядывания вперед (хоть до посинения).
VD>Так вот у меня есть варианты: VD>1. Попытаться распознать выражение идущее за "?". Если выражение распознается и за ним идет ":" мы имеем дело с оператором "?:" и дело в шляпе. Если нет, то принимаем решение, что "?" — это часть определения типа. VD>Так вот проблема в том, что ручной анализ выражения — это застрелиться . VD>2. Придумать некую эвристику (наподобии той, что применяется для разруливания неоднозначностей с "F(G<A, B>(7));". VD>В общем, первый способ конечно надежен, но сложен и медленнен. VD>Между тем, описанная неоднозначность возникает только в случае применения оператора "is" в сочетании с нулбл-типами и/или оператором "?:". VD>Вот и хотелось бы попытаться определить эвристику по которой можно было бы ограничиться проверкой некоторого набора лексем. VD>Ведь если пойти логически, то если после "?" следуют: ")", "=", "?" (возможно что-то еще), то "?" точно являетс частью определения типа. VD>Вот и хотелось бы попытаться продумать набор таких предположений и проверить не возникает ли при этом каких-то проблем.
У меня получился такой список:
если после '?' идет одно из:
то, увы придется делать попытку разбора последовательности токенов как выражение, и проверить следующее за выражением токен. Если он ':', то '?' является частью условного выражения. В противном случае частью типа.
VD>Зачем встроена поддержка в джит, понятно. Это сделано для эмуляции красобы при работе с боксингом.
Ты шире взгляни. Это сделано для удобства работы программиста с Nullable.
VD>А вот химия компилятора не очень очевидна.
Да, в общем, за тем же. Для удобства программиста.
Похоже, при разработке C# 2.0 у них вообще поменялась внутренняя установка. Простота реализации компилятора больше их не волнует, главное преимущества языка/платформы для разаработчика. Смотри, сколько инфраструктурных багов нашли...
Вон, даже non-verifiable можно получить без ключа /unsafe, а они это за серьёзную ошибку не считают. Видно, зашиваются совсем по времени. Кстати, и Эрик Ганнерсон дёрнул в сторону именно на этапе C# 2.0, почуял неладное что ли?
Здравствуйте, Alexander__S, Вы писали:
A__>Извините за настырность, но опять-таки, почему компилятора? Может быть, все-таки CLR в рантайме во время выполнения оператора is проверяет, является ли тип Nullable, инстанцированным данным типом?
Здравствуйте, Mab, Вы писали:
Mab>Здравствуйте, Воронков Василий, Вы писали: ВВ>>Как я понимаю, в выражении i is int? значок "?" является частью _названия_ типа.Соответственно, получаем: Mab>Ну ты бы попробовал компилировать свои примеры хотя бы перед тем как писать Знак вопроса и int -- два отдельных токена. Есть между ними пробел или нет -- без разницы.
А может у меня компилилки нету
Re[3]: О nullable-типах и операторе "? :"
Здравствуйте, Smarty, Вы писали:
S>По-моему заместо заумной фигни с боксингами одна фраза S>
S>An is expression evaluates to true if the provided expression is non-null, and the provided object can be cast to the provided type without causing an exception to be thrown.
S>легко и элегантно объясняет результаты по всем 4м буллам....
1. Насколько я понимаю, это фраза из C# Programmer's Reference. По статусу это всего лишь некие сопроводительные комментарии, а никак не спецификакиция. Мы же здесь обсуждаем стандарт ECMA-334.
2. Если ты считаешь, что эта фраза сама по себе способна что-то объяснить, то ошибаешься. Скажем, при вычислении operator is не учитываются explicit user-defined conversions.
3. В том же Programmer's Rereference в самом конце еще написано:
Note that the is operator only considers reference conversions, boxing conversions, and unboxing conversions. Other conversions, such as user-defined conversions, are not considered.
Мягко говоря, это не тот стиль, которым описывается стнандарт языка (note that совершенно не уместен). В любом случае, ECMA-334 не считает преобразование от int к int? разновидностью боксинга.
Проблема скорее всего в том, что готовой версии стандарта нет. То, что я сейчас смотрю -- это 3rd Edition/June 2005. Вместе с VS2005 Release идет некий doc-файл, озаглавленный C# Language Spec 2.0, представляющий собой дополнение к спецификации 1.2. В этом файле есть раздел 20.8.4 (никак не коррелирующий с таковым в ECMA -- нумерация тут другая):
The is operator (§7.9.9) is extended to support nullable types. An operation of the form e is T, where e is an expression and T is a type, is evaluated as follows, after type arguments have been substituted for all type parameters:
• If the type of e is a reference type or a nullable type and the value of e is null, the result is false.
• Otherwise, let D represent the dynamic type of e as follows:
o If the type of e is a reference type, D is the run-time type of the instance reference by e.
o If the type of e is a nullable type, D is the underlying type of that nullable type.
o If the type of e is a non-nullable value type, D is the type of e.
• The result of the operation depends on D and T as follows:
o If T is a reference type, the result is true if D and T are the same type, if D is a reference type and an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
o If T is a nullable type, the result is true if D is the underlying type of T.
o If T is a non-nullable value type, the result is true if D and T are the same type.
o Otherwise, the result is false.
Жирным выделены пункты, обяъсняющие поведение компилятора.
Здравствуйте, VladD2, Вы писали:
VD>Плюс смущает, что "i is int?" вообще компилируется. Ведь i имеет тип int, а не int?. Это случаем не баг? VD>Какой раздел спецификации описывает это дело?
Ну так раз i is int? вообще не компилируется, значит тут никакой неоднозначности нет.
Здравствуйте, VladD2, Вы писали:
ВВ>>Ну так раз i is int? вообще не компилируется, значит тут никакой неоднозначности нет. VD>Я привел полностью компилируемый код.
Да, пардон. Что-то у меня уже от недосыпа в глаза двоится.
Здравствуйте, VladD2, Вы писали:
VD>Что-то я не въеду в принципы по которым компилятор должен отличать nullable-тип и оператор "? :". VD>Например: VD>
VD>int i = 0;
VD>Console.WriteLine(i is int?);
VD>Console.WriteLine(i is int? "+" : "-");
VD>Надо заглядывать вперед анализируя наличие ":"? Или есть более простая эвристика?
А если наоборот — проверять является ли выражение проверкой типа? Т.е. не так уж и много вариантов завершения проверки i is int? — ";", ")", "]", "?"... Просто касательно провреки на наличие ":" мне не очень понятно ( по кр. мере сейчас ). Ведь между "?" и ":" может быть километр кода.
Здравствуйте, VladD2, Вы писали:
VD>Что-то я не въеду в принципы по которым компилятор должен отличать nullable-тип и оператор "? :". VD>Например: VD>
VD>int i = 0;
VD>Console.WriteLine(i is int?);
VD>Console.WriteLine(i is int? "+" : "-");
VD>Надо заглядывать вперед анализируя наличие ":"? Или есть более простая эвристика?
VD>Плюс смущает, что "i is int?" вообще компилируется. Ведь i имеет тип int, а не int?. Это случаем не баг? VD>Какой раздел спецификации описывает это дело?
Это самая плохо специфицированная часть стандарта C#. Стандарт по этому поводу ничего не говорит.
Можно вычислить FIRST(expression) и FOLLOW(expression) и проанализировать первый токен после '?'.
токены FIRST(expression) будут соответствовать выражению
токены FOLLOW(expression) будут соответствовать типу
class tint<T> where T: struct{};
static void Main()
{
int i = 0;
Console.WriteLine(i is int?);
Console.WriteLine(i is tint<int>); // а тут false
Console.WriteLine(i is int? "+" : "-");
new Program();
}
Здравствуйте, Alexander__S, Вы писали:
A__>Здравствуйте, VladD2, Вы писали:
VD>>Плюс смущает, что "i is int?" вообще компилируется. Ведь i имеет тип int, а не int?. Это случаем не баг?
A__>Так же, как компилируется i is object, i is SomeType и проч. зачем тогда вообще нужен is? Я понимаю, четыре часа ночи...
VladD2 хотел сказать, что если
int i;
Console.Write( i is int? );
или
int? i;
Console.Write( i is int );
то в обоих случаях на экран вылезет true. И это действительно странно, ибо
public struct Nullable<T> where T : struct
вряд ли должно соответствовать типу T.
Провёл пару экспериментов, -> пришёл к выводу, что тип Nullable в самом деле выделен на уровне языка.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>А если наоборот — проверять является ли выражение проверкой типа? Т.е. не так уж и много вариантов завершения проверки i is int? — ";", ")", "]", "?"...
О том и речь. Но хотелось бы иметь четкий алгоритм, а не придумывать собственные эвристики.
ВВ>Просто касательно провреки на наличие ":" мне не очень понятно ( по кр. мере сейчас ). Ведь между "?" и ":" может быть километр кода.
О том и речь. Нужно будет вручную (для гребаного CocoR) распознать любое выражение . Но есть нужен или пасрер LL(*), или много ручного траха.
... << RSDN@Home 1.2.0 alpha rev. 628>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Алексей., Вы писали:
А>Подобные примеры не специфицированы потому что при их разборе не возникает неоднозначностей. Да, надо проводить чуть более сложный анализ, но разбор корректного выражения синтаксически всегда однозначен.
Однозначен то он однозначен. Но это же требует LL(*)-парсера.
Мне нужно азрулить ситуацию на CocoR который строит только LL(1)-парсеры с возможностью ручного заглядывания вперед (хоть до посинения).
Так вот у меня есть варианты:
1. Попытаться распознать выражение идущее за "?". Если выражение распознается и за ним идет ":" мы имеем дело с оператором "?:" и дело в шляпе. Если нет, то принимаем решение, что "?" — это часть определения типа.
Так вот проблема в том, что ручной анализ выражения — это застрелиться .
2. Придумать некую эвристику (наподобии той, что применяется для разруливания неоднозначностей с "F(G<A, B>(7));".
В общем, первый способ конечно надежен, но сложен и медленнен. Между тем, описанная неоднозначность возникает только в случае применения оператора "is" в сочетании с нулбл-типами и/или оператором "?:".
Вот и хотелось бы попытаться определить эвристику по которой можно было бы ограничиться проверкой некоторого набора лексем.
Ведь если пойти логически, то если после "?" следуют: ")", "=", "?" (возможно что-то еще), то "?" точно являетс частью определения типа.
Вот и хотелось бы попытаться продумать набор таких предположений и проверить не возникает ли при этом каких-то проблем.
... << RSDN@Home 1.2.0 alpha rev. 628>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, RoloTomasi, Вы писали:
RT>Ладно компилируется почему true получаем?
Более корректный тест будет выглядеть так:
using System;
class Test<T> where T: struct
{
public Test(T t) { _t = t; }
T _t;
public static implicit operator T(Test<T> test) { return test._t; }
};
class Program
{
static void Main()
{
int i = 0;
Console.WriteLine(i is int);
Console.WriteLine(i is Test<int>); // а тут false
Console.WriteLine(i is int?);
Console.WriteLine(i is int? "+" : "-");
Console.WriteLine(i is int ? ?"+" : "-");
}
}
но все равно получается false. Так что поддержка нулбл-типов явно встроена в язык по самые помидоры. Или это ошибка компилятора.
... << RSDN@Home 1.2.0 alpha rev. 628>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>но все равно получается false. Так что поддержка нулбл-типов явно встроена в язык по самые помидоры. Или это ошибка компилятора.
Извините за настырность, но опять-таки, почему компилятора? Может быть, все-таки CLR в рантайме во время выполнения оператора is проверяет, является ли тип Nullable, инстанцированным данным типом?
Или, может быть, имелся в виду JIT-компилятор, который генерирует неправильный код для isinst?
Re[2]: О nullable-типах и операторе "? :"
От:
Аноним
Дата:
14.01.06 15:11
Оценка:
>Или это ошибка компилятора.
Или горе от ума очередное.
В vb.net конструкция наподобие этой
Console.WriteLine(TypeOf i Is Integer)
Console.WriteLine(TypeOf i Is Test(Of Integer)()) ' а тут false
Console.WriteLine(TypeOf i Is Nullable(Of Integer))
вовсе не существует — слева от Is может быть только ссылочный тип.
Ну, и оператора "?" вместе с синтаксисом int? — тоже нету.
Все на VB.NET!!!
Здравствуйте, Alexander__S, Вы писали:
A__>Извините за настырность, но опять-таки, почему компилятора? Может быть, все-таки CLR в рантайме во время выполнения оператора is проверяет, является ли тип Nullable, инстанцированным данным типом?
Тут компилятор сразу пишет "результат"
int i = 0;
Console.WriteLine(i is int?);
Console.WriteLine(i is int? "+" : "-");
Мелькает еще одна мысль, только непонятно есть в ней прок или нет.
Как я понимаю, в выражении i is int? значок "?" является частью _названия_ типа.Соответственно, получаем:
bool b = i is int?; //валидно
bool b = i is int ?; //невалидно
может, получится как-нибудь хитро разруливать это на этапе проверки имени типа?
Здравствуйте, mormat, Вы писали:
M>Здравствуйте, Alexander__S, Вы писали:
A__>>Здравствуйте, VladD2, Вы писали:
VD>>>Плюс смущает, что "i is int?" вообще компилируется. Ведь i имеет тип int, а не int?. Это случаем не баг?
A__>>Так же, как компилируется i is object, i is SomeType и проч. зачем тогда вообще нужен is? Я понимаю, четыре часа ночи...
M>VladD2 хотел сказать, что если M>
M> int i;
M> Console.Write( i is int? );
M>
M>или M>
M> int? i;
M> Console.Write( i is int );
M>
M>то в обоих случаях на экран вылезет true. И это действительно странно, ибо
Это абсолютно НЕ странно ибо:
An is expression evaluates to true if the provided expression is non-null, and the provided object can be cast to the provided type without causing an exception to be thrown.
Преобразование int/int? однозначно есть в обе стороны.
Здравствуйте, Mab, Вы писали:
Mab>Похоже тееперь в MS считают преобразования между T и T? разновидностью боксинга. С другой стороны, спецификация выделяет такие преобразования в отдельный класс (см. 13.7.2 Nullable conversions), к боксингу отношения не имеющий.
По-моему заместо заумной фигни с боксингами одна фраза
An is expression evaluates to true if the provided expression is non-null, and the provided object can be cast to the provided type without causing an exception to be thrown.
легко и элегантно объясняет результаты по всем 4м буллам....
Mab>VS2005 считает такой код корректным (а вот Решарпер не считает, о чем уже оформлен соответствующий баг )
Не совсем. Соотв. ворнинг генерится. Возможно вместо ворнинга еррор должен быть, но это уже узко-техничесикй вопрос...
Re[3]: О nullable-типах и операторе "? :"
Влад, что именно не работает? Не получается объявить свой тип, ведущий себя как Nullable<T>? Факт, не получается и не получится.
Кстати, в ранних версиях 2005 этот самый Nullable<T> был вполне обычным типом. Но вот начиная с August CTP в дизайне произошли серьезные изменения: он стал частью рантайма и учитывается, например, при боксинге специальным образом. Подробнее можно почитать здесь: http://blogs.msdn.com/somasegar/archive/2005/08/11/450640.aspx
С точки зрения компилятора этот Nullable<T> тоже не обычный тип. Один из множества примеров: посмотри на lifted conversions. Для своих типов устроить такое ты не сможешь.
MSVC# во всех этих случаях не считает '?' частью типа. Что в общеим логично, учитывая что все они имеют более высокий приоритет чем оператор приведения as.
void f()
{
int a = 0;
int b = a is int + a is int; // int b = ( ( a is int ) + a ) is int;int b = a is int? + a is int; // int b = ( a is int ) ? ( ( + a ) is int ); error: expected ':'
}
Или вот (проблема кочующего ':'):
void f()
{
int a = 0;
int b = a is int? + a is int? + a : a;
}
Здравствуйте, Mab, Вы писали: Mab>Жирным выделены пункты, обяъсняющие поведение компилятора.
Кстати, по поводу стандарта. Я тут напоролся на то, что вот в таком контексте
Nullable<SomeType> a;
SomeOtherType b;
выражение a + b имеет тип Nullable<SomeType>, если есть соответствующий перегруженный оператор +, возвращающий SomeType.
Пример:
int? a = 5;
int b = 5;
Выражение a+b не только компилируется без ошибок, но и имеет тип int?, несмотря на отсутствие оператора + c соответствующими аргументами. Еще больше я удивился, когда увидел работоспособность выражения
(TimeSpan.FromDays(1)+(DateTime?)Now).HasValue;
Это у меня глюки, или компилер еще умнее, чем я ожидал?
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, mihailik, Вы писали:
M>Ты шире взгляни. Это сделано для удобства работы программиста с Nullable.
Проблема в том, что люди страдают очень часто из-за того что кто-то хотел им помочь.
M>Похоже, при разработке C# 2.0 у них вообще поменялась внутренняя установка. Простота реализации компилятора больше их не волнует, главное преимущества языка/платформы для разаработчика. Смотри, сколько инфраструктурных багов нашли...
У них такая установка была с самого начала. Иначе бы не нужно было бы делать C#. Ява в разы проще парсится.
M>Кстати, и Эрик Ганнерсон дёрнул в сторону именно на этапе C# 2.0, почуял неладное что ли?
А кто это?
... << RSDN@Home 1.2.0 alpha rev. 628>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: О nullable-типах и операторе "? :"
Здравствуйте, Mab, Вы писали:
Mab>Влад, что именно не работает? Не получается объявить свой тип, ведущий себя как Nullable<T>? Факт, не получается и не получится.
Здравствуйте, Mab, Вы писали:
Mab>Проблема скорее всего в том, что готовой версии стандарта нет. То, что я сейчас смотрю -- это 3rd Edition/June 2005. Вместе с VS2005 Release идет некий doc-файл, озаглавленный C# Language Spec 2.0, представляющий собой дополнение к спецификации 1.2.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Mab, Вы писали:
Mab>>Проблема скорее всего в том, что готовой версии стандарта нет. То, что я сейчас смотрю -- это 3rd Edition/June 2005. Вместе с VS2005 Release идет некий doc-файл, озаглавленный C# Language Spec 2.0, представляющий собой дополнение к спецификации 1.2.
VD>Вообще-то есть полный pdf: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf
Именно на этот файл я и ссылался, говоря 3rd Ed. June.
Здравствуйте, VladD2, Вы писали:
M>>Кстати, и Эрик Ганнерсон дёрнул в сторону именно на этапе C# 2.0, почуял неладное что ли?
VD>А кто это?
Програм-менеджер команды разработки C#. Где то в районе первой беты С# 2.0 (могу немного ошибаться в сроках) свалил обычным разработчиком в команду что пишет новую версию Windows Movie Maker.