Re[8]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.01.10 16:39
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В общем, заэмитить это дело похоже можно. А вот считать через SRE, похоже нельзя. Остается или дублировать это дело с помощью процедур, или плюнуть на него.


У SR проблемы только с считыванием модификаторов у типов-аргументов. А что мешает ставить модификаторы на самом верхнем уровне? Ведь единственная их задача — обойти правило одинаковых сигнатур. Весь overload resolution всё равно будет на основе констрейнтов, которые записываются отдельно.
Re[9]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 17:47
Оценка:
Здравствуйте, nikov, Вы писали:

N>У SR проблемы только с считыванием модификаторов у типов-аргументов. А что мешает ставить модификаторы на самом верхнем уровне? Ведь единственная их задача — обойти правило одинаковых сигнатур. Весь overload resolution всё равно будет на основе констрейнтов, которые записываются отдельно.


Если только для типов параметров, то проблем быть не должно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.01.10 17:55
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В общем, заэмитить это дело похоже можно.


А надо ли разрешать перегрузку по констрейнтам, если тип-параметр метода не встречается в сигнатуре метода? И где ставить модификатор, если метод без параметров (есть только типы-параметры)?
Может быть, вообще всегда ставить модификатор на возвращаемое значение, ведь оно тоже считается частью сигнатуры в CIL. Надо проверить, можно ли прилепить модификатор на void.
Re[9]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 18:07
Оценка:
Здравствуйте, nikov, Вы писали:

N>А надо ли разрешать перегрузку по констрейнтам, если тип-параметр метода не встречается в сигнатуре метода? И где ставить модификатор, если метод без параметров (есть только типы-параметры)?


Не знаю. На первый взгляд — нет.
Вот реалистичный пример:
using System;
using System.Console;
using Nemerle.Utility;

public module Program
{
  Main() : void
  {
    mutable str1 : string;
    mutable str2 : string = "test";
    mutable val1 : int? = 1;
    mutable val2 : int? = null;
    mutable val3 : int = 1;
    
    WriteLine(str1.IsNull());
    WriteLine(str2.IsNull());
    WriteLine(val1.IsNull());
    WriteLine(val2.IsNull());
    WriteLine(val3.IsNull()); // На сегодня этот не работает
    _ = ReadLine();
  }
 
  public IsNull[T](this x : T?) : bool
    where T: struct
  {
    !x.HasValue
  }

  // эта перегрузка конфликтует с IsNull[T](this x : T) : bool where T: class
  public IsNull[T](this x : T) : bool 
    where T: struct
  {
    false
  }

  public IsNull[T](this x : T) : bool
    where T: class
  {
    x == null
  }
}


Хотелось бы, чтобы это работало. Ведь вполне логично, что если констрэйны позволяют отличить одну перегрузку от другой, то проблем быть не должно.
Это даст возможность создавать специализированные функции которые будут более эффективны и менее ограничены в свободе действий.

Ну, а методы которые не содержат параметры типов в описании параметров метода являются весьма редким являением. Обычно — это некие средства преобразования типов вроде Cast() из Linq-а.
Даже не знаю нужно ли в них создавать разные реализации на базе констрэйнов.

N>Может быть, вообще всегда ставить модификатор на возвращаемое значение, ведь оно тоже считается частью сигнатуры в CIL. Надо проверить, можно ли прилепить модификатор на void.


А что есть какие-то проблемы с ассоциацией modreq с самим методом?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.01.10 18:19
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А что есть какие-то проблемы с ассоциацией modreq с самим методом?


Есть.

Each modifer associates a type reference with an item in the signature.

Re[11]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 18:33
Оценка:
Здравствуйте, nikov, Вы писали:

N>

N>Each modifer associates a type reference with an item in the signature.


А что может быть item-ом?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.01.10 18:37
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, nikov, Вы писали:


N>>

N>>Each modifer associates a type reference with an item in the signature.


VD>А что может быть item-ом?


Ну, грубо говоря, тип.
См. Partition I, 8.6.1 Signatures.
Re[13]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 18:54
Оценка:
Здравствуйте, nikov, Вы писали:

N>Ну, грубо говоря, тип.

N>См. Partition I, 8.6.1 Signatures.

Дык вроде бы в ссылке что я привел как раз было сказано, что считать эту байду с параметра нельзя. Или нельзя с самого параметро, но можно с его типа?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Nullable
От: IT Россия linq2db.com
Дата: 18.01.10 18:58
Оценка: :)
Здравствуйте, VladD2, Вы писали:

VD>Это даст возможность создавать специализированные функции которые будут более эффективны и менее ограничены в свободе действий.


Частичная специализация?
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 19:15
Оценка:
Здравствуйте, IT, Вы писали:

IT>Частичная специализация?


Полная перегрузка .

Просто очень полезно иногда перегружать функции не только по их типам, но и по констрэйнам. Отличный пример IsNull():
http://www.rsdn.ru/forum/nemerle/3672473.1.aspx
Автор: VladD2
Дата: 18.01.10

У нас есть ссылочные типы, вэлью-типы и нулабл-типы. Для каждого из них эффективная реализация IsNull() должна быть уникальной.

Частичная же специализация — это термин из шаблонов. Похоже, но не совсем то.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.01.10 20:35
Оценка: 41 (1)
Здравствуйте, VladD2, Вы писали:

VD>Дык вроде бы в ссылке что я привел как раз было сказано, что считать эту байду с параметра нельзя. Или нельзя с самого параметро, но можно с его типа?


Нет, там написано, что если тип параметра — это дженерик или массив или указатель, то нельзя считать модификаторы с типов-аргументов этого дженерика или с типа элемента массива или указателя, а можно только с верхнего уровня.

Вот тебе прототип:

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Linq;

class Program
{
    static void Main()
    {
        var assemblyName = new AssemblyName("modopt");
        var assemblyBuilder =
            AppDomain.CurrentDomain.DefineDynamicAssembly(
                assemblyName,
                AssemblyBuilderAccess.RunAndSave);

        var fileName = assemblyName.Name + ".dll";

        var moduleBuilder = assemblyBuilder.DefineDynamicModule(
            assemblyName.Name, 
            fileName);

        var modopt = moduleBuilder.DefineType(
            "OverloadedOnConstraints",
             TypeAttributes.Public).CreateType();

        var typeBuilder = moduleBuilder.DefineType(
            "MyType",
             TypeAttributes.Public);

        var foo1 = typeBuilder.DefineMethod("Foo", MethodAttributes.Public | MethodAttributes.Static);
        foo1.SetSignature(typeof(void), null, null, foo1.DefineGenericParameters("T"), null, null);
        foo1.DefineParameter(1, ParameterAttributes.None, "x");
        foo1.GetILGenerator().Emit(OpCodes.Ret);

        var foo2 = typeBuilder.DefineMethod("Foo", MethodAttributes.Public | MethodAttributes.Static);
        var t = foo2.DefineGenericParameters("T")[0];
        t.SetGenericParameterAttributes(GenericParameterAttributes.ReferenceTypeConstraint);
        foo2.SetSignature(typeof(void), null, new[] { modopt }, new[] { t }, null, null);
        foo2.DefineParameter(1, ParameterAttributes.None, "x");
        foo2.GetILGenerator().Emit(OpCodes.Ret);

        var myType = typeBuilder.CreateType();

        var methods = myType.GetMethods(BindingFlags.Public|BindingFlags.Static);
        foreach (var method in methods)
        {
            Console.WriteLine(method.ReturnParameter.GetOptionalCustomModifiers().FirstOrDefault());
        }

        assemblyBuilder.Save(fileName);
    }
}



Рефлектор:

public class MyType
{
    // Methods
    public static void Foo<T>(T x)
    {
    }

    public static void modopt(OverloadedOnConstraints) Foo<T>(T x) where T: class
    {
    }
}
Re[15]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 23:11
Оценка:
Здравствуйте, nikov, Вы писали:

N>Вот тебе прототип:


Гы. Я тупо удалил из твоего прототипа "new[] { modopt }" замени его на null и код все равно сгенерировал два метода, один с констрэйном, другой — нет.

Так что modopt не нужен. Похоже, что CLR позволяет размещать в классе и совершенно одинаковые "перегруженные" методы.

Вот модернезированный вариант:
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Linq;

class Program
{
    static void Main()
    {
        var assemblyName = new AssemblyName("modopt");
        var assemblyBuilder =
                AppDomain.CurrentDomain.DefineDynamicAssembly(
                        assemblyName,
                        AssemblyBuilderAccess.RunAndSave);

        var fileName = assemblyName.Name + ".dll";

        var moduleBuilder = assemblyBuilder.DefineDynamicModule(
                assemblyName.Name,
                fileName);

        var modopt = moduleBuilder.DefineType(
                "OverloadedOnConstraints",
                 TypeAttributes.Public).CreateType();

        var typeBuilder = moduleBuilder.DefineType(
                "MyType",
                 TypeAttributes.Public);

        var foo1 = typeBuilder.DefineMethod("Foo", MethodAttributes.Public | MethodAttributes.Static);
        var t1 = foo1.DefineGenericParameters("T")[0];
        t1.SetGenericParameterAttributes(GenericParameterAttributes.NotNullableValueTypeConstraint);
        foo1.SetSignature(typeof(void), null, null, new[] { t1 }, null, null);
        //foo1.SetSignature(typeof(void), null, null, foo1.DefineGenericParameters("T"), null, null);
        foo1.DefineParameter(1, ParameterAttributes.None, "x");
        foo1.GetILGenerator().Emit(OpCodes.Ret);

        var foo2 = typeBuilder.DefineMethod("Foo", MethodAttributes.Public | MethodAttributes.Static);
        var t2 = foo2.DefineGenericParameters("T")[0];
        t2.SetGenericParameterAttributes(GenericParameterAttributes.ReferenceTypeConstraint);
        foo2.SetSignature(typeof(void), null, null, new[] { t2 }, null, null);
        foo2.DefineParameter(1, ParameterAttributes.None, "x");
        foo2.GetILGenerator().Emit(OpCodes.Ret);

        var myType = typeBuilder.CreateType();

        var methods = myType.GetMethods(BindingFlags.Public | BindingFlags.Static);
        foreach (var method in methods)
        {
            Console.WriteLine(method.ReturnParameter.GetOptionalCustomModifiers().FirstOrDefault());
        }

        assemblyBuilder.Save(fileName);
    }
}


Реинжениринг Рефлектором:

public class MyType
{
    // Methods
    public static void Foo<T>(T x) where T: struct
    {
    }

    public static void Foo<T>(T x) where T: struct
    {
    }
}


Остается только один вопрос. Что по этому делу думает стандарт?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.01.10 23:20
Оценка:
Здравствуйте, VladD2, Вы писали:

Протестировал эту сборку в C# и Nemerle.

Результат таков. C# при компиляции говорит о неоднозначности.
Nemerle компилирует:
def i = 1;
def s = "a";

MyType.Foo(i);
MyType.Foo(s);

но при этом происходит связывание с одним и тем же методом, так что в рантайме вылетает исключение.

Пока еще не уверен, но если это ошибка в компиляторе Nemerle, то можно будет реализовать полноценную перегрузку по консрэйнам.

Может быть когда-нибудь и C# допилят так же.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.01.10 08:24
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Гы. Я тупо удалил из твоего прототипа "new[] { modopt }" замени его на null и код все равно сгенерировал два метода, один с констрэйном, другой — нет.


VD>Так что modopt не нужен.


Только твоя сборка не верифицируемая

Microsoft (R) .NET Framework PE Verifier. Version 4.0.21006.1
Copyright (c) Microsoft Corporation. All rights reserved.

[MD]: Error: Method has a duplicate, token=0x06000003. [token:0x06000002]
[MD]: Error: Method has a duplicate, token=0x06000002. [token:0x06000003]
2 Error(s) Verifying modopt.dll


И, я подозреваю, если сделать методы виртуальными, ты не сможешь написать для них override.
Re[17]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.01.10 13:42
Оценка:
Здравствуйте, nikov, Вы писали:

N>Только твоя сборка не верифицируемая


N>

N>Microsoft (R) .NET Framework PE Verifier. Version 4.0.21006.1
N>Copyright (c) Microsoft Corporation. All rights reserved.

N>[MD]: Error: Method has a duplicate, token=0x06000003. [token:0x06000002]
N>[MD]: Error: Method has a duplicate, token=0x06000002. [token:0x06000003]
N>2 Error(s) Verifying modopt.dll


Да, это я проверить забыл.

Ну, стало быть без modopt-ов никуда.


Ладно, будет время попробую прикрутить это дело к Nemerle.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.01.10 13:45
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ну, стало быть без modopt-ов никуда.

VD>Ладно, будет время попробую прикрутить это дело к Nemerle.

Думаю, надо будет поколдовать, чтобы по возможности один из оверлоадов (самый общий) был доступен из C#.
Re[19]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.01.10 15:54
Оценка:
Здравствуйте, nikov, Вы писали:

N>Думаю, надо будет поколдовать, чтобы по возможности один из оверлоадов (самый общий) был доступен из C#.


А как? Шарп тупо не делает между ними разницы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[20]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.01.10 16:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А как? Шарп тупо не делает между ними разницы.


Почему же? Он выбирает сигнатуру с наименьшим количеством modopt. Так что достаточно не лепить его на наиболее общий overload.
Re[21]: Nullable
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.01.10 16:18
Оценка:
Здравствуйте, nikov, Вы писали:

VD>>А как? Шарп тупо не делает между ними разницы.


N>Почему же? Он выбирает сигнатуру с наименьшим количеством modopt. Так что достаточно не лепить его на наиболее общий overload.


А, точно! Это я просто со своей сборкой где не было modopt эксперементировал.
Тогда остается только понять как выбирать метод к которому не лепить modopt. Можно конечно заставлять программиста это явно (например, атрибутом) указывать. Но как-то не красиво это.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[22]: Nullable
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.01.10 16:26
Оценка:
Здравствуйте, VladD2, Вы писали:

N>>Почему же? Он выбирает сигнатуру с наименьшим количеством modopt. Так что достаточно не лепить его на наиболее общий overload.


VD>А, точно! Это я просто со своей сборкой где не было modopt эксперементировал.

VD>Тогда остается только понять как выбирать метод к которому не лепить modopt. Можно конечно заставлять программиста это явно (например, атрибутом) указывать. Но как-то не красиво это.

Я бы предложил по умолчанию выбирать метод с самыми слабыми констрейнтами (или вообще без констрейнтов), если такой имеется. Если нет самых слабых (например, у одного class, а у другого struct, или констрейнты на разных типах-параметрах) — то по умолчанию помечать modopt-ами все методы, из C# нельзя будет вызвать ни один из них.

Можно еще предусмотреть атрибут (например DefaultOverload), который позволил бы программисту переопределить поведение по умолчанию.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.