Разрешение перегрузки.
От: WolfHound  
Дата: 28.04.10 14:22
Оценка:
По следам этой
Автор: WolfHound
Дата: 28.04.10
темы.

class A {}
class B : A {}
module Program
{
  public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]
  {
    foreach (item in e1)
      yield item;
    foreach (item in e2)
      yield item;
  }

  public Cat[T, U](this e1 : IEnumerable[T], e2 : IEnumerable[U]) : IEnumerable[U]
    where T : U
  {
    foreach (item in e1)
      yield item : U;
    foreach (item in e2)
      yield item;
  }

  public Cat[T, U](this e1 : IEnumerable[U], e2 : IEnumerable[T]) : IEnumerable[U]
    where T : U
  {
    foreach (item in e1)
      yield item;
    foreach (item in e2)
      yield item : U;
  }

  Main() : void
  {
    def a = [A(), A(), A()] : IEnumerable[A];
    def b = [B(), B(), B(), B()] : IEnumerable[B];
    _ = a.Cat(b);//Вызов метода номер 3
    _ = b.Cat(a);//Вызов метода номер 2
    _ = a.Cat(a);//Ошибка. Поздходят все три метода.
  }
}

Можно ли изменять правила разрешения перегрузки чтобы был выбран первый метод?
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Разрешение перегрузки.
От: Аноним  
Дата: 28.04.10 17:46
Оценка:
А нужно ли?
Re: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.04.10 18:52
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>По следам этой
Автор: WolfHound
Дата: 28.04.10
темы.


WH>
WH>  public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]
WH>  public Cat[T, U](this e1 : IEnumerable[T], e2 : IEnumerable[U]) : IEnumerable[U]
WH>  public Cat[T, U](this e1 : IEnumerable[U], e2 : IEnumerable[T]) : IEnumerable[U]
WH>

WH>Можно ли изменять правила разрешения перегрузки чтобы был выбран первый метод?

Это перегрузка по констрэйнма. Ее потенциально можно реализовать, только вот SRE не позвляет задать методв по констрэйну. Точнее это вообще невозможно, но в дотнет поддерижваются специальнае метаданные позволяющие отличать методы. Так вот SRE их спользование недопускает.

Такую фичу можно сделать если портировать немерле на CCI. Но это само по себе не мало работы. Хотя портирвоать однозначно надо. Это решит много проблем.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Разрешение перегрузки.
От: WolfHound  
Дата: 28.04.10 19:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это перегрузка по констрэйнма. Ее потенциально можно реализовать, только вот SRE не позвляет задать методв по констрэйну. Точнее это вообще невозможно, но в дотнет поддерижваются специальнае метаданные позволяющие отличать методы. Так вот SRE их спользование недопускает.

Может я что-то не понимаю но вот этот код работает:
    def a = [A(), A(), A()] : IEnumerable[A];
    def b = [B(), B(), B(), B()] : IEnumerable[B];
    def c = [C(), C(), C(), C(), C()] : IEnumerable[C];
    def x = b.Cat(a).Cat(c);
    WriteLine($"..$x");

Выведет:
B, B, B, B, A, A, A, C, C, C, C, C

Проблемы начинаются когда подсовываешь одинаковые типы.
На код b.Cat(b) компилятор говорит:

Main.n(118,5):Error: typing fails on ambiguity between overloads:
Main.n(118,5):Warning: hint: Posible overload: method Program.Cat(e1 : System.Collections.Generic.IEnumerable[T], e2 : System.Collections.Generic.IEnumerable[T]) : System.Collections.Generic.IEnumerable[T]
Main.n(86,3):Warning: hint: overload defination
Main.n(118,5):Warning: hint: Posible overload: method Program.Cat(e1 : System.Collections.Generic.IEnumerable[T], e2 : System.Collections.Generic.IEnumerable[U]) : System.Collections.Generic.IEnumerable[U]
Main.n(94,3):Warning: hint: overload defination
Main.n(118,5):Warning: hint: Posible overload: method Program.Cat(e1 : System.Collections.Generic.IEnumerable[U], e2 : System.Collections.Generic.IEnumerable[T]) : System.Collections.Generic.IEnumerable[U]
Main.n(103,3):Warning: hint: overload defination

Он не может выбрать из трех методов один ибо они все формально подходят для перегрузки.
Но первый метод ИМХО более специализирован чем два других.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.04.10 19:39
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Может я что-то не понимаю но вот этот код работает:

WH>
WH>    def a = [A(), A(), A()] : IEnumerable[A];
WH>    def b = [B(), B(), B(), B()] : IEnumerable[B];
WH>    def c = [C(), C(), C(), C(), C()] : IEnumerable[C];
WH>    def x = b.Cat(a).Cat(c);
WH>    WriteLine($"..$x");
WH>


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

Но в случае одинаковых параметров действительно не ясно какой предпочесть.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.04.10 20:02
Оценка:
Короче поздно уже. Может завтра посморю.

ЗЫ

Откровенно говоря не вижу зачем такая фиогя нужна на практике. А время и так есть на что тратить.

ЗЗЫ

Ты бы тоже лучше доделал бы генерацию ДКА для терминальных символов в PEG-парсере. А то уже месяц прошел, а воз и ныне там.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Разрешение перегрузки.
От: WolfHound  
Дата: 28.04.10 20:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>По идее не должен был даже скомпилироваться. Немерл я докрутил для поддержки перегрузки по констрэйнам, а вот SRE должно генерировать фигню. Возможно все же тут имеет дело перегрузка по параметрам типов.

Так оно и есть.
Если у одного из методов поменять метами T и U
Cat[U, T](...)
То компилироваться перестанет.

VD>Но в случае одинаковых параметров действительно не ясно какой предпочесть.

Хотелось бы вот этот
public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]

Ибо у нас тут точное совпадение типов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Разрешение перегрузки.
От: Воронков Василий Россия  
Дата: 28.04.10 20:10
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Но в случае одинаковых параметров действительно не ясно какой предпочесть.

WH>Хотелось бы вот этот
WH>
WH>public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]
WH>

WH>Ибо у нас тут точное совпадение типов.

Честно говоря, это начинает подозрительно напоминать игру компилятора в "угадайки".
ИМХО не стоит такие вещи делать, если нет желания превратить в Немерле в Вижуал Бейсик.
Re[5]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.04.10 20:28
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Хотелось бы вот этот

WH>
WH>public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]
WH>

WH>Ибо у нас тут точное совпадение типов.

Эх. Пора тебе в дебри вывода типов погрузиться .

Могу показать откуда копать...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.04.10 20:28
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Эх. Пора тебе в дебри вывода типов погрузиться .


VD>Могу показать откуда копать...


Там давно все переписать нужно...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Разрешение перегрузки.
От: Аноним  
Дата: 29.04.10 15:16
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Честно говоря, это начинает подозрительно напоминать игру компилятора в "угадайки".

ВВ>ИМХО не стоит такие вещи делать, если нет желания превратить в Немерле в Вижуал Бейсик.

На VB-то не наезжайте Там алгоритмы перегрузки такие же как в C#.
Re[7]: Разрешение перегрузки.
От: Воронков Василий Россия  
Дата: 29.04.10 15:24
Оценка:
Здравствуйте, Аноним, Вы писали:

ВВ>>Честно говоря, это начинает подозрительно напоминать игру компилятора в "угадайки".

ВВ>>ИМХО не стоит такие вещи делать, если нет желания превратить в Немерле в Вижуал Бейсик.
А>На VB-то не наезжайте Там алгоритмы перегрузки такие же как в C#.

Это просто абсолютная неправда. Алгоритмы перегрузки в VB.NET и C# разные. И отличий там до фига. Взять хотя бы то, что VB учитывает виртуальные функции как first class кандидаты и поддерживает hide by name. Причем многие отличия как раз и сводятся к тому, что C# выдает ошибку при неоднозначности, а VB пытается угадать.

Как там вообще даже теоретически может быть одинаковый overloading, если в VB всегда были optional параметры, а в шарпе только что появились?
Re[7]: Разрешение перегрузки.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 06.05.10 13:23
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>На VB-то не наезжайте Там алгоритмы перегрузки такие же как в C#.


Немного похожие, но не такие же. Я бы сказал, что общей является только идея "выбираем то, что лучше подходит". Считается, что VB.NET чаще пытается "угадать" в случае неоднозначности.

Да и в C# правила для overload resolution не всегда интуитивно понятные.
Re[4]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.05.10 13:35
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Откровенно говоря не вижу зачем такая фиогя нужна на практике. А время и так есть на что тратить.


В четвертом дотнете все и так бедет работатть благодоря тому, что IEnumerable[T] будет ковариантным.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.05.10 13:53
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Хотелось бы вот этот

WH>
WH>public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]
WH>

WH>Ибо у нас тут точное совпадение типов.

В общем, я этим заниматься не буду. Есть у нас и другие дела.

Могу сказать куда копать.

Код ответственный за выбор лучшего варианта перегрузки находится строке 266 файла Typer-OverloadSelection.n (базовая часть):

GetBestOverloads (parms : list [OverloadPossibility]) : list [OverloadPossibility]
{
  match (parms) {
    | [] | [_] => parms
    | _ =>
      def res1 = RemoveExtensionMethods(parms);
      def res2 = GetMinimal(res1, IsBetterOverload);
      def res3 = res2.FilterIfExists(AintVarArgs);
      def res4 = res3.FilterIfExists(DidntMamboJumbo);
      def res5 = res4.FilterIfExists(AintGeneric);
        
      // Message.Debug ($"gbo: $parms ---> $res5");

      res5
  }
}

и в строке 139 (конкретное сравнение перегрузок):
    IsBetterOverload (o1 : OverloadPossibility, o2 : OverloadPossibility) : bool
    {
      def f1 = o1.FormalTypes;
      def f2 = o2.FormalTypes;
      // Message.Debug($"$o1==$(NList.FromArray(f1)) != $o2==$(NList.FromArray(f2))");

      System.Diagnostics.Debug.Assert(f1 != null && f2 != null);
      System.Diagnostics.Debug.Assert(f1.Length == f2.Length);
      Util.cassert (f1 != null && f2 != null);
      Util.cassert (f1.Length == f2.Length, 
                    $"$o1==$(NList.FromArray(f1)) != $o2==$(NList.FromArray(f2))");
                    
      def getBetterList(f1, f2)
      {
        Manager.Solver.PushState ();
        try 
        {
          def tyCmps = f1.Map2ToArray(f2, (t1, t2) => IsBetterType(t1, t2));
          tyCmps
        }
        finally { Manager.Solver.PopState() }
      }
      
      def tyCmpsForward  = getBetterList(f1, f2);
      def tyCmpsBackward = getBetterList(f2, f1);
      def tyCmpPairs = tyCmpsForward.ZipToArray(tyCmpsBackward);
      
      // exclude identical pairs (for example (true, true) or (false, false))
      // The (true, true) pair cause in case (object * object)
      // The (false, false) pair cause if type not comparable
      def differPairs = tyCmpPairs.FilterToArray(_ != _);
      
      def isBetterOverload = differPairs.Exists((p1, _) => p1) && !differPairs.Exists((_, p2) => p2);
      
      // Message.Debug($"X $o1==$(NList.FromArray(f1)) != $o2==$(NList.FromArray(f2))");
      //Message.Debug ($"cmp:$o1,$o2 $(f1.Length) ==> $res");
      isBetterOverload
    }

53 (вот это надо к черту переписывать!)
IsBetterType (t1 : TypeVar, t2 : TypeVar) : bool
{
  def real_check (t1, t2) 
  {
    mutable we_dont_care = null;

    SubtypingOrImplicitConv (t1, t2, out we_dont_care) 
      || (t1.IsFixed && t2.IsFixed 
          && match (t1.FixedValue) 
             {
               // treat all parametric types (including arrays) as covariant
               | FixedType.Class (tc1, _ :: _ as a1) =>
                 match (t2.FixedValue) 
                 {
                   | FixedType.Class (tc2, a2) when tc1.Equals (tc2) =>
                     NList.ForAll2 (a1, a2, IsBetterType)
                   | _ => false
                 }

               | FixedType.Array (a1, r1) =>
                 match (t2.FixedValue) 
                 {
                   | FixedType.Array (a2, r2) when r1 == r2 =>
                     IsBetterType (a1, a2)
                   | _ => false
                 }

               | _ => false
             })
  }


  def both_fixed = t1.IsFixed && t2.IsFixed;
  mutable tc1 = null;
  mutable tc2 = null;

  when (both_fixed)
    match (t1.FixedValue) 
    {
      | FixedType.Class (tc, []) => 
        tc1 = tc;
        match (t2.FixedValue) 
        {
          | FixedType.Class (tc, []) =>
            tc2 = tc;
          | _ => {}
        }
      | _ => {}
    }

  def res =
    if (tc2 == null) 
    {
      // cannot use cache
      real_check (t1, t2)
    }
    else
    {
      def ids = (tc1, tc2);
      def better_type_cache = Manager.Typer_BetterTypeCache;
      mutable result;

      unless (better_type_cache.TryGetValue(ids, out result))
      {
        result = 
          if (tc1.IsNumeric && tc2.IsNumeric)
          {
            if (tc1.IsFloating != tc2.IsFloating)
              tc2.IsFloating
            else
              tc1.Size < tc2.Size 
              || tc1.Size == tc2.Size && tc1.Unsigned != tc2.Unsigned && tc2.Unsigned
          }
          else
            real_check(t1, t2);

        better_type_cache.Add(ids, result);
      }
        
      result
    }
  //Message.Debug ($"better($t1,$t2)=$res");
  res
}



Можешь попробовать покопаться. Только если вдруг что-то будешь править, не забудь прогнать все тесты и скомпилировать компилятор в многостадийном режиме (короче, прогнать DevBuildForCommit.cmd), потому как сломать что-то там можно за проста.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.05.10 13:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Можешь попробовать покопаться.


Только учти, что все это потеряет смысл с перходом на 4-ый фрймворк, так как там будет ковариантность для для IEnumerable, так что все заработает само собой.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Новая фича (надеюсь, последняя) - макрос Resource
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.05.10 22:28
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Хотелось бы вот этот

WH>
WH>public Cat[T](this e1 : IEnumerable[T], e2 : IEnumerable[T]) : IEnumerable[T]
WH>

WH>Ибо у нас тут точное совпадение типов.

Совподение там есть везде. Иначе бы небыло бы конфликта.

Для решения данной проблемы можно добавить эвристику — побеждает метод с наименьшим числом параметров типов. Но не факт, что это не вызовет проблем.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Разрешение перегрузки.
От: catbert  
Дата: 15.05.10 08:09
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>[c#]

VD>GetBestOverloads (parms : list [OverloadPossibility]) : list [OverloadPossibility]
VD>{
VD> match (parms) {
VD> | [] | [_] => parms
VD> | _ =>
VD> def res1 = RemoveExtensionMethods(parms);
VD> def res2 = GetMinimal(res1, IsBetterOverload);
VD> def res3 = res2.FilterIfExists(AintVarArgs);
VD> def res4 = res3.FilterIfExists(DidntMamboJumbo);
VD> def res5 = res4.FilterIfExists(AintGeneric);

VD> // Message.Debug ($"gbo: $parms ---> $res5");


VD> res5

VD> }
VD>}

DidntMamboJumbo улыбнуло
Re[7]: Разрешение перегрузки.
От: nikov США http://www.linkedin.com/in/nikov
Дата: 15.05.10 12:40
Оценка:
Здравствуйте, catbert, Вы писали:

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

C>DidntMamboJumbo улыбнуло

здесь
Автор: VladD2
Дата: 01.07.08
Re[7]: Разрешение перегрузки.
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.05.10 13:27
Оценка:
Здравствуйте, catbert, Вы писали:

C>DidntMamboJumbo улыбнуло


Тут скорее плакать нужно. Давать столь дурацкие имена функциям просто неприемлемо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.