[Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 23.09.06 13:51
Оценка:
Не так давно IT в Nemerle'овской рассылке спрашивал про оператор ??, который есть в Шарпе и напрочь отсутствует в Nemerle. Ну я и решлил для расзимнки написать его макросом. Оказалось не все так просто
Сперва, приведу соответствующий кусок C# спецификации:

14.12 The null coalescing operator
The ?? operator is called the null coalescing operator.
null-coalescing-expression:
conditional-or-expression
conditional-or-expression ?? null-coalescing-expression
A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. If a is
non-null, the result of a ?? b is a; otherwise, the result is b. The operation evaluates b only if a is null.
The null coalescing operator is right-associative, meaning that operations are grouped from right to left.
[Example: An expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). In general terms, an
expression of the form E1 ?? E2 ?? ... ?? EN returns the first of the operands that is non-null, or null if all
operands are null. end example]
The type of the expression a ?? b depends on which implicit conversions are available between the types
of the operands. In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a, B is the
type of b, and A0 is the type that results from removing the trailing ? modifier, if any, from A. Specifically,
a ?? b is processed as follows:
• If A is not a nullable type or a reference type, a compile-time error occurs.
• If A is a nullable type and an implicit conversion exists from b to A0, the result type is A0. At run-time, a
is first evaluated. If a is not null, a is unwrapped to type A0, and this becomes the result. Otherwise, b is
evaluated and converted to type A0, and this becomes the result.
• Otherwise, if an implicit conversion exists from b to A, the result type is A. At run-time, a is first
evaluated. If a is not null, a becomes the result. Otherwise, b is evaluated and converted to type A, and
this becomes the result.
• Otherwise, if an implicit conversion exists from A0 to B, the result type is B. At run-time, a is first
evaluated. If a is not null, a is unwrapped to type A0 (unless A and A0 are the same type) and converted
to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.
Otherwise, a and b are incompatible, and a compile-time error occurs.


Решил делать все по уму, а именно стараться неприкоснительно следовать спецификации. Итак, вот такой вот макрос получился:

using System.Console;

using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Text;

namespace Iae.Macro
{
  /** This module is used to simplify work with op_Implicit operator.

      This module is stateless.
   */
  module OpImplicitHelper
  {
    /**
     * Used to print all implicit operators of some type
     */
    public PrintAll(cl : MType.Class) : void
    {
      def members = cl.tycon.LookupMember("op_Implicit");
      foreach (m is IMethod in members)
        WriteLine(m);
    }

    /**
     * Used to determine has a `from' type implicit conversation 
     * to a `to' type or hasn't.
     */
    public HasImplicit(from : MType.Class, to : MType.Class) : bool
    {
      def members = to.tycon.LookupMember("op_Implicit") 
                    + from.tycon.LookupMember("op_Implicit");
      ret : 
      {
        foreach (m is IMethod in members)
        {
          def tyRet = m.ReturnType;
          def tyPar = m.GetParameters().Head.ty;
          when (tyRet.Equals(to) && tyPar.Equals(from))
            ret (true);
        }  
        false;
      }
    }
  }

  macro @printImplicit(expr)
  {
    def typer = Macros.ImplicitCTX ();
    def tx = typer.TypeExpr (expr);
    match (tx.Type.Hint) 
    {
      | Some (Class (_ti, _args) as cl) => 
          OpImplicitHelper.PrintAll(cl);
          <[]>
      | _ => 
          Message.FatalError ("PrintImplicit macro can not be used with such expression.");
    }
  }

  macro @test(expr)
  {
    <[ if ($expr != null) $expr.Value; else (CI () : int) ]>
  }

  macro @?? (exprA, exprB)
  {
    def typer = Macros.ImplicitCTX ();
    def tx = (typer.TypeExpr(exprA).Type.Hint, typer.TypeExpr(exprB).Type.Hint);
    def teA = typer.TypeExpr(exprA);
    def teB = typer.TypeExpr(exprB);
    def tyA = typer.TypeExpr(exprA).Type;
    def tyB = typer.TypeExpr(exprB).Type;

    def upCast = 
      (texpr, ty) => 
        TExpr.TypeConversion (texpr.loc, ty, texpr, ty, 
                              ConversionKind.UpCast());
    def _implicit = 
      (texpr, ty) => 
        TExpr.TypeConversion (texpr.loc, ty, texpr, ty, 
                              ConversionKind.Implicit());

    match (tx) 
    {
      | (Some(Class(tiA, [tyA0]) as clA), Some(Class(_, _) as clB)) 
        when tiA.IsValueType && tiA.FullName == "System.Nullable" =>

          def clA0 = tyA0 :> MType.Class;
          if (clA0.Equals(clB) 
              || OpImplicitHelper.HasImplicit(clB, clA0))
          {
            /**
             *  BUG: 'Nullable[T]' can not be converted to 'T', 
             *       but it should.
             *  Example:
             *    def inull : int? = 10
             *    // cannot convert System.Nullable[int] to int:
             *    def i : int = inull :> int
            **/
            def st = <[ 
              if ($exprA != null) 
                $exprA.Value
              else 
                $(upCast(teB, tyA0) : typed)
            ]>;
            WriteLine($"nullable: B -> A0: $st");
            st
          }
          else if (clA.Equals(clB) 
                   || OpImplicitHelper.HasImplicit(clB, clA))
          {
            /**
             *  BUG: 'Nullable[T1]' can not be converted to 
             *       'Nullable[T2]' when 'T1' has implicit 
             *       conversation to 'T2', but it should.
             *  C# Example: 
             *    int? i = 10;
             *    double? d = i;
            **/
            def st = <[ 
              if ($exprA != null) 
                $exprA 
              else 
                $(upCast(teB, tyA) : typed)
            ]>;
            WriteLine($"nullable: B -> A: $st");
            st
          }
          else if (OpImplicitHelper.HasImplicit(clA0, clB))
          {
            /**
             *  BUG: 'T1' can not be converted to 'Nullable[T2]' 
             *       when 'T1' has implicit conversation to 'T2', 
             *       but it should.
             *  C# Example: 
             *    int i = 10;
             *    double? d = 0.1;
             *    d = i;
            **/
            def st = <[ 
              if ($exprA != null) 
                $(upCast(typer.TypeExpr(<[ $exprA.Value ]>), tyB) : typed)
              else 
                $exprB
            ]>;
            WriteLine($"nullable: A0 -> B: $st");
            st
          }
          else
          {
            Message.FatalError ($"Operator `??' cannot be applied to "
                                "operands of type `$clA' and `$clB'");
          }

      | (Some(Class(tiA, _)), Some(Class(_, _))) 
        when tiA.IsValueType =>

          Message.FatalError (exprA.Location, 
                              $"`$tiA' is not a reference or nullable type "
                              "as required by the `??' operator");

      | (Some(Class(_, _) as clA), Some(Class(_, _) as clB))
        when clA.Equals(clB) || OpImplicitHelper.HasImplicit(clB, clA) =>

          /**
           * ?BUG: This match case and next one can be replaced with single
           *       one, but followed by code doesn't compile. Is this a design
           *       decision or a bug? (C# compile such code with no problems)
           *  Example: 
           *    #pragma indent
           *    class A {}
           *    class B
           *      public static @:(_ : B) : A
           *        A()
           *    def a = A()
           *    def b = B()
           *    // expected B-, got A in computation branch:
           *    def c = if (a==null) b else a 
          **/
          def st = <[ 
            if ($exprA != null) 
              $exprA 
            else 
              $(upCast(teB, tyA) : typed)
          ]>;
          WriteLine($"reference: B -> A: $st");
          st

      | (Some(Class(_, _) as clA), Some(Class(_, _) as clB))
        when OpImplicitHelper.HasImplicit(clA, clB) =>

          def st = <[ 
            if ($exprA != null) 
              $(upCast(teA, tyB) : typed)
            else 
              $exprB
          ]>;
          WriteLine($"reference: A -> B: $st");
          st

      | _ => 
          Message.FatalError ($"Operator `??' cannot be applied to "
                              "operands of type `$tyA' and `$tyB'");
    }
  }
}


В процессе написания понял, что в Nemerle работа с Nullable типами просто никакая. В коде макроса в комментах можно встретить баги Nullable типов, которые мне с ходу удалось обнаружить. Чуть позже все баги занесу в багтрэкер, но прежде хочу разобраться в ряде моментов, ибо есть стойкое ощущение, что чего-то я недопонимаю.

Итак, пример использования макроса, с комментариями проблем:
#pragma indent

using System.Console;
using Iae.Macro;


class C1
  public override ToString() : string
    "C1"
  public Test() : void
    WriteLine("C1::Test");

class C2
  public static @:(_ : C2) : C1
    C1()
  public override ToString() : string
    "C2"

class CI
  public static @:(_ : CI) : int
    2

def getType['t] (_ : 't)
  $"$(typeof('t))"


def c1 = null : C1
def c2 = C2()
def r1 = c1 ?? c2 // (***)compile-time message: "reference: B -> A: if (c1 != null) c1; else (c2 : C1)"
def c1 = C1()
def t1 = getType(r1)
WriteLine($"TEST REFERENCE B -> A (result):  $r1")
WriteLine($"TEST REFERENCE B -> A (type):  $t1")
// run-time messages:
// TEST REFERENCE B -> A (result):  C2
// TEST REFERENCE B -> A (type):  C1

def r2 = c2 ?? c1 // compile-time message: "reference: A -> B: if (c2 != null) (c2 : C1); else c1"
def t2 = getType(r2)
WriteLine($"TEST REFERENCE A -> B (result):  $r2")
WriteLine($"TEST REFERENCE A -> B (type):  $t2")
// run-time messages:
// TEST REFERENCE B -> A (result):  C2
// TEST REFERENCE B -> A (type):  C1

def r0 = if (c1 == null) (c2 : C1) else c1 // собственно, тоже самое, что и в (***)
def t0 = getType(r0)
WriteLine($"TEST REFERENCE B -> A (result):  $r0")
WriteLine($"TEST REFERENCE B -> A (type):  $t0")
// run-time messages: выводит то, что ожидается в предыдущих случаях
// TEST REFERENCE B -> A (result):  C1
// TEST REFERENCE B -> A (type):  C1



def inull_v : int? = 10
def inull_n : int? = null
def r3 = inull_v ?? 1 // compile-time message: "nullable: B -> A0: if (inull_v != null) inull_v.Value; else (1 : int)"
def t3 = getType(r3)
WriteLine($"TEST NULLABLE B -> A0 (result):  $r3")
WriteLine($"TEST NULLABLE B -> A0 (type):  $t3")
// run-time messages:
// TEST NULLABLE B -> A0 (result):  10
// TEST NULLABLE B -> A0 (type):  System.Int32

def r4 = inull_n ?? 1 // compile-time message: "nullable: B -> A0: if (inull_n != null) inull_v.Value; else (1 : int)"
def t4 = getType(r4)
WriteLine($"TEST NULLABLE B -> A0 (result):  $r4")
WriteLine($"TEST NULLABLE B -> A0 (type):  $t4")
// run-time messages:
// TEST NULLABLE B -> A0 (result):  1
// TEST NULLABLE B -> A0 (type):  System.Int32


def r5 = test(inull_n) // это макрос, см. выше
def t5 = getType(r5)
WriteLine($"TEST NULLABLE B -> A0 (result):  $r5")
WriteLine($"TEST NULLABLE B -> A0 (type):  $t5")
// run-time messages:
// TEST NULLABLE B -> A0 (result):  2
// TEST NULLABLE B -> A0 (type):  System.Int32

def r5 = inull_n ?? CI() // compile-time message: "nullable: B -> A0: if (inull_n != null) inull_n.Value; else (CI () : int)"
// Compile-time exception:
//test.n:59:21:59:23: debug: Internal compiler error, please report a bug to bugs.nemerle.org. You can try modifying program near this location.
//error: internal compiler error: assertion failed in file ncc\generation\ILEmitter.n, line 801:
//_N_AutoModule::Main: failed to convert non-value type CI to a value type int
// .............

def r5 = if (inull_n != null) inull_n.Value; else (CI () : int)
def t5 = getType(r5)
WriteLine($"TEST NULLABLE B -> A0 (result):  $r5")
WriteLine($"TEST NULLABLE B -> A0 (type):  $t5")
// run-time messages:
// TEST NULLABLE B -> A0 (result):  2
// TEST NULLABLE B -> A0 (type):  System.Int32


Вообщем сдается мне, что есть какие-то тонкости, о которых я пока не знаю... Может есть какие-то идеи, почему макрос отрабатывает не так как хотелось бы?
... << RSDN@Home 1.2.0 alpha rev. 655>>

30.01.07 18:10: Перенесено модератором из 'Декларативное программирование' — IT
Превратим окружающую нас среду в воскресенье.
Re: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 23.09.06 14:55
Оценка:
Здравствуйте, ie, Вы писали:

ie>В процессе написания понял, что в Nemerle работа с Nullable типами просто никакая.


это определенно связано с наличием в языке option['a]
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 23.09.06 15:15
Оценка:
Здравствуйте, PhantomIvan, Вы писали:

ie>>В процессе написания понял, что в Nemerle работа с Nullable типами просто никакая.

PI>это определенно связано с наличием в языке option['a]

Никакой связи не вижу...
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[3]: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 23.09.06 17:13
Оценка:
Здравствуйте, ie, Вы писали:

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


ie>>>В процессе написания понял, что в Nemerle работа с Nullable типами просто никакая.

PI>>это определенно связано с наличием в языке option['a]

ie>Никакой связи не вижу...


превратить переменную в null — это все равно что показать, что в ней нет никакого осмысленного значения
в c# value-типы не имели возможности обратиться в null, и не имеют ее сейчас, т.к. реально при декларировании чего-то вроде int? создается объект класса вроде Nullable<int>
по идее, производительность, для которой собственно, и существуют value-типы, падает в результате применения фактически ссылочного типа вместо исходного value-типа

в немерле появляется класс option['a], который принимает 2 значения, аналогично nullable типу выше: Some(x) или None()
то есть это то же самое фактически, но семантика выражена более явно, при этом собственно null не используется, что дает возможность применять option для обычных reference-объектов

я пользовался и nullable-типами c#-а, и option из немерле
однако пользовался не много, и сказать что лучше, не могу
по-моему те же яйца, только в профиль

говорят, nullable-типы в c#-пе были нужны в связи с базаданными типами
и говорят также, что ado.net 2.0 реально их не использует

впрочем, мне все равно, что использовать из этих двух вещей — ведь по сути что там, что здесь это вариант по сути
а есть ли у option оверхед (синтаксический или перфоманс), — непонятно
может, со временем, увижу неудобства, и мое мнение изменится
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 23.09.06 17:20
Оценка:
PI>впрочем, мне все равно, что использовать из этих двух вещей — ведь по сути что там, что здесь это вариант по сути

все равно с точки зрения производительности
а иногда структуры становятся классами, и наоборот (рефакторинг типа)
и тогда, кажется, option более удобен, т.к. позволяет пустить всех под 1 гребенку
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 23.09.06 17:48
Оценка: +1
Здравствуйте, PhantomIvan, Вы писали:

PI>превратить переменную в null — это все равно что показать, что в ней нет никакого осмысленного значения


С одной стороны да, а с другой — наллаблы были введены как раз для унификации reference и value типов с точки зрения null-значений.

PI>в c# value-типы не имели возможности обратиться в null, и не имеют ее сейчас, т.к. реально при декларировании чего-то вроде int? создается объект класса вроде Nullable<int>

PI>по идее, производительность, для которой собственно, и существуют value-типы, падает в результате применения фактически ссылочного типа вместо исходного value-типа

Прошу обратить внимание на выделенное:
public struct Nullable<T> where T: struct

Так что о падении производительности из-за использовании ссылок я бы смелых заявлений делать не стал бы

PI>в немерле появляется класс option['a], который принимает 2 значения, аналогично nullable типу выше: Some(x) или None()

PI>то есть это то же самое фактически, но семантика выражена более явно, при этом собственно null не используется, что дает возможность применять option для обычных reference-объектов

Однако, повторюсь, наллаблы добавили для возможности работать со всеми объектами (в том числе и value-типов), как с объектами принимающими значение null.
Some же пришло в Nemerle из функционального мира, где значения null не существует. Это более высокий уровень абстракции.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[5]: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 23.09.06 20:24
Оценка:
Здравствуйте, ie, Вы писали:

...

согласен в принципе, но нужны ли эти ноллаблы особо?
это внатуре вопрос
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 23.09.06 20:31
Оценка:
Здравствуйте, PhantomIvan, Вы писали:

PI>согласен в принципе, но нужны ли эти ноллаблы особо?


Как один из языков .NET Nemerle должен поддерживать всё, что есть в CLR.

PI>это внатуре вопрос


Что-то твоя падонковщина уже начинает напрягать. Это внатуре предупреждение.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 23.09.06 21:04
Оценка:
IT>Как один из языков .NET Nemerle должен поддерживать всё, что есть в CLR.

тоже в принципе согласен
но это дается ценой некоторой путаницы, к примеру
коллекции .net — коллекции nemerle
nullable — option
delegates — function values

что применять, где применять, это путает
тех, кто только принимается программировать на немерле

какая падонковщина, не выдумывай
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.09.06 21:44
Оценка:
Здравствуйте, ie, Вы писали:

Насколько я помню в рассылке упоминалось, что поддержка нулабл-типов ограниченная. Ребятам было просто влом терять на них время.
Откровенно говоря я сам так ни разу ими и не воспользовался по делу. Один раз захотелось, но обломался, так как они несовместимы со ссылочными типами.

Что до оператора ??, то больно сложно у тебя что-то выходит. Мне кажется ты перемудрил. Ничего осмысленного о реализации сказать не могу (не вникал).

Зато могу дать предложение. Хорошо бы чтобы этот оператор поддерживал бы и option[T].
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.09.06 21:44
Оценка:
Здравствуйте, PhantomIvan, Вы писали:

PI>тоже в принципе согласен

PI>но это дается ценой некоторой путаницы, к примеру
PI>коллекции .net — коллекции nemerle
PI>nullable — option
PI>delegates — function values

Делегаты обратно соместимы с функциональными объектами, так что все ОК.

Думаю, что и option можно сделать не отличимым в использовании от nullable.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 24.09.06 22:50
Оценка: +2
Здравствуйте, VladD2, Вы писали:

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


PI>>тоже в принципе согласен

PI>>но это дается ценой некоторой путаницы, к примеру
PI>>коллекции .net — коллекции nemerle
PI>>nullable — option
PI>>delegates — function values

VD>Делегаты обратно соместимы с функциональными объектами, так что все ОК.


VD>Думаю, что и option можно сделать не отличимым в использовании от nullable.


но путаница возникает все-таки
вот, у Ильи кажется заминка с применением делагатов вышла
я к тому, что если некоторые вещи удобней в немерле (например функции), чем в дотнете (делегаты), то нужны ли, по большому счету, эти чисто дотнетные вещи...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.09.06 23:57
Оценка:
Здравствуйте, PhantomIvan, Вы писали:

PI>но путаница возникает все-таки

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

Конечно. Причем просто для совместимости с другими языками дотнета. Почему-то меня не покидает уверенность, что Немерле еще не скоро станет едиственным или хотя бы основным языком дотнета. А до тех пор он будет прекрасным средством реализации длл-лек которые будут использоваться из других языков. И тут Немерле требуется все умение, чтобы успешно прикидываться C#-ом для внешних клиентов (т.е. создавать публичный интерфейс сборок не отличимый от C# последней версии).

В общем, с точки зрения возможности создания публичных интерфейсов и возможности использования чужих интерфейсов Nemerle обязан быть эдаким C#++, ну, или C##. Собственно это и декларируется.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Nemerle] The null coalescing operator
От: FR  
Дата: 25.09.06 05:18
Оценка:
Здравствуйте, VladD2, Вы писали:

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


PI>>но путаница возникает все-таки

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

VD>Конечно. Причем просто для совместимости с другими языками дотнета. Почему-то меня не покидает уверенность, что Немерле еще не скоро станет едиственным или хотя бы основным языком дотнета. А до тех пор он будет прекрасным средством реализации длл-лек которые будут использоваться из других языков. И тут Немерле требуется все умение, чтобы успешно прикидываться C#-ом для внешних клиентов (т.е. создавать публичный интерфейс сборок не отличимый от C# последней версии).


Правильней было бы все что нужно для прикидывания C# выделить в отдельную сущность (скажем библиотеку макросов — враперов) а не портить язык.
Re[2]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 25.09.06 05:51
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Насколько я помню в рассылке упоминалось, что поддержка нулабл-типов ограниченная. Ребятам было просто влом терять на них время.

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

Ну это в принципе ладно, не поддерживаются и бог с ними. Кстати, классная задачка, для желающего разобраться с компилятором (ну или хотя бы с его частью). Возможно, попробую пофиксать, коль время будет. Что до пользования ими, то мне реально пригодились наллаблы лишь несколько раз, примерно в таких случаях:

    // без наллаблов:
    public bool GetValue(out int value)
    {
        if (надоВернутьЗначение)
        {
            value = 10;
            return true;
        }
        else
        {
            value = 0;
            return false;
        }
    }

        int z;
        if (GetValue(out z))
            // do something

    // с наллаблами:
    public int? GetValueN()
    {
        return надоВернутьЗначение ? 10 : (int?)null;
    }

        int? zn = GetValueN();
        if (zn != null)
            // do something


С наллаблами код становиться лаконичнее, хотя и без них обойтись можно.

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


Дык, я тоже думал проще получится, а оказалось сам оператор достаточно служный и имеет ряд ньюансов. На самом деле все эти ньюансы касаются наллабл-типов. С референс-типами все сводится к банальному ?:, но и тут у Немерла проблемы:

C#:
class A {}

class B : A {}

class C
{
    public static implicit operator B(C c)
    {
        return new B();
    }
}

A a = new A();
B b = new B();
C c = new C();

B b1 = c ?? b;
A a1 = c ?? a;
B b2 = c == null ? b : c;
A a2 = a == null ? c : a;

Nemerle:
class A
  ;
    
class B : A
  ;

class C
  public static @:>(c : C) : B
    B();


def a = A();
def b = B();
def c = C();
// expected B-, got C in computation branch: common super type of types [B, C] is just `System.Object', 
// please upcast one of the types to `System.Object' if this is desired
def b2 = if (c == null) b else c;
// expected C-, got A in computation branch: common super type of types [C, A] is just `System.Object', 
// please upcast one of the types to `System.Object' if this is desired
def a2 = if (a == null) c else a;


Вот и не ясно, толи это ограничения матча, толи это баг. Я написал Москалю, посмотрим, что об этом скажет. Так вот если это ограничение матча и фиксать они его не планируют, то мой макрос упростить никак нельзя, даже наоборот, он еще больше может усложниться.

VD>Зато могу дать предложение. Хорошо бы чтобы этот оператор поддерживал бы и option[T].


Это следующее, что я хотел сделать, как только он мало-мальски заработает


Если в кратце, то основная моя загвоздка описывается вот таким вот кодом:
макрос

  macro @??? (exprA, exprB)
  {
    def typer = Macros.ImplicitCTX ();
    def teB = typer.TypeExpr(exprB);
    def tyA = typer.TypeExpr(exprA).Type;
    def tyB = typer.TypeExpr(exprB).Type;
    def tx = (tyA.Hint, tyB.Hint);

    def upCast = 
      (texpr, ty) => 
        TExpr.TypeConversion (texpr.loc, ty, texpr, ty, 
                              ConversionKind.UpCast());

    match (tx) 
    {
      | (Some(Class(_, _)), Some(Class(_, _))) =>

          def st = <[ 
            if ($exprA != null) 
              $exprA 
            else 
              $(upCast(teB, tyA) : typed)
          ]>;
          WriteLine($"Generated expression: $st");
          st

      | _ => 
          Message.FatalError ($"Operator `???' cannot be applied to "
                              "operands of type `$tyA' and `$tyB'");
    }
  }

тестовый пример
class C1
  public override ToString() : string
    "C1"

class C2
  public static @:(_ : C2) : C1
    WriteLine("Implicit!")
        C1()
  public override ToString() : string
    "C2"

def c1 = null : C1
def c2 = C2()
def r = c1 ??? c2
WriteLine($"r: $r")


А непонимаю я собственно вот что: при компиляции тестового примера получаю ожидаемое сообщение:

Generated expression: if (c1 != null) c1; else (c2 : C1)

Если вместо c1 ??? c2, тупо написать этот самый сгенерированный if:
def r = if (c1 != null) c1; else (c2 : C1)
WriteLine($"r: $r")

то при выполнении получу то, что хочу:

Implicit!
r: C1

а если оставить ???, то при выполнении:

r: C2


Почему, вроде бы правильно сгенерированный if выполняется не правильно, я не понимаю. Причем, если глянуть рефлектором, то код для обоих случаев получается идентичный:
    C1 c1 = null;
    C2 c2 = new C2();
    C1 c3 = (c1 == null) ? ((C1) c2) : c1;
    StringBuilder builder1 = new StringBuilder();
    builder1.Append("r: ");
    builder1.Append(c3);
    Console.WriteLine(builder1.ToString());
    C1 c4 = (c1 == null) ? ((C1) c2) : c1;
    StringBuilder builder2 = new StringBuilder();
    builder2.Append("r: ");
    builder2.Append(c4);
    Console.WriteLine(builder2.ToString());


Однако, если глянуть il, то видны различия:
c1 ??? c2
      L_0008: ldloc.0 
      L_0009: ldnull 
      L_000a: ceq 
      L_000c: ldc.i4.0 
      L_000d: ceq 
      L_000f: ldc.i4.1 
      L_0010: bne.un L_001b
      L_0015: ldloc.0 
      L_0016: br L_001c
      L_001b: ldloc.1 
      L_001c: stloc.2 


if (c1 != null) c1; else (c2 : C1)
      L_0042: ldloc.0 
      L_0043: ldnull 
      L_0044: ceq 
      L_0046: ldc.i4.0 
      L_0047: ceq 
      L_0049: ldc.i4.1 
      L_004a: bne.un L_0055
      L_004f: ldloc.0 
      L_0050: br L_005b
      L_0055: ldloc.1 
      L_0056: call C1 C2::op_Implicit(C2)
      L_005b: stloc.s c4


Почему такие различия я ума не приложу.
Как можно посмотреть сгенеренный после выполнения макроса код? Т.е. финальный код, который будет скармливаться компилятору. В интеграции я видел, вы сделали такое раскрытие кода, но пока нет возможности скачать VSSDK, так что поглядеть в студии не могу.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[12]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 25.09.06 06:07
Оценка:
Здравствуйте, FR, Вы писали:

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


В конечном счете, было бы правильно, если б к этому все пришло, но выносить все эти вещи, поддерживаемые рантаймом, в отдельную сущность достаточно большой объем работы. Да и вообще, с приводимыми тут похожестями:

PI>>коллекции .net — коллекции nemerle

PI>>nullable — option

не согласен:
— коллекции nemerle нисколько не пытаются заменить коллекции .net, а расширяют их
— nullable — это средство представления null-based value-типов, причем без пенальти, как с точки зрения использования памяти, так и с точки зрения быстродействия. option же имеет другое предназначение.

согласен только с этой:

PI>>delegates — function values
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[5]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 25.09.06 06:11
Оценка:
Здравствуйте, PhantomIvan, Вы писали:

PI>>впрочем, мне все равно, что использовать из этих двух вещей — ведь по сути что там, что здесь это вариант по сути


PI>все равно с точки зрения производительности


Вот как раз с точки зрения производительности, иногда и слудет отказаться от option в пользу nullable типов.

PI>а иногда структуры становятся классами, и наоборот (рефакторинг типа)


Первый раз слышу такое определение боксинга/анбоксинга

PI>и тогда, кажется, option более удобен, т.к. позволяет пустить всех под 1 гребенку


Да он ИМХО почти всегда удобней, но всегда есть "но"
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[6]: [Nemerle] The null coalescing operator
От: PhantomIvan  
Дата: 25.09.06 07:00
Оценка:
PI>>а иногда структуры становятся классами, и наоборот (рефакторинг типа)

ie>Первый раз слышу такое определение боксинга/анбоксинга


не, я имел в виду рефакторинг "сделать из структуры класс", "сделать из класса структуру"
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[12]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.09.06 15:38
Оценка:
Здравствуйте, FR, Вы писали:

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


И как можно, например, поддержку делегатов выделить в библиотеку?

А оператор ?? и так будет в библиотеке которую в общем-то можно не использовать.

Вот только это стандартная библиотека и без нее никто не будет воспринимать язык.

Nemerle вообще два. Один базовый. А другой полный, в библиотеке.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.09.06 15:38
Оценка: +1
Здравствуйте, ie, Вы писали:

ie>Что до пользования ими, то мне реально пригодились наллаблы лишь несколько раз, примерно в таких случаях:


ie>
ie>    // с наллаблами:
ie>    public int? GetValueN()
ie>    {
ie>        return надоВернутьЗначение ? 10 : (int?)null;
ie>    }

ie>        int? zn = GetValueN();
ie>        if (zn != null)
ie>            // do something
ie>


ie>С наллаблами код становиться лаконичнее, хотя и без них обойтись можно.


Тебе повезло, что использовался конкретный тип — int. А вот мне нужно было сделать тоже самое, но для абстрактного T. И я обломался, так как при этмо я обязан был пометить T как вэлью-тип (struct), а для бибилотеки это неприемлемо.

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


ie>Дык, я тоже думал проще получится, а оказалось сам оператор достаточно служный и имеет ряд ньюансов. На самом деле все эти ньюансы касаются наллабл-типов. С референс-типами все сводится к банальному ?:,


Очень станно. У наллабл есть свойство HasValue которое сводит работу с ним к тому же ?:. Но только ?: в Nemerle нет, так что к if()/else.

ie>но и тут у Немерла проблемы:

...
Это скорее всего баг в компиляторе. У них вообще с неявнями приведениями типов проблемы. Хорошо что это большая редкость.

ie>Вот и не ясно, толи это ограничения матча, толи это баг. Я написал Москалю, посмотрим, что об этом скажет.


Разумно. Потом странслуруй куда нить. А вообще надо было писать в конфу.

ie> Так вот если это ограничение матча и фиксать они его не планируют, то мой макрос упростить никак нельзя, даже наоборот, он еще больше может усложниться.


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

ie>Если в кратце, то основная моя загвоздка описывается вот таким вот кодом:

...
ie>А непонимаю я собственно вот что: при компиляции тестового примера получаю ожидаемое сообщение:
...

Незнаю. Вникать нет времени. Но тоже вижу что код явно какой-то слишком избыточный. В ральных условиях обработка option[] сводится к (псевдокод):
using System.Console;

module P
{
  public GetValueWithDefault[T](value : option[T], default : T) : T
  {
      match (value)
      {
          | Some(x) => x
          | None    => default
      }
  }
}

def a = Some(1) : option[int];
def b = None() : option[int];

WriteLine(P.GetValueWithDefault(a, 0));
WriteLine(P.GetValueWithDefault(b, 0));

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

С nullable все должно быть точно так же:
using System.Console;

module P
{
  public GetValueWithDefault[T](value : T?, default : T) : T
        where T: struct
  {
    if (value.HasValue) value.Value else default;
  }
}

def a = 1 : int?;
def b = null : int?;

WriteLine(P.GetValueWithDefault(a, 0));
WriteLine(P.GetValueWithDefault(b, 0));


Если этот код не компилируется (а это так, проверил), то нужно лать баг-репорт и ждать пока Камил или Москаль разберутся. Или самому поправить ошибки.
Аналогичный код на C# без проблем компилируется:
using System;

class P
{
    static T GetValueWithDefault<T>(T? value, T def)
        where T: struct

    {
        return value.HasValue ? value.Value : def;
    }

    static void Main(string[] args)
    {
        int? a = 1;
        int? b = null;

        Console.WriteLine(GetValueWithDefault(a, 0));
        Console.WriteLine(GetValueWithDefault(b, 0));
    }
}


В общем, не забивай голову и не трать зря время. Такие горы кода по такому примитивному случаю делать нельзя. Надо исправлять причины проблем, а не замазвать их проявления.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 27.09.06 09:26
Оценка: 30 (2)
Ну что ж. В итоге после копания в компиляторе, разговоров с Москалем и крепких размышлений, пришел вот к чему:

Для написания оператора '??' одним if/else не обойтись. Ну второй if/else спецефичный для наллаблов, особого труда не представляет, так что я действительно понаворотил кучу ненужного кода, который по сути является заплатками недоработок компилятора.

Для нормального функционирования макроса нужно пофиксать 2 бага:

1. Хотя этот баг Москаль считает не багом, а скорее некоторым ограничением, он все равно планирует его поправить:
    class A {}
    class B
    public static @:(_ : B) : A
        A()
    def a = A()
    def b = B()
    // expected B-, got A in computation branch:
    def c = if (a==null) b else a

В if/match проверяется только возможность приведения к базовому типу с целью поиска общего типа, но не проверяется возможность implicit приведения.

2. Баг с implicit/explicit приведением generic типов:
def p = (10 : int?) :> int; 
// это был пример с наллаблами, но проблема распростроняется и на все другие типы, например:
class Y['t]
  mutable _t : 't
  public this(t : 't)
    _t = t
  public static @:> (y : Y['t]) : 't
    y._t
  
def y = Y.[int](10)
def x = y :> int

С этой проблемой я решил попробовать разобраться сам. Сразу скажу ничерта не вышло, но в основной задаче, которую я себе ставил — понять как работает компилятор Немерла — маленько продвинулся.
В классе Typer есть метод TypeConversion. Который проверяет можно ли expression привести к некоторому типу. Так вот что этот метод делает касательно приведенного выше примера:
а. получает список всех implicit и explicit операторов у типа expression и приводимого типа;
б. выкидывает повторяющиеся;
в. строит needed — тип функции, с сигнатурой требуемой для нашего преобразования (Y[int] -> int);
г. проверяет имеют ли implicit/explicit операторы сигнатуру эквивалентную needed, если нет, выкидываем из рассмотрения;
д. выбираем наилучший оператор, используем его.
Так вот проблема возникла в пункте г. op_Explicit для приведенного примера имеет сигнатуру Y['t] -> 't, а не как нам бы хотелось Y[int] -> int. Я написал патч строящий правильные сигнатуры (в мантисе в баге я этот патч приаттачил), но это не решило проблему. Начал валиться с исключением Typer4:

tv 't.836 defined in Y and accessed from _N_AutoModule

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

Хмммм...... Дописал все и думаю, а нафига я все это пишу....
Ну уж коль написал пущай будет. Мож кому интересно...
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 29.09.06 11:00
Оценка: 87 (1)
Финальный вариант макроса, забил на несколько экзотических правил C#-ового оператора и добавил поддержку option:

using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Text;

namespace Nemerle.Core
{
  macro @?? (exprA, exprB) 
  {
    def refEq = System.Type.ReferenceEquals;
    def ref3Eq = (t1,t2,t3) => refEq(t1, t2) || refEq(t1, t3);
    def tnullable = typeof (System.Nullable[_]);
    def toptNone = typeof (Nemerle.Core.option[_].None);
    def toptSome = typeof (Nemerle.Core.option[_].Some);

    def typer = Macros.ImplicitCTX ();
    def hA = typer.TypeExpr (exprA).Type.Hint;
    def hB = typer.TypeExpr (exprB).Type.Hint;
    def tx = (hA, hB);

    match (tx) {
      | (Some (Class (tiA, _)), Some (Class (tiB, _))) 
        when tiA.IsValueType && refEq (tiA.SystemType, tnullable)
                && !refEq (tiB.SystemType, tnullable)
             || ref3Eq (tiA.SystemType, toptNone, toptSome)
                && !ref3Eq (tiB.SystemType, toptNone, toptSome) =>

          <[ if ($exprA.HasValue) $exprA.Value else $exprB ]>;

      | (Some (Class (tiA, _)), Some (Class (tiB, _))) 
        when tiA.IsValueType && refEq (tiA.SystemType, tnullable)
                && refEq (tiB.SystemType, tnullable) =>

          <[ if ($exprA != null) $exprA else $exprB ]>;

      | (Some (Class (tiA, _)), Some (Class (tiB, _))) 
        when ref3Eq (tiA.SystemType, toptNone, toptSome)
                && ref3Eq (tiB.SystemType, toptNone, toptSome) =>

          <[ if ($exprA.IsSome) $exprA else $exprB ]>;

      | (Some (Class (tiA, _)), Some (Class (_, _))) 
        when tiA.IsValueType =>

          Message.FatalError (exprA.Location, 
                              $"`$tiA' is not a reference or nullable type "
                              "as required by the `??' operator");

      | _ => 
          <[ if ($exprA != null) $exprA else $exprB ]>;
    }
  }
}


Тесты:
using System.Console;



def GetExprType['t] (_ : 't)
{
  typeof ('t)
}



def rn = null;
def r1 = "str1";
def r2 = "str2";

assert (rn ?? r2 == "str2");
assert (GetExprType(rn ?? r2).Equals (typeof (string)));
WriteLine($"$(rn ?? r2)");

assert (r1 ?? r2 == "str1");
assert (GetExprType(r1 ?? r2).Equals (typeof (string)));
WriteLine($"$(r1 ?? r2)");



def dn : double? = null;
def d1 : double? = 0.1;
def d2 : double? = 0.2;

assert ((dn ?? d2).Value == 0.2);
assert (GetExprType(dn ?? d2).Equals (typeof (double?)));
WriteLine($"$(dn ?? d2)");

assert ((d1 ?? d2).Value == 0.1);
assert (GetExprType(d1 ?? d2).Equals (typeof (double?)));
WriteLine($"$(d1 ?? d2)");

assert (dn ?? 0.3 == 0.3);
assert (GetExprType(dn ?? 0.3).Equals (typeof (double)));
WriteLine($"$(dn ?? 0.3)");

assert (d1 ?? 0.3 == 0.1);
assert (GetExprType(d1 ?? 0.3).Equals (typeof (double)));
WriteLine($"$(d1 ?? 0.3)");



def on = None();
def on2 = None();
def o1 = Some(1);
def o2 = Some(2);

assert ((on ?? o2).IsSome);
assert ((on ?? o2).Value == 2);
assert (GetExprType(on ?? o2).Equals (typeof (option[int])));
WriteLine($"$(on ?? o2)");

assert ((o1 ?? o2).Value == 1);
assert (GetExprType(o1 ?? o2).Equals (typeof (option[int].Some)));
WriteLine($"$(o1 ?? o2)");

assert (on ?? 3 == 3);
assert (GetExprType(on ?? 3).Equals (typeof (int)));
WriteLine($"$(on ?? 3)");

assert (o1 ?? 3 == 1);
assert (GetExprType(o1 ?? 3).Equals (typeof (int)));
WriteLine($"$(o1 ?? 3)");

assert ((on ?? on2).IsNone);
assert (GetExprType(on ?? on2).Equals (typeof (option[int].None)));
WriteLine($"$(on ?? on2)");
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[2]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.09.06 17:44
Оценка:
Здравствуйте, ie, Вы писали:

ie>Финальный вариант макроса, забил на несколько экзотических правил C#-ового оператора и добавил поддержку option:


ie>
ie>    def tnullable = typeof (System.Nullable[_]);
ie>    def toptNone = typeof (Nemerle.Core.option[_].None);
ie>    def toptSome = typeof (Nemerle.Core.option[_].Some);
ie>


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

А эти:
ie> def refEq = System.Type.ReferenceEquals;
ie> def ref3Eq = (t1,t2,t3) => refEq(t1, t2) || refEq(t1, t3);
Лучше переписать на обычных локальных методах чтобы вызова по ссыне не блыло. Хотя это уже не так важно.

Так как оператор вызвается довольно часто стоит немного подоптимизировать.

И вот это:
          <[ if ($exprA.IsSome) $exprA else $exprB ]>;

мне кажется ошибкой. Ведь $exprA будет тоже типа Some(...), а это не верно. Надо так:
          <[ match ($exprA) { | Some(x) => x | _ => $exprB ]>;


Ну, и соотвественно тесты надо исправить. А то ты их явно под ошибку подстрогал.
Не:
assert (GetExprType(on ?? o2).Equals (typeof (option[int])));

а:
assert (GetExprType(on ?? o2).Equals (typeof (int)));



Потом match по двум значениям (кортежу) медленее чем по одному значению. А так как у тебя в первом элементе всегда Some (Class (tiA, _)), то стоит использовать вложенный match. Оно и понятнее будет.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.09.06 17:44
Оценка:
Здравствуйте, ie, Вы писали:

ie>
ie>    def tnullable = typeof (System.Nullable[_]);
ie>    def toptNone = typeof (Nemerle.Core.option[_].None);
ie>    def toptSome = typeof (Nemerle.Core.option[_].Some);
...
ie>        when tiA.IsValueType && refEq (tiA.SystemType, tnullable)
ie>


Кстати, меня интересует вопрос... Ты вот сравниваешь дотнетные типы основываясь на том, что все нужные тебе типы всегда определены во вне. А как быть если нужно сравнить типы которые могут быть определены как во внешней сборке, так и в компилируемом проекте?

Может есть какой-то более универсальный способ?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 09:32
Оценка:
Здравствуйте, VladD2, Вы писали:

ie>>
ie>>    def tnullable = typeof (System.Nullable[_]);
ie>>    def toptNone = typeof (Nemerle.Core.option[_].None);
ie>>    def toptSome = typeof (Nemerle.Core.option[_].Some);
ie>>


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


Это да. Добавлю нужные типы в \ncc\external\internaltypes.n

VD>И вот это:

VD>
VD>          <[ if ($exprA.IsSome) $exprA else $exprB ]>;
VD>

VD>мне кажется ошибкой. Ведь $exprA будет тоже типа Some(...), а это не верно. Надо так:
VD>
VD>          <[ match ($exprA) { | Some(x) => x | _ => $exprB ]>;
VD>


Тут я сделал по аналогии с nullable. A ?? B. Если A и B nullable, то результат тоже nullable, если A nullable, а B нет, то и результат является базой nullable. Ты привел кусок кода, где оба выражения option. В этом случае и результат option.

VD>Потом match по двум значениям (кортежу) медленее чем по одному значению. А так как у тебя в первом элементе всегда Some (Class (tiA, _)), то стоит использовать вложенный match. Оно и понятнее будет.


Ок.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[3]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 09:32
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Кстати, меня интересует вопрос... Ты вот сравниваешь дотнетные типы основываясь на том, что все нужные тебе типы всегда определены во вне. А как быть если нужно сравнить типы которые могут быть определены как во внешней сборке, так и в компилируемом проекте?


Что-то не понял вопроса. Или ты имеешь ввиду типы, которые могут появиться в компайл-тайме после выполнения какого-то макроса?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[4]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 12:26
Оценка:
Здравствуйте, ie, Вы писали:

ie>Ок.


Теперь пора заняться '??='
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[5]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 12:37
Оценка:
Здравствуйте, IT, Вы писали:

ie>>Ок.

IT>Теперь пора заняться '??='

Можно так:
  macro @??= (exprA, exprB) 
  {
    <[ {$exprA = $exprA ?? $exprB; $exprA} ]>
  }

Только вот хз что с ним делать, какие-то он экзотические задачи решает
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[5]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 13:05
Оценка:
Здравствуйте, IT, Вы писали:

IT>Теперь пора заняться '??='


А правильно ли я понимаю, что он будет иметь поведение другое нежели '??'. Например:
def i : int? = 10;
def j = i ?? 2;

у j будет тип int, а в случае с '??=' такая ситуация недопустима.
Хмм. ну ок, накидаю, как свободная минутка появится, все вроде тривиально.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[6]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 13:54
Оценка:
Здравствуйте, ie, Вы писали:

ie>А правильно ли я понимаю, что он будет иметь поведение другое нежели '??'. Например:


Если выражать через ??, то поведение должно быть примерно такое:

mutable a;
def b = a ?? { a = c; a };
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 13:55
Оценка: +1
Здравствуйте, ie, Вы писали:

ie>Только вот хз что с ним делать, какие-то он экзотические задачи решает


Нормальные задачи, например, отложенная инициализация свойст недефолтными значениями.
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 14:07
Оценка:
Здравствуйте, ie, Вы писали:

VD>>И вот это:

VD>>
VD>>          <[ if ($exprA.IsSome) $exprA else $exprB ]>;
VD>>

VD>>мне кажется ошибкой. Ведь $exprA будет тоже типа Some(...), а это не верно. Надо так:
VD>>
VD>>          <[ match ($exprA) { | Some(x) => x | _ => $exprB ]>;
VD>>


ie>Тут я сделал по аналогии с nullable. A ?? B. Если A и B nullable, то результат тоже nullable, если A nullable, а B нет, то и результат является базой nullable. Ты привел кусок кода, где оба выражения option. В этом случае и результат option.


Но это бессмысленно! Даже больше. Это просто неразумно. Да и работать не может. Ведь не может же один и тот же оператор в разные моменты возвращать Nullable[T] и T?
В общем, это явный баг.

Весь смысл этого оператора в том, чтобы он возвращал значение засунутое в nullable тип или значение используемое по умолчанию.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 14:07
Оценка:
Здравствуйте, ie, Вы писали:

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


VD>>Кстати, меня интересует вопрос... Ты вот сравниваешь дотнетные типы основываясь на том, что все нужные тебе типы всегда определены во вне. А как быть если нужно сравнить типы которые могут быть определены как во внешней сборке, так и в компилируемом проекте?


ie>Что-то не понял вопроса. Или ты имеешь ввиду типы, которые могут появиться в компайл-тайме после выполнения какого-то макроса?


На самом деле я уже нашел вопрос. Сравнивать нужно не дотнетные типы (т.е. не System.Type), а Nemerle-овское TypeInfo. Немерловцы сами создали список часто используемых типов и заполняют его в начальной стадии компиляции. Правда туда можно поместить только внешние типы. А внутренние нужно "лукапить" перед использованием.

Но проблемы все же остаются. В рефлекшоне есть фунукции позволяющие узнать является ли тип подтипом другого типа, или реализует ли тип некоторый интерйесй. Похоже подобных функций в Немерле попросту нет. Так что их нужно еще написать. А жаль.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 14:47
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Но это бессмысленно! Даже больше. Это просто неразумно. Да и работать не может. Ведь не может же один и тот же оператор в разные моменты возвращать Nullable[T] и T?

VD>В общем, это явный баг.

VD>Весь смысл этого оператора в том, чтобы он возвращал значение засунутое в nullable тип или значение используемое по умолчанию.


Однока, спецификация C# так не считает, и в этом я с ней солидарен.
int? p = null;
int? q = null;
if (p ?? q == 0); // тут мне 0 нафиг не нужен
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[7]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 14:52
Оценка: +1
Здравствуйте, IT, Вы писали:

ie>>А правильно ли я понимаю, что он будет иметь поведение другое нежели '??'. Например:

IT>Если выражать через ??, то поведение должно быть примерно такое:

IT>
IT>mutable a;
IT>def b = a ?? { a = c; a };
IT>


Сравнивая поведение, я имел ввиду немного другое.

mutable a : int? = null;
def b = a ?? 5; // тут тип int, а если тупо выражать ??= через ??, то получим бредовые ошибки.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[5]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 14:53
Оценка:
Здравствуйте, VladD2, Вы писали:

ie>>Что-то не понял вопроса. Или ты имеешь ввиду типы, которые могут появиться в компайл-тайме после выполнения какого-то макроса?


VD>На самом деле я уже нашел вопрос. Сравнивать нужно не дотнетные типы (т.е. не System.Type), а Nemerle-овское TypeInfo. Немерловцы сами создали список часто используемых типов и заполняют его в начальной стадии компиляции. Правда туда можно поместить только внешние типы. А внутренние нужно "лукапить" перед использованием.


Я собственно в итоге все на TypeInfo и поменял.

VD>Но проблемы все же остаются. В рефлекшоне есть фунукции позволяющие узнать является ли тип подтипом другого типа, или реализует ли тип некоторый интерйесй. Похоже подобных функций в Немерле попросту нет. Так что их нужно еще написать. А жаль.


Ну BaseType то есть, а значит как минимум IsSubclassOf или IsAssignableFrom достаточно просто реализуемы.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[8]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 14:54
Оценка:
Здравствуйте, ie, Вы писали:

ie>def b = a ?? 5; // тут тип int, а если тупо выражать ??= через ??, то получим бредовые ошибки.


Какие именно бредовые? Если я буду делать тоже самое без макроса, то ошибки будут не бредовые?
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 15:11
Оценка:
Здравствуйте, IT, Вы писали:

ie>>def b = a ?? 5; // тут тип int, а если тупо выражать ??= через ??, то получим бредовые ошибки.

IT>Какие именно бредовые? Если я буду делать тоже самое без макроса, то ошибки будут не бредовые?

Я про ошибки компилятора:

Error 1 expected option[int-]-, got int in assigned value: common super type of types [option[int-], int] is just `System.Object', please upcast one of the types to `System.Object' if this is desired E:\Ivan\Projects\MyOwn Projects\Nemerle Projects\Macro\Cns.MacroLibrary.Test\Main.n 78 9 Cns.MacroLibrary.Test
Error 2 there is no member named `HasValue' in System.Object- with type ? E:\Ivan\Projects\MyOwn Projects\Nemerle Projects\Macro\Cns.MacroLibrary.Test\Main.n 78 9 Cns.MacroLibrary.Test
Error 3 there is no member named `Value' in System.Object- with type ? E:\Ivan\Projects\MyOwn Projects\Nemerle Projects\Macro\Cns.MacroLibrary.Test\Main.n 78 9 Cns.MacroLibrary.Test

А по уму бы написать:

`5' should have type `option[int]'.

... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[10]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 15:20
Оценка:
Здравствуйте, ie, Вы писали:

ie>>>def b = a ?? 5; // тут тип int, а если тупо выражать ??= через ??, то получим бредовые ошибки.

IT>>Какие именно бредовые? Если я буду делать тоже самое без макроса, то ошибки будут не бредовые?

ie>Я про ошибки компилятора:


И я про тоже.

ie>А по уму бы написать:

ie>

ie>`5' should have type `option[int]'.


Так было бы совсем хорошо. Но как я понимаю, компилятору всё равно делается ли что-то неверно из макроса или прямо в коде. Ошибки будут одни и те же.

Конечно, лучше выдавать вменяемые ошибки. А ещё лучше, сделать самому приведение, если это возможно.
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 15:36
Оценка:
Здравствуйте, IT, Вы писали:

ie>>А по уму бы написать:

ie>>

ie>>`5' should have type `option[int]'.

IT>Так было бы совсем хорошо. Но как я понимаю, компилятору всё равно делается ли что-то неверно из макроса или прямо в коде. Ошибки будут одни и те же.

Если так написать:
def b = {when (a == null) a = 6; a};

, то хотя бы не будет сообщений про HasValue/Value. Хотя эти сообщение спецефично для option.

IT>Конечно, лучше выдавать вменяемые ошибки.


+100, а то эти невменяемые отмазки компилятора уже напрягают.

IT>А ещё лучше, сделать самому приведение, если это возможно.


Хмм. Какими правилами руководствоваться? Implicit и UpCast?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[12]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 15:48
Оценка:
Здравствуйте, ie, Вы писали:

IT>>Конечно, лучше выдавать вменяемые ошибки.

ie>+100, а то эти невменяемые отмазки компилятора уже напрягают.

Ну так займись Там поле не паханное. Всё равно с такой диагностикой ошибок как сейчас в релиз пускать компилятор рановато.

IT>>А ещё лучше, сделать самому приведение, если это возможно.

ie>Хмм. Какими правилами руководствоваться? Implicit и UpCast?

Я бы начал с рассмотрения частных случаев. Преобразование 5 к int? логично? Значит надо преобразовывать. И т.д.
Если нам не помогут, то мы тоже никого не пощадим.
Re[5]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 15:58
Оценка:
Здравствуйте, IT, Вы писали:

ie>>Ок.


IT>Теперь пора заняться '??='


Я бы не стал такое чудо вводить. Это только путать будет.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 15:58
Оценка:
Здравствуйте, IT, Вы писали:

IT>Нормальные задачи, например, отложенная инициализация свойст недефолтными значениями.


Это у тебя что свойство будет на ходу тип менять?

Единственное применение это:
def x : int? = null;
def x ::= 2;

что по-моему совершенно не очевидно и даже нелепо. В общем, я против такого.

Так:
def x : int? = null;
def x = x ?? 2;

понятнее, очевиднее и разницы практически никакой.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 15:58
Оценка:
Здравствуйте, IT, Вы писали:

IT>Если выражать через ??, то поведение должно быть примерно такое:


IT>
IT>mutable a;
IT>def b = a ?? { a = c; a };
IT>


Ты хоть сам то понял что написал? Я — нет.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 16:21
Оценка: +1
Здравствуйте, ie, Вы писали:

ie>Ну BaseType то есть, а значит как минимум IsSubclassOf или IsAssignableFrom достаточно просто реализуемы.


Реализуемо все. Но это надо реализовывать. Ладно видимо надо заняться.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 16:21
Оценка:
Здравствуйте, ie, Вы писали:

ie>Однока, спецификация C# так не считает, и в этом я с ней солидарен.

ie>
ie>int? p = null;
ie>int? q = null;
ie>if (p ?? q == 0); // тут мне 0 нафиг не нужен
ie>


Я незнаю что тебе "тут" не нужно. Но такой оператор не нужен никому. В нем просто нет смысла.


А вот где в спецификации C# такое написано мне было бы интересно поглядеть. Тыкни, плиз пальцем. Или процитируй.

А пока вот простенький тестик на C# 2.0:
using System;

class Program
{
    static void Main(string[] args)
    {
        int? a1 = null;
        int a2 = a1 ?? 2;
        Console.WriteLine(a2);
        Console.WriteLine((a1 ?? 2) == 2);
        Console.WriteLine((a1 ?? 2).GetType().FullName);
        a1 = 4;
        Console.WriteLine((a1 ?? 2) == 2);
        Console.WriteLine((a1 ?? 2).GetType().FullName);
    }
}

А вот его вывод:
2
True
System.Int32
False
System.Int32

Что-то мне не веритися, что в МС реализовали эту фичу не по спецификации.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 02.10.06 16:35
Оценка:
Здравствуйте, VladD2, Вы писали:

ie>>
ie>>int? p = null;
ie>>int? q = null;
ie>>if (p ?? q == 0); // тут мне 0 нафиг не нужен
ie>>

VD>Я незнаю что тебе "тут" не нужно. Но такой оператор не нужен никому. В нем просто нет смысла.

Смысл можно найти во всем, но то что такой случай редкость, спорить не буду.

VD>А вот где в спецификации C# такое написано мне было бы интересно поглядеть. Тыкни, плиз пальцем. Или процитируй.


The type of the expression a ?? b depends on which implicit conversions are available between the types
of the operands. In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a, B is the
type of b, and A0 is the type that results from removing the trailing ? modifier, if any, from A.
Specifically,
a ?? b is processed as follows:
• If A is not a nullable type or a reference type, a compile-time error occurs.
• If A is a nullable type and an implicit conversion exists from b to A0, the result type is A0. At run-time, a
is first evaluated. If a is not null, a is unwrapped to type A0, and this becomes the result. Otherwise, b is
evaluated and converted to type A0, and this becomes the result.
• Otherwise, if an implicit conversion exists from b to A, the result type is A. At run-time, a is first
evaluated. If a is not null, a becomes the result. Otherwise, b is evaluated and converted to type A, and
this becomes the result.

• Otherwise, if an implicit conversion exists from A0 to B, the result type is B. At run-time, a is first
evaluated. If a is not null, a is unwrapped to type A0 (unless A and A0 are the same type) and converted
to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.
Otherwise, a and b are incompatible, and a compile-time error occurs.


Т.е. если оператор применяется к 2-м nullable, то результатом всегда будет nullable.

VD>А пока вот простенький тестик на C# 2.0:

VD>
VD>        int? a1 = null;
VD>        int a2 = a1 ?? 2;
VD>        Console.WriteLine(a2);
VD>        Console.WriteLine((a1 ?? 2) == 2);
VD>        Console.WriteLine((a1 ?? 2).GetType().FullName);
VD>        a1 = 4;
VD>        Console.WriteLine((a1 ?? 2) == 2);
VD>        Console.WriteLine((a1 ?? 2).GetType().FullName);
VD>}
VD>

VD>А вот его вывод:
VD>
VD>2
VD>True
VD>System.Int32
VD>False
VD>System.Int32
VD>


Дык, тут как раз попадаем под 2-ой пункт, где B приводимо к A0, т.к. A == int?, A0 == int, B == int.

VD>Что-то мне не веритися, что в МС реализовали эту фичу не по спецификации.


Да нет, сам проверял, все по спецификации.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[6]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 17:02
Оценка:
Здравствуйте, VladD2, Вы писали:

IT>>Теперь пора заняться '??='


VD>Я бы не стал такое чудо вводить. Это только путать будет.


А ?? не путает? Боюсь, что не путает только потому, что это уже есть в C#.
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 17:05
Оценка:
Здравствуйте, VladD2, Вы писали:

IT>>Нормальные задачи, например, отложенная инициализация свойст недефолтными значениями.


VD>Это у тебя что свойство будет на ходу тип менять?


Это как У нас же статически типизированный язык. Недефолтное значит, что string может равняться не string.Empty, а "something else".

VD>Единственное применение это:

VD>
VD>def x : int? = null;
VD>def x ::= 2;
VD>

VD>что по-моему совершенно не очевидно и даже нелепо. В общем, я против такого.

Против такого я тоже против
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 17:17
Оценка: +2
Здравствуйте, VladD2, Вы писали:

IT>>Если выражать через ??, то поведение должно быть примерно такое:


IT>>
IT>>mutable a;
IT>>def b = a ?? { a = c; a };
IT>>


VD>Ты хоть сам то понял что написал? Я — нет.


Все поняли, а он нет Ладно, специально для особо непонятливых примеры из жизни:

Nemerle.VsIntegration -> SourceTextManager, line 37-46:

private NemerleSource _source;
public  NemerleSource  Source
{
    get
    {
        if (_source == null)
            _source = (NemerleSource)_service.GetSource(TextLines);
        return _source;
    }
}

Или вот, например, NemerleProjectNode, line 137-145:

protected internal VSLangProj.VSProject VSProject
{
    get
    {
        if (_vsProject == null)
            _vsProject = new OAVSProject(this);
        return _vsProject;
    }
}

Пока я рефакторил C# проект таких мест было обнаружено вагон и маленькая тележка. Заменить это всё можно было на такое:

private NemerleSource _source;
public  NemerleSource  Source
{
    get { return _source ??= (NemerleSource)_service.GetSource(TextLines); }
}

Или вот, например, NemerleProjectNode, line 137-145:

protected internal VSLangProj.VSProject VSProject
{
    get { _vsProject ??= new OAVSProject(this); }
}

По-моему, более чем понятно что здесь происходит.
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 22:19
Оценка:
Здравствуйте, IT, Вы писали:

VD>>Единственное применение это:

VD>>
VD>>def x : int? = null;
VD>>def x ::= 2;
VD>>

VD>>что по-моему совершенно не очевидно и даже нелепо. В общем, я против такого.

IT>Против такого я тоже против


Тут имелос в виду "def x ??= 2;"

Я решительно не понимаю что ты хочешь. По-моему идея оператора ??= — плохая идея.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 22:19
Оценка:
Здравствуйте, IT, Вы писали:
IT>
IT>private NemerleSource _source;
IT>public  NemerleSource  Source
IT>{
IT>    get { return _source ??= (NemerleSource)_service.GetSource(TextLines); }
IT>}
IT>

IT>Или вот, например, NemerleProjectNode, line 137-145:

IT>
IT>protected internal VSLangProj.VSProject VSProject
IT>{
IT>    get { _vsProject ??= new OAVSProject(this); }
IT>}
IT>

IT>По-моему, более чем понятно что здесь происходит.

Мне это решительно не нравится. Такое "сокращение" резко усложнит понимание. Оно не интуитивно. И практически ничего не дает. Так как таких пест впрограмме не много. Если тебе уж хочется автоматизировать подобные вещи, то лучше создай просто фукнцию типа:
AutoInit[T](var : ref T, creator : void) : T
    where T: class
{
    when (var == null)
        var = creator();
    
    var;
}

тогда хотя бы будет понятно что присходит и не будет лишней сущьности.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 22:19
Оценка:
Здравствуйте, IT, Вы писали:

IT>А ?? не путает? Боюсь, что не путает только потому, что это уже есть в C#.


?? интуитивно понятен и не создает странного побочного эффекта. В общем, я все болше и больше против такого расширения. Это идея от избытка возможностей. Совершенно лишняя, по-моему.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.06 22:19
Оценка:
Здравствуйте, ie, Вы писали:

ie>Смысл можно найти во всем, но то что такой случай редкость, спорить не буду.


Ну, так поясни мне его. А то я его не вижу в упор. Если речь идет не о nullable-типах, а о ссылочных, то это другое дело. Ты все равно это как частный случай обрабатываешь.

ie>Да нет, сам проверял, все по спецификации.


С Some() у тебя точно ерунда выходит, так как из него точно никаких неявных приведений типов нет. Так что это по любому ошибка.

В отношении nullable-типов что-то я пока торможу. Может ты и прав. Надо не спросони еще раз проанализировать.

Так что по крайней мере разберись с Some(x)/None().
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 23:18
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Мне это решительно не нравится. Такое "сокращение" резко усложнит понимание. Оно не интуитивно. И практически ничего не дает.


А '??' тебе нравится? Такое сокращение не резко усложняет понимание? Оно интуитивно? Практически что-то делает?

Боюсь, что у этого сокращения есть только один плюс — оно уже в C#, поэтому включение аналога в N не вызывает такого негодования. Стоило предложить, все покивали головами и тут же побежали его делать. '??=' при наличии '??' — это уже не так страшно, поверь мне. Если понимать, что такое первые два '??', то '=' проблем уже не вызывает. Впрочем, мне всё равно, но на реакцию, основанную исключительно на личных предпочтениях, посмотреть было забавно

VD>Так как таких пест впрограмме не много.


Ты их все сосчитал? Только в своём коде? Осталось только добавить, что это вообще плохой паттерн, назвать его бредом и заклеймить всех, кто его использует
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 02.10.06 23:33
Оценка:
Здравствуйте, VladD2, Вы писали:

IT>>А ?? не путает? Боюсь, что не путает только потому, что это уже есть в C#.


VD>?? интуитивно понятен




Нифига он не понятен. Ставил эксперименты над несколькими людьми. Ни один человек сходу интуитивно не понял. Ни один!

VD>и не создает странного побочного эффекта.


Как насчёт: '::=', '&=', '|=' и даже '='? Они тоже создают странные побочные эффекты?

VD>В общем, я все болше и больше против такого расширения. Это идея от избытка возможностей. Совершенно лишняя, по-моему.


Да ради бога, я и не настаиваю. Смешно только смотреть, как странные фичи от MS воспринимаются с открытым ртом, а такие же по странности, но другие отвергаются с негодованием. Если уж на то пошло, то хотя я и предложил добавить '??' в N, но шедевром этот оператор не считаю. А уж в N без короткого if — ?:, он вовсе нелогичен и ему там вообще делать нечего.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 03.10.06 09:03
Оценка:
Здравствуйте, VladD2, Вы писали:

ie>>Смысл можно найти во всем, но то что такой случай редкость, спорить не буду.


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


Например такой:

def GetValue(p) : int?
{
    // возвращаем зависимое от p значение
}
...
...
foreach (i in $[1..20])
  res = res ?? GetValue(i); // мож сделать оператор '=??' в догонку к '??' и '??=' ?  :)))


Ситуация конечно надуманная, но я не исключаю возможности ее возникновения. Аналогично с option.

VD>С Some() у тебя точно ерунда выходит, так как из него точно никаких неявных приведений типов нет. Так что это по любому ошибка.


Дык, из nullable тоже нет никаких неявных приведений.

VD>Так что по крайней мере разберись с Some(x)/None().


Я бы разобрался, но тоже не могу понять как правильно то надо?

Не зависимо от того является ли второй операнд option, возвращать Value? — А что тогда делать если оба None?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[9]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 03.10.06 09:05
Оценка:
Здравствуйте, IT, Вы писали:

IT>>>А ?? не путает? Боюсь, что не путает только потому, что это уже есть в C#.

VD>>?? интуитивно понятен
IT>
IT>Нифига он не понятен. Ставил эксперименты над несколькими людьми. Ни один человек сходу интуитивно не понял. Ни один!

Какого плана экспиримент? Только что спросил джависта, то ли у них там в джаве что-то похожее есть, но со второй попытки угадал. (Первая была: "какой-то муд@к полез ставить && в русской раскладке" )

VD>>В общем, я все болше и больше против такого расширения. Это идея от избытка возможностей. Совершенно лишняя, по-моему.

IT>Да ради бога, я и не настаиваю. Смешно только смотреть, как странные фичи от MS воспринимаются с открытым ртом, а такие же по странности, но другие отвергаются с негодованием. Если уж на то пошло, то хотя я и предложил добавить '??' в N, но шедевром этот оператор не считаю. А уж в N без короткого if — ?:, он вовсе нелогичен и ему там вообще делать нечего.

Эээ, а причем тут кототкий if?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[10]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 03.10.06 12:09
Оценка: +1
Здравствуйте, ie, Вы писали:

ie>Эээ, а причем тут кототкий if?


При том, что ?? — это расширение оператора ?:, которого в N нет, т.е. пропущен один шаг эволюции
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 03.10.06 12:34
Оценка:
Здравствуйте, IT, Вы писали:

ie>>Эээ, а причем тут кототкий if?

IT>При том, что ?? — это расширение оператора ?:, которого в N нет, т.е. пропущен один шаг эволюции

Ну прям, скажешь тоже.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[9]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.10.06 13:57
Оценка:
Здравствуйте, IT, Вы писали:

IT>Нифига он не понятен. Ставил эксперименты над несколькими людьми. Ни один человек сходу интуитивно не понял. Ни один!


А ты им сказал что он должен делать? Я вот прочтя строчку описания и поглядев пример сразу понял о чем идет речь.

VD>>и не создает странного побочного эффекта.


IT>Как насчёт: '::=', '&=', '|=' и даже '='? Они тоже создают странные побочные эффекты?


Отлично. Эти операторы принимают и возвращают значение одного и того же пипа, а ?? разного.

Так что как насчет :=, :>= и прочего бред?

IT>Да ради бога, я и не настаиваю.


Ну, и отлично, так как я категорически против этого извращения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.10.06 13:57
Оценка:
Здравствуйте, IT, Вы писали:

IT, операторы с побочными эффектаи это просто уму невоброзимо. Ненадо гробить язык и портить код проектов.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.10.06 13:57
Оценка:
Здравствуйте, ie, Вы писали:

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


ie>>>Смысл можно найти во всем, но то что такой случай редкость, спорить не буду.


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


ie>Например такой:


ie>
ie>def GetValue(p) : int?
ie>{
ie>    // возвращаем зависимое от p значение
ie>}
ie>...
ie>...
ie>foreach (i in $[1..20])
ie>  res = res ?? GetValue(i); // мож сделать оператор '=??' в догонку к '??' и '??=' ?  :))) 
ie>


ie>Ситуация конечно надуманная, но я не исключаю возможности ее возникновения. Аналогично с option.


Ситуация не надоуманная, а бредовая. Да и преимер не определен. Что за тип у res?

Что касается оперовтов =??, ??=. Я гляжу у вас ребяты от избытка возможностей крушу рвет. Возмите себя в руки. Новшества не должны создавать проблем. Они должны решать имеющиеся. "Крутость" ни в коем случае не долнжна становиться аспектом выбора.

VD>>С Some() у тебя точно ерунда выходит, так как из него точно никаких неявных приведений типов нет. Так что это по любому ошибка.


ie>Дык, из nullable тоже нет никаких неявных приведений.


Как же нет если 'int?' по твоим же словам приводится к 'int' ?

VD>>Так что по крайней мере разберись с Some(x)/None().


ie>Я бы разобрался, но тоже не могу понять как правильно то надо? \


Я тебе уеж говорил. Забей на всесь булшит что ты начитался в стандарте и сделай тупо:
<[ mattch ($value1) { Some| (x) => x | None() => $defValue } ]>


ie>Не зависимо от того является ли второй операнд option, возвращать Value? — А что тогда делать если оба None?


Просто рассчитывать на то что второй аргумент не можут быть option[]. Я даже представить не могу разумного использования такой ситуации. Если кому-то надо возвратить option[] пусть использует паттерн-матчинг.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 03.10.06 16:12
Оценка:
Здравствуйте, VladD2, Вы писали:

ie>>
ie>>def GetValue(p) : int?
ie>>{
ie>>    // возвращаем зависимое от p значение
ie>>}
ie>>...
ie>>...
ie>>foreach (i in $[1..20])
ie>>  res = res ?? GetValue(i); // мож сделать оператор '=??' в догонку к '??' и '??=' ?  :))) 
ie>>


ie>>Ситуация конечно надуманная, но я не исключаю возможности ее возникновения. Аналогично с option.

VD>Ситуация не надоуманная, а бредовая.

Спасибо, сам боялся себе признаться, что я брежу.

VD>Да и преимер не определен.


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

VD>Что за тип у res?


Разве не очевидно? 'int?'

VD>Что касается оперовтов =??, ??=. Я гляжу у вас ребяты от избытка возможностей крушу рвет. Возмите себя в руки. Новшества не должны создавать проблем. Они должны решать имеющиеся. "Крутость" ни в коем случае не долнжна становиться аспектом выбора.


Ты смайлик видел?

VD>>>С Some() у тебя точно ерунда выходит, так как из него точно никаких неявных приведений типов нет. Так что это по любому ошибка.

ie>>Дык, из nullable тоже нет никаких неявных приведений.
VD>Как же нет если 'int?' по твоим же словам приводится к 'int' ?

По каким словам?
Неявно можно привести 'int' к 'int?', но не наоборот. Наоборот, только используя явное привидение.

VD>Я тебе уеж говорил. Забей на всесь булшит что ты начитался в стандарте и сделай тупо:

VD>
VD><[ mattch ($value1) { Some| (x) => x | None() => $defValue } ]>
VD>


Вот это точно ерунда. o1 ?? o2 — где тут $value1, а где тут $defValue? И вообще, куда ты дел o2?

ie>>Не зависимо от того является ли второй операнд option, возвращать Value? — А что тогда делать если оба None?

VD>Просто рассчитывать на то что второй аргумент не можут быть option[]. Я даже представить не могу разумного использования такой ситуации. Если кому-то надо возвратить option[] пусть использует паттерн-матчинг.

Так из-за чего сыр-бор то???
Если ты второй аргумент не option, то работать будет так, как ты и хочешь, не используй с option в качестве второго аргумента и будет тебе счастье.

def x = Some (1);
def y = Some (2);
def z = x ?? y ?? 3; // у 'z' будет тип 'int'
... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[10]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 03.10.06 17:23
Оценка:
Здравствуйте, VladD2, Вы писали:

IT>>Нифига он не понятен. Ставил эксперименты над несколькими людьми. Ни один человек сходу интуитивно не понял. Ни один!


VD>А ты им сказал что он должен делать?


Зачем? Всё же интуитивно понятно

VD>>>и не создает странного побочного эффекта.

IT>>Как насчёт: '::=', '&=', '|=' и даже '='? Они тоже создают странные побочные эффекты?
VD>Отлично. Эти операторы принимают и возвращают значение одного и того же пипа, а ?? разного.

Кто сказал разного? Я такого не говорил. Впрочем вот это:

int? n = 0;
n &= 1;

работает без проблем.

VD>Так что как насчет :=, :>= и прочего бред?


К чему это всё? Боюсь, ты опять что-то недопонял и решил додумать по своему.

IT>>Да ради бога, я и не настаиваю.


VD>Ну, и отлично, так как я категорически против этого извращения.


Почему же ты не против извращения '??' ?
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: [Nemerle] The null coalescing operator
От: IT Россия linq2db.com
Дата: 03.10.06 17:24
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>IT, операторы с побочными эффектаи это просто уму невоброзимо. Ненадо гробить язык и портить код проектов.


Какие ещё побочные эффекты? Ты мне можешь объяснить что ты там сам себе нафантазировал?
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.10.06 00:06
Оценка:
Здравствуйте, ie, Вы писали:

ie>Если ты второй аргумент не option, то работать будет так, как ты и хочешь, не используй с option в качестве второго аргумента и будет тебе счастье.


ie>
ie>def x = Some (1);
ie>def y = Some (2);
ie>def z = x ?? y ?? 3; // у 'z' будет тип 'int'
ie>


Что-то я не вижу как твой код
Автор: ie
Дата: 29.09.06
это обеспечит.
Ты тесты делал?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 04.10.06 03:42
Оценка:
Здравствуйте, VladD2, Вы писали:

ie>>Если ты второй аргумент не option, то работать будет так, как ты и хочешь, не используй с option в качестве второго аргумента и будет тебе счастье.


ie>>
ie>>def x = Some (1);
ie>>def y = Some (2);
ie>>def z = x ?? y ?? 3; // у 'z' будет тип 'int'
ie>>


VD>Что-то я не вижу как твой код
Автор: ie
Дата: 29.09.06
это обеспечит.


x ?? y ?? 3 == x ?? (y ?? 3)

y — option[int], 3 — int, (option[int] ?? int) — int => (y ?? 3) — int
x — option[int] => x ?? (y ?? 3) — int => x ?? y ?? 3 — int

VD>Ты тесты делал?


Естественно, вот эти тесты отрабатываю на ура:

assert (on ?? o1 ?? o2 ?? 3 == 1);
assert (GetExprType(on ?? o1 ?? o2 ?? 3).Equals (typeof (int)));
WriteLine($"$(on ?? o1 ?? o2 ?? 3)");

assert (on ?? on ?? on ?? 3 == 3);
assert (GetExprType(on ?? on ?? on ?? 3).Equals (typeof (int)));
WriteLine($"$(on ?? on ?? on ?? 3)");
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[14]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.10.06 13:56
Оценка:
Здравствуйте, ie, Вы писали:

VD>>Ты тесты делал?


ie>Естественно, вот эти тесты отрабатываю на ура:


ie>
ie>assert (on ?? o1 ?? o2 ?? 3 == 1);
ie>assert (GetExprType(on ?? o1 ?? o2 ?? 3).Equals (typeof (int)));
ie>WriteLine($"$(on ?? o1 ?? o2 ?? 3)");

ie>assert (on ?? on ?? on ?? 3 == 3);
ie>assert (GetExprType(on ?? on ?? on ?? 3).Equals (typeof (int)));
ie>WriteLine($"$(on ?? on ?? on ?? 3)");
ie>


Это не то что нужно. Нужно:
def a : option[int] = None();
def b : int = a ?? 2;
assert((a ?? 2).GetType().FullName == "System.Int32");
assert(a ?? 2 == 2);

def a : option[int] = Some(1);
def b : int = a ?? 2;
assert((a ?? 2).GetType().FullName == "System.Int32");
assert(a ?? 2 == 1);


PS

И логики работы с option[] я все равно не понял.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: [Nemerle] The null coalescing operator
От: ie Россия http://ziez.blogspot.com/
Дата: 04.10.06 14:35
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это не то что нужно. Нужно:

VD>
VD>def a : option[int] = None();
VD>def b : int = a ?? 2;
VD>assert((a ?? 2).GetType().FullName == "System.Int32");
VD>assert(a ?? 2 == 2);

VD>def a : option[int] = Some(1);
VD>def b : int = a ?? 2;
VD>assert((a ?? 2).GetType().FullName == "System.Int32");
VD>assert(a ?? 2 == 1);
VD>


Ну да, это и так есть
Кстати, несколько дней назад я закомитил оператор в svn, можешь свои догадки относительно работы легко проверить.

VD>PS

VD>И логики работы с option[] я все равно не понял.

Ну все же вроде просто, 2 правила:

option['t] ?? 't -> 't
option['t] ?? option['t] -> option['t]

... << RSDN@Home 1.2.0 alpha rev. 655>>
Превратим окружающую нас среду в воскресенье.
Re[16]: [Nemerle] The null coalescing operator
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.10.06 22:03
Оценка:
Здравствуйте, ie, Вы писали:

ie>Ну да, это и так есть

ie>Кстати, несколько дней назад я закомитил оператор в svn, можешь свои догадки относительно работы легко проверить.

ОК, так и сделаю. Но чуть позже.
ie>Ну все же вроде просто, 2 правила:

ie>

ie>option['t] ?? 't -> 't
ie>option['t] ?? option['t] -> option['t]


Вот первого я что-то и не вижу. Возможно плохо смотрел. Но...
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.