Варианты и свойства
От: _FRED_ Черногория
Дата: 29.03.11 04:59
Оценка:
Я как-то возмущался, что в Немероле используются поля тогда, когда кошерно использовать свойства.
Сейчас поигрался, вижу что с рекордами в этом отношении всё отлично: можно объявлять свойства, по ним работаем паттерн-матчинг (только простые кейсы попробовал, буду надеяться, что работает всё).

С вариантами такое не прокатывает. Но подробнее. Рассмотрим сначала такой вот вариант:
variant Color
{
  | Red
  | Green
  | Blue
}


Из него получается
internal abstract class Color
{
  // Methods
  protected Color();
  public abstract override int _N_GetVariantCode();
  public static int _N_GetVariantCodeObject(object x);
  public static int _N_GetVariantCodeSafe(Color x);

 internal protected sealed class Blue : Color { }
 …


Если бы мне пришлось выписывать вариант "руками", то я сделал бы немного иначе:

Далее. Дополняем вариант:

variant Color
{
  | Red
  | Green
  | Blue
  | Custom {
      Red : int
  }
}

и получаем:

Warning: field: Red : int; hides 'Color.Red' but neither 'override' nor 'new' is specified
Warning: hint: hiden definition


Ничто не мешает компилятору самостоятельно добавить "new" к объявлению поля. То, что вариант реализуется посредством наследования можно вообще считать деталью реализации компилятора.

Теперь делаем так:

variant Color
{
  | Red
  | Green
  | Blue
  | Custom {
      Red : int { get; private set; }
  }
}

module Program
{
  W() : Color {
    Color.Custom(1)
  }

  Main() : void
  {
    def color = W();
    match(color) {
      | Color.Red => WriteLine("Red")
      | Color.Green => WriteLine("Green")
      | Color.Blue => WriteLine("Blue")
      | Color.Custom(red) => WriteLine("Red: {0}", red)
    }//match

    _ = ReadLine();
  }
}

И это не компилируется:

Error: pattern matches 1 values, while the type 'Color.Custom' has 0 fields
Error: unbound name 'red'

Сложно исправить?

Кстати, почему, если написать код вот так:
module Program
{
  Main() : void
  {
    def color = Color.Custom(1);
    match(color) {
      | Color.Red => WriteLine("Red")
      | Color.Green => WriteLine("Green")
      | Color.Blue => WriteLine("Blue")
      | Color.Custom(red) => WriteLine("Red: {0}", red)
    }//match
  }
}

public variant Color
{
  | Red
  | Green
  | Blue
  | Custom {
      Red : int
  }
}

то получаем целый ворох ошибок:

Error: the matched value type Color.Custom was expected to be compatible with Color.Red: Color.Red is not a subtype of Color.Custom [simple require]
Error: the matched value type Color.Custom was expected to be compatible with Color.Green: Color.Green is not a subtype of Color.Custom [simple require]
Error: the matched value type Color.Custom was expected to be compatible with Color.Blue: Color.Blue is not a subtype of Color.Custom [simple require]
Warning: this match clause is unused
Warning: this match clause is unused
Warning: this match clause is unused

Help will always be given at Hogwarts to those who ask for it.
Re: Варианты и свойства
От: hardcase Пират http://nemerle.org
Дата: 29.03.11 05:46
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Если бы мне пришлось выписывать вариант "руками", то я сделал бы немного иначе:

_FR>
Защищенный конструктор — это по-видимому просто недоделка. Думаю легко можно поправить на приватный .

_FR>Ничто не мешает компилятору самостоятельно добавить "new" к объявлению поля. То, что вариант реализуется посредством наследования можно вообще считать деталью реализации компилятора.


Не вижу проблемы в этом сообщении компилятора.

_FR>И это не компилируется:

_FR>

_FR>Error: pattern matches 1 values, while the type 'Color.Custom' has 0 fields
_FR>Error: unbound name 'red'

_FR> Сложно исправить?

Да. Теперь объясни политику матча таких вещей:
variant Foo
{
  | Baz
  | Bar
  {
    public X { get; }
    public Y { get { X + 1 } }
  }
}


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


_FR>Кстати, почему, если написать код вот так:

_FR>[nemerle]
_FR>module Program
_FR>{
_FR> Main() : void
_FR> {
_FR> def color = Color.Custom(1);
_FR> match(color) {
_FR> | Color.Red => WriteLine("Red")
_FR> | Color.Green => WriteLine("Green")
_FR> | Color.Blue => WriteLine("Blue")
_FR> | Color.Custom(red) => WriteLine("Red: {0}", red)
_FR> }//match
_FR> }
_FR>}

Потому что тип color : Color.Custom и потому его бессмысленно матчить на Color.Red, Color.Green и Color.Blue.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Варианты и свойства
От: _FRED_ Черногория
Дата: 29.03.11 06:02
Оценка:
Здравствуйте, hardcase, Вы писали:

_FR>>Ничто не мешает компилятору самостоятельно добавить "new" к объявлению поля. То, что вариант реализуется посредством наследования можно вообще считать деталью реализации компилятора.

H>Не вижу проблемы в этом сообщении компилятора.

А, понятно.

_FR>> Сложно исправить?

H>Да. Теперь объясни политику матча таких вещей:
H>variant Foo
H>{
H>  | Baz
H>  | Bar
H>  {
H>    public X { get; }
H>    public Y { get { X + 1 } }
H>  }
H>}


Что такое "public X { get; }" без сеттера? Имеется в виду { get; private set; } как у меня?
Во-вторых, как я понимаю, в паттерне Color.Custom(red) "red" матчится по параметру конструктора, то есть в этой форме X будет матчится понятно как, а Y, наверное, никак. А сейчас в Немерлое что, нельзя заматчить самый обычный объект по его свойствам? Синтаксис такого матча придумать не очень сложно.
В-третьих: X в данном случае матчиться может. Я не просил добавлять возможность матча по Y в примере. Я прошу возможность матча по X. А такая возможность есть, потому что компилятор знает о зависимости свойства X и первого параметра образца.

H>В любом случае такие изменения сейчас в компилятор внедрять не будем.


А, понятно.

_FR>>Кстати, почему, если написать код вот так:

_FR>>[nemerle]
_FR>>module Program
_FR>>{
_FR>> Main() : void
_FR>> {
_FR>> def color = Color.Custom(1);
_FR>> match(color) {
_FR>> | Color.Red => WriteLine("Red")
_FR>> | Color.Green => WriteLine("Green")
_FR>> | Color.Blue => WriteLine("Blue")
_FR>> | Color.Custom(red) => WriteLine("Red: {0}", red)
_FR>> }//match
_FR>> }
_FR>>}

H>Потому что тип color : Color.Custom и потому его бессмысленно матчить на Color.Red, Color.Green и Color.Blue.


В таком случае компиляторы обычно выдают одно предупреждение (ну лано, тут можно и схалтурить и выдать три ворнинга), а не три ошибки + три предупреждения
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Варианты и свойства
От: hardcase Пират http://nemerle.org
Дата: 29.03.11 06:13
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Что такое "public X { get; }" без сеттера? Имеется в виду { get; private set; } как у меня?


Это get-only свойство, Nemerle дозволяет их объявлять.

_FR>Во-вторых, как я понимаю, в паттерне Color.Custom(red) "red" матчится по параметру конструктора, то есть в этой форме X будет матчится понятно как, а Y, наверное, никак. А сейчас в Немерлое что, нельзя заматчить самый обычный объект по его свойствам? Синтаксис такого матча придумать не очень сложно.


Можно — через оператор where.

_FR>В-третьих: X в данном случае матчиться может. Я не просил добавлять возможность матча по Y в примере. Я прошу возможность матча по X. А такая возможность есть, потому что компилятор знает о зависимости свойства X и первого параметра образца.


H>>В любом случае такие изменения сейчас в компилятор внедрять не будем.


_FR>А, понятно.


Это чисто технически сложно (много кода нужно править), к ближайшему релизу (кстати, где он?) делать не будем, а в качестве рефреша (Nemerle 1.1) я думаю можно.

_FR>>>Кстати, почему, если написать код вот так:

_FR>>>[nemerle]
_FR>>>module Program
_FR>>>{
_FR>>> Main() : void
_FR>>> {
_FR>>> def color = Color.Custom(1);
_FR>>> match(color) {
_FR>>> | Color.Red => WriteLine("Red")
_FR>>> | Color.Green => WriteLine("Green")
_FR>>> | Color.Blue => WriteLine("Blue")
_FR>>> | Color.Custom(red) => WriteLine("Red: {0}", red)
_FR>>> }//match
_FR>>> }
_FR>>>}

H>>Потому что тип color : Color.Custom и потому его бессмысленно матчить на Color.Red, Color.Green и Color.Blue.


_FR>В таком случае компиляторы обычно выдают одно предупреждение (ну лано, тут можно и схалтурить и выдать три ворнинга), а не три ошибки + три предупреждения


Там warning-и точно лишние
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Варианты и свойства
От: _FRED_ Черногория
Дата: 29.03.11 06:50
Оценка:
Здравствуйте, hardcase, Вы писали:

_FR>>Что такое "public X { get; }" без сеттера? Имеется в виду { get; private set; } как у меня?

H>Это get-only свойство, Nemerle дозволяет их объявлять.

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

_FR>>Во-вторых, как я понимаю, в паттерне Color.Custom(red) "red" матчится по параметру конструктора, то есть в этой форме X будет матчится понятно как, а Y, наверное, никак. А сейчас в Немерлое что, нельзя заматчить самый обычный объект по его свойствам? Синтаксис такого матча придумать не очень сложно.

H>Можно — через оператор where.

Тогда не понимаю, что мешает реализовать матчинг для Bar X матчится как параметр конструктора, Y через where

_FR>>В-третьих: X в данном случае матчиться может. Я не просил добавлять возможность матча по Y в примере. Я прошу возможность матча по X. А такая возможность есть, потому что компилятор знает о зависимости свойства X и первого параметра образца.

H>>>В любом случае такие изменения сейчас в компилятор внедрять не будем.
_FR>>А, понятно.
H>Это чисто технически сложно (много кода нужно править), к ближайшему релизу (кстати, где он?) делать не будем, а в качестве рефреша (Nemerle 1.1) я думаю можно.

Если дело просто в сложности — это одно. Главное, что бы было понятие о нужности.

_FR>>>>Кстати, почему, если написать код вот так:

_FR>>>>module Program
_FR>>>>{
_FR>>>>  Main() : void
_FR>>>>  {
_FR>>>>    def color = Color.Custom(1);
_FR>>>>    match(color) {
_FR>>>>      | Color.Red => WriteLine("Red")
_FR>>>>      | Color.Green => WriteLine("Green")
_FR>>>>      | Color.Blue => WriteLine("Blue")
_FR>>>>      | Color.Custom(red) => WriteLine("Red: {0}", red)
_FR>>>>    }//match
_FR>>>>  }
_FR>>>>}

H>>>Потому что тип color : Color.Custom и потому его бессмысленно матчить на Color.Red, Color.Green и Color.Blue.
_FR>>В таком случае компиляторы обычно выдают одно предупреждение (ну лано, тут можно и схалтурить и выдать три ворнинга), а не три ошибки + три предупреждения
H>Там warning-и точно лишние

Так почему это ошибка-то?
Help will always be given at Hogwarts to those who ask for it.
Re[5]: Варианты и свойства
От: hardcase Пират http://nemerle.org
Дата: 29.03.11 07:26
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Кстати, при отсутствии явно заданного пользователем конструктора для типа с таким свойством я бы генерил два конструктора: один по-умолчанию, другой: в котором на каждое такое свойство есть параметр со значением по-умолчанию.


Зачем?

_FR>Тогда не понимаю, что мешает реализовать матчинг для Bar X матчится как параметр конструктора, Y через where


Тем что работа с одними и теми же сущностями — свойствами. Будет происходить различным образом. Одни свойства можно будет использовать в паттерне "конструктор", а другие — нет. Совместно их использовать можно будет лишь в паттерне "объект".

_FR>Если дело просто в сложности — это одно. Главное, что бы было понятие о нужности.


Вот кстати с нужностью и проблема Мне необходимость в таком изменении совсем не очевидна.

_FR>Так почему это ошибка-то?


Компилятор ясно выразился:

Error: the matched value type Color.Custom was expected to be compatible with Color.Red: Color.Red is not a subtype of Color.Custom [simple require]

Тип переменной color : Color.Custom, который не является супертипом Color.Red. Чтобы твой код заработал достаточно указать базовый тип в одном из двух мест:
1) я предпочитаю этот способ
    def color = Color.Custom(1);
    match(color : Color) {
      | Red => WriteLine("Red")
      | Green => WriteLine("Green")
      | Blue => WriteLine("Blue")
      | Custom(red) => WriteLine($"Red: $red")
    }

либо
2)
    def color : Color = Color.Custom(1);
    match(color) {
      | Red => WriteLine("Red")
      | Green => WriteLine("Green")
      | Blue => WriteLine("Blue")
      | Custom(red) => WriteLine($"Red: $red")
    }
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Варианты и свойства
От: _FRED_ Черногория
Дата: 29.03.11 07:37
Оценка:
Здравствуйте, hardcase, Вы писали:

_FR>>Кстати, при отсутствии явно заданного пользователем конструктора для типа с таким свойством я бы генерил два конструктора: один по-умолчанию, другой: в котором на каждое такое свойство есть параметр со значением по-умолчанию.

H>Зачем?

Затем, что если в классе есть такое свойство и не определён конструктор, то установить значение такого свойства извне не представляется возможным. Или как-то можно?

_FR>>Тогда не понимаю, что мешает реализовать матчинг для Bar X матчится как параметр конструктора, Y через where

H>Тем что работа с одними и теми же сущностями — свойствами. Будет происходить различным образом. Одни свойства можно будет использовать в паттерне "конструктор", а другие — нет. Совместно их использовать можно будет лишь в паттерне "объект".

Будет различными. И это более чем объяснимо: природа свойств различна: одно инициализируется через конструктор, другое нет.

_FR>>Если дело просто в сложности — это одно. Главное, что бы было понятие о нужности.

H>Вот кстати с нужностью и проблема Мне необходимость в таком изменении совсем не очевидна.

А, понятно.

_FR>>Так почему это ошибка-то?

H>Компилятор ясно выразился:

Ну в общем ясно.
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Варианты и свойства
От: hardcase Пират http://nemerle.org
Дата: 29.03.11 07:42
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Затем, что если в классе есть такое свойство и не определён конструктор, то установить значение такого свойства извне не представляется возможным. Или как-то можно?


Макрос Record генерирует конструктор, в котором учитываются автоматические свойства.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[8]: Варианты и свойства
От: _FRED_ Черногория
Дата: 29.03.11 07:54
Оценка:
Здравствуйте, hardcase, Вы писали:

_FR>>Затем, что если в классе есть такое свойство и не определён конструктор, то установить значение такого свойства извне не представляется возможным. Или как-то можно?


H>Макрос Record генерирует конструктор, в котором учитываются автоматические свойства.


В нём учитываются, если я правильно понимаю, все свойства. Кстати, а Record не генерит ToString() если та не определена? В общем, Record — это скорее некая отдельная сущность и вот тут смешивать одно с другим совсем не к чему. Но это конечно же ваше дело.
Help will always be given at Hogwarts to those who ask for it.
Re[9]: Варианты и свойства
От: hardcase Пират http://nemerle.org
Дата: 29.03.11 08:24
Оценка:
Здравствуйте, _FRED_, Вы писали:

H>>Макрос Record генерирует конструктор, в котором учитываются автоматические свойства.


_FR>В нём учитываются, если я правильно понимаю, все свойства.


Record генерирует конструкторы, которые наследуют все конструкторы предка + добавляет параметры для полей и автоматических свойств.

_FR>Кстати, а Record не генерит ToString() если та не определена?


Тут
Автор: para
Дата: 06.03.11
уже спрашивали уже про ToString. Готового макроса для перекрытия ToString нету — это слишком частная операция.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Варианты и свойства
От: BogdanMart Украина  
Дата: 29.03.11 11:58
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Я как-то возмущался, что в Немероле используются поля тогда, когда кошерно использовать свойства.


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