Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 10:32
Оценка: 5 (2)
using System;

class A
{
    static void Main()
    {
        Foo(1, 1);
    }

    static void Foo(long x, ulong y) { Console.WriteLine(1); }
    static void Foo(ulong? x, params long[] y) { Console.WriteLine(2); }
}
Re: Просто любопытный эффект
От: Димчанский Литва http://dimchansky.github.io/
Дата: 19.06.08 10:40
Оценка:
Только не 2!
Re[2]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 10:49
Оценка:
Здравствуйте, Димчанский, Вы писали:

Д>Только не 2!

Именно 2, и причем это так по стандарту.
Re[3]: Просто любопытный эффект
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 19.06.08 10:55
Оценка: 1 (1) +3 :)
Здравствуйте, nikov, Вы писали:

N>Именно 2, и причем это так по стандарту.


Честно говоря, увидев такие оверлоады в реальном production коде, рука потянется за чем-нибудь тяжелым и острым....
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[3]: Просто любопытный эффект
От: Димчанский Литва http://dimchansky.github.io/
Дата: 19.06.08 10:59
Оценка:
Здравствуйте, nikov, Вы писали:

N>Именно 2, и причем это так по стандарту.


Я именно так и думал.
А можно ознакомиться с пунктом стандарта?
Re[3]: Просто любопытный эффект
От: ARMSoft Украина  
Дата: 19.06.08 11:04
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Димчанский, Вы писали:


Д>>Только не 2!

N>Именно 2, и причем это так по стандарту.

Мдаа, легких путей МС не любит.
-------------------------
My professional profile
Re[3]: Просто любопытный эффект
От: Аноним  
Дата: 19.06.08 11:24
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Димчанский, Вы писали:


Д>>Только не 2!

N>Именно 2, и причем это так по стандарту.

странное дело... Чем обоснован выбор второй перегрузки, если первая наиболее специализированая?
Re[3]: Просто любопытный эффект
От: Аноним  
Дата: 19.06.08 11:55
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Димчанский, Вы писали:


Д>>Только не 2!

N>Именно 2, и причем это так по стандарту.

А в чём фишка? Объясните новичку? Это кстати на каком языке?
Re: Просто любопытный эффект
От: Аноним  
Дата: 19.06.08 12:08
Оценка:
Здравствуйте, nikov, Вы писали:

N>
N>using System;

N>class A
N>{
N>    static void Main()
N>    {
N>        Foo(1, 1);
N>    }

N>    static void Foo(long x, ulong y) { Console.WriteLine(1); }
N>    static void Foo(ulong? x, params long[] y) { Console.WriteLine(2); }
N>}
N>

Если убрать params выводится 1.
Re[2]: Просто любопытный эффект
От: Аноним  
Дата: 19.06.08 12:14
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Если убрать params выводится 1.

здесь
Re: Просто любопытный эффект
От: Andir Россия
Дата: 19.06.08 13:10
Оценка:
Здравствуйте, nikov, Вы писали:

Вторую перегрузку можно ещё заменить и просто на:
static void Foo(ulong? x, long y) { Console.WriteLine(2); }


Или фича не в этом?

С Уважением, Andir!
using( RSDN@Home 1.2.0 alpha 4 rev. 987 ) { /* Работаем */ }
Re[2]: Просто любопытный эффект
От: desco США http://v2matveev.blogspot.com
Дата: 19.06.08 13:18
Оценка:
Здравствуйте, Andir, Вы писали:

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


A>Вторую перегрузку можно ещё заменить и просто на:

A>
A>static void Foo(ulong? x, long y) { Console.WriteLine(2); }
A>


A>Или фича не в этом?


A>С Уважением, Andir!


в этом
при выборе перегрузки выбор идет по второму параметру, поскольку первый в обоих случаях подходит одинаково
... << RSDN@Home 1.2.0 alpha 4 rev. 1090>>
Re[4]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:29
Оценка: 42 (7)
Здравствуйте, Димчанский, Вы писали:

Д>А можно ознакомиться с пунктом стандарта?


Ну давайте проанализируем. Надо начинать с 7.5.5.1 Method invocations. Сначала строим множество применимых (applicable) методов. Применимость определяется согласно 7.4.3.1 Applicable function member. Ну, очевидно, оно будет состоять из двух методов Foo, причем второй метод будет применим только в expanded form, то есть как будто он имеет сигнатуру Foo(ulong? x, long y). Далее множество урезается только до методов из наиболее производных классов (для нас это не дает никакого эффекта, так как оба метода определены в одном классе). Теперь наступает самое интересное — нам нужно выделить лучший (best) метод согласно 7.4.3 Overload resolution. Лучший метод — это метод, который лучше, чем все остальные методы в построенном множестве, по отношению к данному списку аргументов. То есть надо сравнить все методы попарно (в данном случае только два метода). Чтобы узнать, какой из двух методов лучше, надо воспользоваться 7.4.3.2 Better function member. Если есть два метода A и B, то возможны три исхода: метод A лучше, метод B лучше, ни один метод не лучше.

Чтобы метод A был лучше метода B надо:

* чтобы хотя бы для одного аргумента неявное преобразование от этого аргумента к типу соответствующего параметра метода A было лучше, чем неявное преобразование от этого же аргумента к типу соответствующего параметра метода B
И
* ни для одного аргумента неявное преобразование от этого аргумента к типу соответствующего параметра метода B не было бы лучше, чем неявное преобразование от этого же аргумента к типу соответствующего параметра метода A.

ИЛИ

* типы соответствующих параметров методов A и B были одинаковы
И
* tie-breaking rules выбирали бы метод A.


Впрочем, второй блок условий нам не понадобится. Таким образом, нам надо ответить на два вопроса:
1) Какое из неявных преобразований: 1 -> long, 1 -> Nullable<ulong> лучше?
2) Какое из неявных преобразований: 1 -> ulong, 1 -> long лучше?

Так как 1 — это выражение, имеющие тип int, то согласно 7.4.3.3 Better conversion from expression, нам надо ответить на следующие вопросы:
1) Какое из преобразований: int -> long, int -> Nullable<ulong> лучше?
2) Какое из преобразований: int -> ulong, int -> long лучше?

Заметьте исчезновение слова "неявных". Теперь мы смотрим на 7.4.3.4 Better conversion from type. Если у нас есть преобразование от типа C к типу A, и преобразование от типа C к типу B, то первое преобразование считается лучшим, если типы A и B различны и выполняется хотя бы одно из следующих условий:
* Тип C совпадает с типом A.
* Существует неявное преобразование от типа A к типу B, но не существует неявного преобразовани от типа B к типу A.
* A — целочисленный тип со знаком, а B — целочисленный тип без знака, но не существует неявного преобразования от типа B к типу A (Ключевой момент: здесь ничего не говорится о nullable типах, сконструированных из целочисленных типов без знака).

Таким образом мы получаем следующие ответы на наши вопросы:
1) Ни одно из преобразований не лучше.
2) Преобразовани int -> long лучше, чем преобразование int -> ulong (согласно третьему пункту).

Таким образом, получается что метод Foo(ulong? x, params long[] y) лучше.

Парадокс состоит еще в том, что если бы мы попарно сравнивали 3 преобразования:
1) int -> long
2) int -> ulong
3) int -> ulong?
то первое преобразование было бы лучше второго, а второе — лучше третьего. Тем не менее, как мы уже убедилсь, первое преобразование оказывается не лучше чем третье. То есть отношение "лучше чем" оказывается не транзитивным.
Re[4]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:31
Оценка:
Здравствуйте, xvost, Вы писали:

X>Честно говоря, увидев такие оверлоады в реальном production коде, рука потянется за чем-нибудь тяжелым и острым....

Тем не менее, РеШарпер всегда справлялся с этим примером нормально.
Re[4]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:34
Оценка:
Здравствуйте, Аноним, Вы писали:

А>странное дело... Чем обоснован выбор второй перегрузки, если первая наиболее специализированая?


А нет такого понятия, как более специализированный метод. Есть понятие лучшего метода. В данном случае второй оказывается
Автор: nikov
Дата: 19.06.08
лучшим по отношению к этому списку аргументов.
Re[4]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А в чём фишка? Объясните новичку?

здесь
Автор: nikov
Дата: 19.06.08


А>Это кстати на каком языке?

C#
Re[4]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:38
Оценка:
Здравствуйте, ARMSoft, Вы писали:

ARM>Мдаа, легких путей МС не любит.


А какой путь был бы легким в данном случае?
Очень трудно придумать правила, которые бы не имели парадоксальных последствий в граничных случаях.
Re[2]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Если убрать params выводится 1.


Тогда уж и [] убирай.
Re[5]: Просто любопытный эффект
От: Димчанский Литва http://dimchansky.github.io/
Дата: 19.06.08 13:48
Оценка:
Здравствуйте, nikov, Вы писали:

N>А какой путь был бы легким в данном случае?

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

А если отказаться от неявных преобразований?
Re[6]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 13:52
Оценка:
Здравствуйте, Димчанский, Вы писали:

Д>А если отказаться от неявных преобразований?


Тогда получим путь F#. В нем неявные преобразования сведены до минимума.
Re[7]: Просто любопытный эффект
От: Димчанский Литва http://dimchansky.github.io/
Дата: 19.06.08 13:58
Оценка:
Здравствуйте, nikov, Вы писали:

N>Тогда получим путь F#. В нем неявные преобразования сведены до минимума.


Да, мне это в F# тоже в частности понравилось. Так же как и неизменность объектов (ну если не говорить про умышленные ref, mutable).
Но F# еще не готовый блин, хотя и уже вкусный.
Re[5]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.08 14:08
Оценка:
Здравствуйте, nikov, Вы писали:

N>А какой путь был бы легким в данном случае?

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

Элементарное. При прочих равных выбирать метод без params. Это банальное правило позволило бы поднять производительность за счет выбора более специализированных функций.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.08 14:13
Оценка:
Здравствуйте, nikov, Вы писали:

using System.Console;

module Program
{
  Main() : void
  {
    Foo(1, 1);
    _ = ReadLine();
  }

  Foo(_ : long, _ : ulong) : void { WriteLine(1) }
  Foo(_ : ulong?, params _ : array[long]) : void { WriteLine(2) }
}


Как думаешь, что выведет этот код?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 14:14
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Как думаешь, что выведет этот код?


А теперь покажи мне спецификацию, которая это объясняет.
Re[6]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 14:17
Оценка:
Здравствуйте, VladD2, Вы писали:

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


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


А такое правило в C# есть. Это второе из tie-breaking rules, которые применяются при совпадении списка параметров (7.4.3.2 Better function member).
В исходном примере типы параметров различны, и действует более сильное правило. Правда, несколько парадоксальным образом.
Re[3]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.08 14:28
Оценка:
Здравствуйте, nikov, Вы писали:

N>А теперь покажи мне спецификацию, которая это объясняет.


Ну, то есть тебе шашечки, а не ехать?
С С++ тоже было все очень похоже. Спрашиваешь у людей "почему из виртуального деструктора не вызываются методы переопределенные в потомках?", а тебе отвечают "по спецификации!". "Но ведь это же неинтуитивно!" — говорю я — "А нам по фигу" — говорят они.

Вот как бы с Шарпом так же не стало. Он конечно несравнимо более интуитивен, но вот вместо того чтобы выявлять проблемы и устранять их (или хотя бы обращать внимание разработчиков и общественности) ты радостно объясняешь всем, что мол, так оно и надо.

А я вот не считаю, что так оно надо. Надо так как удобнее (если конечно это не вызывает других проблем).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.08 14:31
Оценка:
Здравствуйте, nikov, Вы писали:

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

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

Значит правила надо местами переставить. Стандарт вообще штука недетерминированная. Его ведь по разному можно интерпретировать. Я бы вот счел приведение константы к long и ulong неразличимым и применил бы правило для params.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.08 14:33
Оценка:
А вообще, характерно, то что большинство найденных тобой странностей C# не обнаруживается в Немерле. Это говорит о том, что алгоритмы в нем по разумнее. В прочем немерловый компилятор и думает существенно дольше.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 14:45
Оценка: 35 (1)
Здравствуйте, VladD2, Вы писали:

VD>Вот как бы с Шарпом так же не стало. Он конечно несравнимо более интуитивен, но вот вместо того чтобы выявлять проблемы и устранять их (или хотя бы обращать внимание разработчиков и общественности) ты радостно объясняешь всем, что мол, так оно и надо.


Поздно, Влад, уже что-то менять в этой части C#. Поломается обратная совместимось. Можно только сообщать людям, где есть подводные камни, чтобы они их избегали. Ну и чтобы разработчики новых языков могли учесть это. Собственно, я это и делаю (сообщаю).
Re[5]: Просто любопытный эффект
От: Димчанский Литва http://dimchansky.github.io/
Дата: 19.06.08 14:54
Оценка:
Здравствуйте, nikov, Вы писали:

N>Поздно, Влад, уже что-то менять в этой части C#. Поломается обратная совместимось. Можно только сообщать людям, где есть подводные камни, чтобы они их избегали. Ну и чтобы разработчики новых языков могли учесть это. Собственно, я это и делаю (сообщаю).


"Мотороллер не мой, я просто разместил объяву."

P.S.:
Прошу простить меня за шутку, конец дня, мозги ни на что больше не способны.
Re[5]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.08 15:00
Оценка: +1
Здравствуйте, nikov, Вы писали:

N>Поздно, Влад, уже что-то менять в этой части C#. Поломается обратная совместимось. Можно только сообщать людям, где есть подводные камни, чтобы они их избегали. Ну и чтобы разработчики новых языков могли учесть это. Собственно, я это и делаю (сообщаю).


C# не Святой Грааль. В С++ меняли и все пережили. Схема может быть проста как три копейки — в следующей верссии вводятся предупреждения, а в следующей за ней меняется код.

На самом деле проблем это особых не создаст, так как, как правильно заметил Хвост, за такой код надо чем-то тяжелым и острым... Другими словами подобный код большая редкость и напорются на несоответствие единицы. Зато миллионам будет жить проще.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 15:02
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А вообще, характерно, то что большинство найденных тобой странностей C# не обнаруживается в Немерле. Это говорит о том, что алгоритмы в нем по разумнее.

Оно может быть и так. Но я уверен, что если поставить цель эти алгоритмы документировать и потом протестировать реализацию на соответствие этой документации (на уровне объема тестирования C#), то это будет стоить неимоверную кучу бабла. И еще ошибки найдутся.
Re[2]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 15:18
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Как думаешь, что выведет этот код?


Посмотрел еще пару примеров на Nemerle. Очень неочевидное поведение.


#pragma indent
using System.Console;

module A
  Foo[T](_x : T) : void
    WriteLine(1);

  Foo(_x : object) : void
    WriteLine(2);

  Main() : void
    Foo(1); // вызывается Foo(_x : object)
    _ = ReadKey()


Пример можно усугубить еще так:

#pragma indent
using System.Console;
module A
  Foo[T](x : T) : void
    WriteLine(1);
    Foo(x); // вызывается Foo(_x : object)

  Foo(_x : object) : void
    WriteLine(2);

  Main() : void
    Foo.[int](1);
    _ = ReadKey()


И главное непонятно: то ли это баг в реализации, то ли косяк проектировщика. Спросить не с кого.
Re: Просто мысль
От: HotDog Швейцария www.denebspace.com
Дата: 19.06.08 15:25
Оценка:
... если бы твои этюды использовались в качестве теста при приеме на работу, то количество подходящих кандидатур стремилось бы к нулю
Re[3]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 15:46
Оценка:
Здравствуйте, nikov, Вы писали:

N>Посмотрел еще пару примеров на Nemerle. Очень неочевидное поведение.


Вот еще:

#pragma indent
using System;
using System.Console;

module A
  Foo[S](_x : IConvertible) : void // Вызывается этот метод
    WriteLine(1);

  Foo(params _x : array[IComparable]) : void
    WriteLine(2);

  Main() : void
    Foo(1);
    _ = ReadKey()


Почему взять S с потолка — это лучше, чем развернуть params?
Re[2]: Просто любопытный эффект
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 15:56
Оценка:
Здравствуйте, VladD2, Вы писали:

#pragma indent
using System;
using System.Console;

module A
  Foo[T](_ : T) : void where T : struct
    WriteLine(1);

  Foo(params _ : array[object]) : void
    WriteLine(2);

  Main() : void
    Foo(1); // Error: the type 'System.Object' must be a value type in order to use it as type parameter 'T' in method A.Foo(_N_u1710 : T.922) : void
    _ = ReadKey()


А это что за мистическая ошибка?
Re[4]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.06.08 07:58
Оценка:
Здравствуйте, nikov, Вы писали:

N>
N>#pragma indent
N>using System;
N>using System.Console;

N>module A
N>  Foo[S](_x : IConvertible) : void // Вызывается этот метод
N>    WriteLine(1);

N>  Foo(params _x : array[IComparable]) : void
N>    WriteLine(2);

N>  Main() : void
N>    Foo(1);
N>    _ = ReadKey()
N>


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


На мой взгляд, этот пример работает наилучим образом. Если есть альтернативы без params, то нужно предпочитать их.
Единственный варос который у меня возникает: не надо ли здесь сообщять о неопределенности?
Как, кстати, в подобном случае ведет себя C#?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.06.08 08:07
Оценка:
Здравствуйте, nikov, Вы писали:

N>Посмотрел еще пару примеров на Nemerle. Очень неочевидное поведение.


N>
N>  Foo[T](_x : T) : void
N>  Foo(_x : object) : void
...
N>    Foo(1); // вызывается Foo(_x : object)
N>


С точки зрения алгоритма вывода типов — это обычное поведение. object в Немереле считается самым базовым типом для всех типов. Параметр типов без ограничений также выводится как object (как и любая другая переменная типа, есть такое понятие в компиляторе).
Другой вопрос насколько удобен именно выбор object-а? Ведь в данном случае можно просто сообщить о неоднозначности.
Однако пример может быть и несколько другой:
  Foo[T](_x : T) : void
  Foo(_x : ulong) : void
...
    Foo(1); // вызывается Foo(_x : object)

В нем выбор специализированного параметра будет 100%-но предпочтительнее. Возможно выбор объекта тоже основывается на предпочтении "более специализированного" типа, что в данном случае подводит.

N>И главное непонятно: то ли это баг в реализации, то ли косяк проектировщика. Спросить не с кого.


Можно спросить у Камила и Михаля. Они ведь не умерли. Но важнее не это, а то "какое поведение будет лучше?". Ведь цель не найти ответственного за проблемы, а минимизировать их количество.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Просто любопытный эффект
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.06.08 08:08
Оценка:
Здравствуйте, nikov, Вы писали:

N>
N>#pragma indent
N>using System;
N>using System.Console;

N>module A
N>  Foo[T](_ : T) : void where T : struct
N>    WriteLine(1);

N>  Foo(params _ : array[object]) : void
N>    WriteLine(2);

N>  Main() : void
N>    Foo(1); // Error: the type 'System.Object' must be a value type in order to use it as type parameter 'T' in method A.Foo(_N_u1710 : T.922) : void
N>    _ = ReadKey()
N>


N>А это что за мистическая ошибка?


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

VD>Параметр типов без ограничений также выводится как object (как и любая другая переменная типа, есть такое понятие в компиляторе).


С чего бы вдруг? Это же тип-параметр метода, он должен выводиться из аргументов при вызове. Иначе, зачем вообще нужны типы-параметры без ограничений?
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...
Пока на собственное сообщение не было ответов, его можно удалить.