Re[5]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 20.06.08 08:37
Оценка:
Здравствуйте, VladD2, Вы писали:

N>>Почему взять S с потолка — это лучше, чем развернуть params?


VD>На мой взгляд, этот пример работает наилучим образом. Если есть альтернативы без params, то нужно предпочитать их.


Почему? params не так уж и плох — он позволяет захватить строго типизированные аргументы, и обработать их специфичным для данного типа способом. Поэтому он должен рассматриваться как лучший вариант по сравнению с приведением к базовому типу. И хуже, только если есть метод, содержащий только фиксированные параметры с теми же типами (потому что это позволяет избежать создания массива), или хотя бы большее количество фиксированных параметров (потому что мы можем предположить, что параметры, различимые по имени, метод обрабатывает более специфичным образом).

VD>Единственный варос который у меня возникает: не надо ли здесь сообщять о неопределенности?

VD>Как, кстати, в подобном случае ведет себя C#?

Ну, в C# тип-параметр не выводится, если он не фигурирует в типах параметров метода. Поэтому первый вариант просто не будет участвовать в overload resolution. Если же убрать тип-параметр, то будет неоднозначность:

using System;

static class A
{
    static void Foo(IConvertible x){}
    static void Foo(params IComparable[] x){}
    static void Main()
    {
        Foo(1); // error CS0121: The call is ambiguous between the following methods or properties: 'A.Foo(System.IConvertible)' and 'A.Foo(params System.IComparable[])'
    }
}


потому что params в C# может быть средством разрешения неоднозначности только если раскрытые сигнатуры совпадают.
Re[5]: Просто любопытный эффект
От: WolfHound  
Дата: 20.06.08 11:15
Оценка:
Здравствуйте, VladD2, Вы писали:

N>>Почему взять S с потолка — это лучше, чем развернуть params?

VD>На мой взгляд, этот пример работает наилучим образом. Если есть альтернативы без params, то нужно предпочитать их.
А на мой взгляд тут явная бага ибо тип S неоткуда вывести.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Просто мысль
От: linker Россия  
Дата: 20.06.08 11:53
Оценка:
Здравствуйте, HotDog, Вы писали:

HD>... если бы твои этюды использовались в качестве теста при приеме на работу, то количество подходящих кандидатур стремилось бы к нулю

Их надо использовать если кандидат Вам крайне не симпотичен.
... << RSDN@Home 1.2.0 alpha rev. 789>>
Re[2]: Просто мысль
От: orangy Россия
Дата: 20.06.08 13:22
Оценка:
Здравствуйте, HotDog, Вы писали:

HD>... если бы твои этюды использовались в качестве теста при приеме на работу, то количество подходящих кандидатур стремилось бы к нулю

Что забавно, во многих случаях происходит именно так — интервьюирующий спрашивает подобного рода спецзнания, хорошо известные ему самому. Каюсь, сам грешен был, но всё же...
... << RSDN@Home 1.2.0 alpha rev. 655>>
"Develop with pleasure!"
Re[6]: Просто любопытный эффект
От: aloch Россия  
Дата: 20.06.08 15:48
Оценка:
Здравствуйте, VladD2, Вы писали:

VD> В С++ меняли и все пережили.


Не все. Боюсь в длинной перспективе сам C++ этого не переживет.


Re[7]: Просто любопытный эффект
От: vdimas Россия  
Дата: 20.06.08 17:35
Оценка:
Здравствуйте, nikov, Вы писали:

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


N>>>Очень трудно придумать правила, которые бы не имели парадоксальных последствий в граничных случаях.


VD>>Элементарное. При прочих равных выбирать метод без params. Это банальное правило позволило бы поднять производительность за счет выбора более специализированных функций.


N>А такое правило в C# есть. Это второе из tie-breaking rules, которые применяются при совпадении списка параметров (7.4.3.2 Better function member).

N>В исходном примере типы параметров различны, и действует более сильное правило. Правда, несколько парадоксальным образом.

Жаль, что не учитывается такой фактор, как "длина" цепочки преобразований, т.к. для приведения 1 к ulong? требуется на самом деле два преобразования. Без учёта этого фактора, как ты правильно заметил, потерялась транзитивность при попарном сравнении на лучшее преобразование. А раз вместо строгой иерархии преобразований имеем неупорядоченные локальные отношения "лучше/хуже", то привет грабли.
Re[6]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.06.08 22:43
Оценка:
Здравствуйте, WolfHound, Вы писали:

N>>>Почему взять S с потолка — это лучше, чем развернуть params?

VD>>На мой взгляд, этот пример работает наилучим образом. Если есть альтернативы без params, то нужно предпочитать их.
WH>А на мой взгляд тут явная бага ибо тип S неоткуда вывести.

А он похоже и не учитывается. Вот код метода отвечающего за выбор лучшей перегрузки (комментарии мои):

    GetBestOverloads (parms : list [OverloadPossibility]) : list [OverloadPossibility]
    {
      match (parms) {
        | [] | [_] => parms // если есть только одна перегрузка, то возвращаем ее и ничего не делаем.
        | _ =>
          def res = RemoveExtensionMethods (parms);      // Первым делом отбрасываем методы-расширения.
          def res = GetMinimal (res, IsBetterOverload);  // Далее выбираем "лучшую перегрузку" исходя из выведенных типов методов.

          def res = // отбрасываем params-методы (методы с переменным числом параметров) если в списке есть не params-методы.
            if (List.Exists (res, AintVarArgs)) 
              List.RevFilter (res, AintVarArgs)
            else res;
            
          def res = // повбывал бы за такие имена. В общем, что-то там отбрасывают...
            if (List.Exists (res, DidntMamboJumbo))
              List.RevFilter (res, DidntMamboJumbo)
            else res;
            
          def res = // отбрасываем джереник-методы если есть не дженерик-методы.
            if (List.Exists (res, AintGeneric))
              List.RevFilter (res, AintGeneric)
            else res;
            
          // Message.Debug ($"gbo: $parms ---> $res");

          res
      }
    }

Таким образом "Foo[S](_x : IConvertible) : void" выбирается исходя из правила отбрасывать params-методы если есть другие:
            if (List.Exists (res, AintVarArgs)) 
              List.RevFilter (res, AintVarArgs)
            else res;

Интересно, что по логике метода GetBestOverloads отбросит "Foo[S](_x : IConvertible) : void" и предпочтет скажем "Foo(_x : IComparable) : void" просто на основании, что первый вариант — это дженерик-метод.
В данном примере это конечно бессмысленно, но на практике от этого есть толк, так как просто так параметры типов никто в методы не пихает, и с большой вероятностью обобщенный метод будет более медленным.

ЗЫ

Кстати, правило предпочтения "Foo(_x : object) : void" вместо "Foo[T](_x : T) : void" основывается на том, что IsBetterOverload выводит T как object (ведь никаких доп-констрейнов нет), что приводит к тому, что после вызова "GetMinimal (res, IsBetterOverload)" в списке оказывается два метода, но обобщенный вариант отбрасывается в виду правила предпочтения не обобщенного варианта.

На мой взгляд нужно вставлять проверку которая пытается обработать ситуация "T vs. object" и предпочитать обобшенный вариант. Однако это легче сказать нежели сделать, ведь тип может быть вычислен до сравнения и сравниваться будут два object-а, что опять таки приведет к тому что в списке окажутся оба кандидата.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 02.07.08 11:16
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>На мой взгляд нужно вставлять проверку которая пытается обработать ситуация "T vs. object" и предпочитать обобшенный вариант. Однако это легче сказать нежели сделать, ведь тип может быть вычислен до сравнения и сравниваться будут два object-а, что опять таки приведет к тому что в списке окажутся оба кандидата.


Интересно, что в C# правила overload resolution могут учитывать и типы, полученные в результате подстановки типов-параметров, а при их совпадении — и исходные типы, указанные в декларации метода.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.