Nemerle Enhancement Proposal 1
От: _nn_ www.nemerleweb.com
Дата: 16.11.10 10:30
Оценка:
Nemerle Enhancement Proposal 1

Проблема:
В C# и в Nemerle мы имеем возможность определить свойства похожим образом включая автосвойства.
Но ни в C# ни в Nemerle нет возможности задать в автосвойстве только getter. (или только setter, кому оно надо не знаю )

Для этой цели в C# надо писать поле и свойство, а в Nemerle можно сократить работу за счет макроатрибута:
_i : int;
I : int { get { _i } };

mutable _j : int;
J : int { get { _j } set { _j = value } };

mutable _k : int;
K : int { set { _k = value } };


[Accessor]
_i : int;

[Accessor(WantSetter = true)]
_j : int;


Accessor неинтуитивен для программистов C#.

Предложение:
Вместо этого предлагаю обратный Accessor-у стиль.
Описываем свойство, а поле генерируется по имени свойства:

I : int { get };
// _i : int;
// I : int { get { _i } };

[MutableField] I : int { get };
// mutable _i : int;
// I : int { get { _i } };

J : int { get; set; };
// mutable _j : int;
// J : int { get { _j } set { _j = value } };

K : int { set };
// mutable _k : int;
// K : int { set { _k = value } };


Не нужен сложный атрибут Accessor, код более понятен.
Также это не ломает старый код, а лишь дополняет функционал.
Если имя уже занято, ошибка компиляции.

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

Старый вариант:
variant A
{
  | X
    {
      i : int; j : int; // Определение полей
      public new this(i : int, j : int)
      {
        this.i = i;
        this.j = j;
      }
    }
  | Y
    {
      K : int; L : int; // Определение полей
      public new this(k : int, l : int)
      {
        this.K = k;
        this.L = l;
      }
    }
}

def x = A.X(1, 2);
def i = x.i;
def j = x.j;

def y = A.Y(1, 2);
def k = y.K;
def l = y.L;


Новый вариант:
variant A
{
  | X
    {
      // Создаются поля _i, _j
      i : int; j : int; // Определение свойств
      public new this(i : int, j : int)
      {
        this._i = i;
        this._j = j;
      }
    }
  | Y
    {
      // Создаются поля _k, _l
      K : int; L : int; // Определение свойств
      public new this(k : int, l : int)
      {
        this._k = k;
        this._l = l;
      }
    }
}

def x = A.X(1, 2);
def i = x.i;
def j = x.j;

def y = A.Y(1, 2);
def k = y.K;
def l = y.L;


Заключение:
Предложенный способ позволит улучшить код и привлечь больше программистов C#.
Изменение variant улучшает взаимодействие с C#.

Высказываемся
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 16.11.10 12:37
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Nemerle Enhancement Proposal 1


__>Новый вариант:

variant A
{
  | X
    {
      // Создаются поля _i, _j
      i : int; j : int; // Определение свойств
      public new this(i : int, j : int)
      {
        this._i = i;
        this._j = j;
      }
    }
  | Y
    {
      // Создаются поля _k, _l
      K : int; L : int; // Определение свойств
      public new this(k : int, l : int)
      {
        this._k = k;
        this._l = l;
      }
    }
}


То есть программисту необходимо знать про поля, которые генерирует компилятор. Это мне не нравится.
К тому же, соглашения о том, как именовать member-переменные, разные в разных конторах (в отличии от соглашений о том, как именовать свойства).

Если удастся как-то решить эту проблему, я за.
Re[2]: Nemerle Enhancement Proposal 1
От: SergASh  
Дата: 16.11.10 15:50
Оценка:
Здравствуйте, catbert, Вы писали:

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

C>К тому же, соглашения о том, как именовать member-переменные, разные в разных конторах (в отличии от соглашений о том, как именовать свойства).

C>Если удастся как-то решить эту проблему, я за.


Пару лет назад я предлагал ввести в API макросов механизм, который бы позволял абстрагироваться от стиля именования, и чтобы все макросы, генерирующие разные члены класса, при создании имен этих членов опирались на данный механизм. Если программиста не устроит стиль по умолчанию, то он один раз на проект или солюшен настроит под себя и больше об этом не волнуется. Правда, тогда мой голос не был услышан. Возможно, сейчас самое время что-то такое сделать.
Re[2]: Nemerle Enhancement Proposal 1
От: _nn_ www.nemerleweb.com
Дата: 16.11.10 16:27
Оценка:
Здравствуйте, catbert, Вы писали:

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

C>К тому же, соглашения о том, как именовать member-переменные, разные в разных конторах (в отличии от соглашений о том, как именовать свойства).

C>Если удастся как-то решить эту проблему, я за.


Вы о классах или о вариантах ?

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

Если о вариантах, то интерес на наименования поля появляется только в одном случае, когда переопределяется конструктор.
Из всего кода компилятора данная возможность используется только в 2-х файлах.
Кстати, вы знали что это возможно до этого поста ?
Т.е. в большинстве случаев нас не интересует какие поля создает компилятор.
Зато это даст лучший интероп с C#, где у варианта будут видны свойства, а не поля.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Nemerle Enhancement Proposal 1
От: _nn_ www.nemerleweb.com
Дата: 17.11.10 07:38
Оценка:
Здравствуйте, catbert, Вы писали:

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


Сейчас можно вручную все указать и нет проблем.
Можно конечно придумать какой-то макрос типа такого:
[Field(Name = "otherName")] X : int { get };

otherName : int;
X : int { get { otherName } };


[Field(Name = "otherName2")] Y : int { get; set; };

mutable otherName2 : int;
Y : int { get { otherName2 } set { otherName2 = value } };

(После написания, возник вопрос, почему его нет сейчас ? )

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

I : int { get }

public this()
{
  Initialize(out I); // out I_Generated_Name
  Initialize2(ref I); // ref I_Generated_Name
  I = 1; // I_Generated_Name = 1
}


variant A
{
  | X
    {
      I : int;
      public new this(i : int)
      {
        I = 1; // I_Generated_Name = 1
        // ..
      }
    }
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 17.11.10 10:45
Оценка:
Здравствуйте, catbert, Вы писали:

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


C>Если удастся как-то решить эту проблему, я за.


Мое решение — макрос field(PropertyName), который возвращает PExpr-референс на сгенерированное автополе.
Re[3]: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 17.11.10 10:48
Оценка:
Здравствуйте, _nn_, Вы писали:

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

__>Из всего кода компилятора данная возможность используется только в 2-х файлах.

Или когда определяется новый конструктор... эту возможность я использую часто.

Вообще, автосвойство с геттером нужно лишь одном случае — когда возвращаемое значение задается в конструкторе. В результате, нужен лишь способ задать в конструкторе это самое значение.
Re[4]: Nemerle Enhancement Proposal 1
От: _nn_ www.nemerleweb.com
Дата: 17.11.10 11:54
Оценка:
Здравствуйте, catbert, Вы писали:

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


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

__>>Из всего кода компилятора данная возможность используется только в 2-х файлах.

C>Или когда определяется новый конструктор... эту возможность я использую часто.


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


Что насчет автоматической подстановки поля вместо свойства в get свойствах ?
http://rsdn.ru/forum/nemerle/4041734.1.aspx
Автор: _nn_
Дата: 17.11.10
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 17.11.10 21:38
Оценка:
Здравствуйте, _nn_, Вы писали:

__>
__>[Field(Name = "otherName2")] Y : int { get; set; };

__>mutable otherName2 : int;
__>Y : int { get { otherName2 } set { otherName2 = value } };
__>

__>(После написания, возник вопрос, почему его нет сейчас ? )

Это круто.

__>Для автосвойств типа get и для свойств variant вместо этого макроса можно разрешить использовать имя свойства и вместо него компилятор подставит поле.

__>В любом случае кроме как конструктора мы не можем их инциализировать.
__>Таким образом нам не нужно знать имени генерируемого поля.

__>
__>I : int { get }

__>public this()
__>{
__>  Initialize(out I); // out I_Generated_Name
__>  Initialize2(ref I); // ref I_Generated_Name
__>  I = 1; // I_Generated_Name = 1
__>}
__>


__>
__>variant A
__>{
__>  | X
__>    {
__>      I : int;
__>      public new this(i : int)
__>      {
__>        I = 1; // I_Generated_Name = 1
__>        // ..
__>      }
__>    }
__>


Если замена I на I_Generated_Name в конструкторах не вызовет всяких странностей при попытке обращения к свойству именно как свойству, можно и так сделать.
Re: Nemerle Enhancement Proposal 1
От: matumba  
Дата: 21.11.10 09:09
Оценка:
Здравствуйте, _nn_, Вы писали:

nn>J : int { get; set; };

nn>// mutable _j : int;
nn>// J : int { get { _j } set { _j = value } };

Всесторонне поддерживаю! На мой взгляд, если под каждую команду пытаться затачивать компилятор (ах, какие капризные разрабы — им не нравится подчёркивание!), то в результате из-за 10% извращенцев будут страдать 90% остальных (извращенцев) . В ЛЮБОМ языке есть фичи, которые не нравятся той или иной группе — надо принимать решение, оптимальное для большинства.
Мне кажется предложенный nn метод самым практичным — голова должна думать об алгоритмах, а не плюшках в названиях переменных.
И вот ещё что бы добавил:

J : int { get; set; } = 7;
// mutable _j : int = 7;
// J : int { get { _j } set { _j = value } };


Т.е. статическая инициализация проперти.
Re[2]: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 21.11.10 11:46
Оценка:
Здравствуйте, matumba, Вы писали:

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


nn>>J : int { get; set; };

nn>>// mutable _j : int;
nn>>// J : int { get { _j } set { _j = value } };

M> В ЛЮБОМ языке есть фичи, которые не нравятся той или иной группе — надо принимать решение, оптимальное для большинства.


Я сам использую имена полей класса с нижним подчеркиванием. Просто мне кажется, что если наше свойство автоматическое, то выставлять напоказ сгенерированную компилятором переменную для этого свойства нелогично и некрасиво как-то.

А большинство станет еще больше, если не привязывать язык к какому-то конкретному стилю именования. Поэтому варианты, где такой привязки нет, имхо ценнее. А уже есть два варианта: макрос field(...) и подстановка поля вместо свойства в конструкторах.

M>
M>J : int { get; set; } = 7;
M>// mutable _j : int = 7;
M>// J : int { get { _j } set { _j = value } };
M>


M>Т.е. статическая инициализация проперти.


Плюсадин
Re[3]: Nemerle Enhancement Proposal 1
От: matumba  
Дата: 21.11.10 15:12
Оценка:
Здравствуйте, catbert, Вы писали:

C>Просто мне кажется, что если наше свойство автоматическое, то выставлять напоказ сгенерированную компилятором переменную для этого свойства нелогично и некрасиво как-то.


"Напоказа" не будет — она же приватная! Кроме того, она необходима, если логика доступа нетривиальная:

Hour : int { get; set; };// тут-то всё легко!
Minute : int {
    get;// ожидаемо, get { _minute; }
    set {
        if (value > 60) _hour = value / 60;// здесь нет смысла дёргать Hour, т.к. это внутренние разборки
        _minute = value % 60;// а как тут присвоить, не зная имени?
    }
};


C>Поэтому варианты, где такой привязки нет, имхо ценнее.


Нет смысла возить весь чемодан ключей, если у колеса один единственный размер гаек. Зато неудобств — море. Никто же не парится, что в идентификаторах нельзя ставить пробелы? Хотя куда приятнее читать "Загрузить(Отчёт за месяц)", чем "Загрузить(ОтчётЗаМесяц)". "Где-то приходится быть злым, чтобы всё вокруг стало добрее".
Re[4]: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 21.11.10 15:57
Оценка:
Здравствуйте, matumba, Вы писали:

M>"Напоказа" не будет — она же приватная! Кроме того, она необходима, если логика доступа нетривиальная:


M>
M>Hour : int { get; set; };// тут-то всё легко!
M>Minute : int {
M>    get;// ожидаемо, get { _minute; }
M>    set {
M>        if (value > 60) _hour = value / 60;// здесь нет смысла дёргать Hour, т.к. это внутренние разборки
M>        _minute = value % 60;// а как тут присвоить, не зная имени?
M>    }
M>};
M>


Для автосвойств с геттером и сеттером использование сгенерированного поля вообще не имеет смысла, потому что все обращения к полю можно выразить через обращения к свойству.

M>Нет смысла возить весь чемодан ключей, если у колеса один единственный размер гаек. Зато неудобств — море. Никто же не парится, что в идентификаторах нельзя ставить пробелы? Хотя куда приятнее читать "Загрузить(Отчёт за месяц)", чем "Загрузить(ОтчётЗаМесяц)". "Где-то приходится быть злым, чтобы всё вокруг стало добрее".


В данном случае злым быть не приходится, нужно просто чуточку больше подумать.
Re: Nemerle Enhancement Proposal 1
От: matumba  
Дата: 21.11.10 17:16
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Предложение:

__>Описываем свойство, а поле генерируется по имени свойства:

J : int { get; set; };
// mutable _j : int;
// J : int { get { _j } set { _j = value } };


Ребят, пните начинающего, хотел вот попробовать реализовать это (в сильно упрощённом виде), но чую, сделал совсем не то и не так.
Для начала, я не нашёл как втиснуться в класс под видом объявления проперти — решил просто через синтаксис "prop ИмяСвойства Тип;", но хотелось бы именно как у _нн_ — "Джи : инт {get;set;}" (а то и вообще "J : int R;" / "J : int RW;"). Вторая грабля — это правильно достучаться к названию переменной. Моя storage_name — строка, а компилер ругаицца "in argument #1 (expr), needed a Nemerle.Compiler.Parsetree.PExpr, got string: System.String is not a subtype of Nemerle.Compiler.Parsetree.PExpr [simple require]" (это он на строку с mutable).
Теперь я догадываюсь, почему это КВАЗИцитирование — потому что, блин, всё так сложно, что Макросы становятся вообще высшим дзеном, хотя по идее, ничего сверхсложного из себя не представляют — взял исходник, преобразовал, выдал AST или вообще тупую строку-подстановку.
Вот мои мозолистые 3-часовые труды (где мозоль — не скажу ) :

public macro prop (prop_type, name)
  syntax ("prop", prop_type, name)
  {
      def storage_name = "_" + name.ToString().ToLower();
      <[
          mutable $storage_name : $prop_type;
      ]>
  }
Re[5]: Nemerle Enhancement Proposal 1
От: hi_octane Беларусь  
Дата: 21.11.10 18:20
Оценка:
__>Что насчет автоматической подстановки поля вместо свойства в get свойствах ?
__>http://rsdn.ru/forum/nemerle/4041734.1.aspx
Автор: _nn_
Дата: 17.11.10

Совсем свойство не выкинуть, т.к. оно может быть частью реализации интерфейса, оно может понадобиться через рефлексию, может использоваться каким-либо макросом для чего-то. Экономия на get несущественная, да и оптимизация доступа к свойствам — вроде как работа jit'a, и он вроде даже с ней в релизе справляется... короче оно того стоит? Какое преимущество ожидается от этой фичи?
Re[2]: Nemerle Enhancement Proposal 1
От: catbert  
Дата: 21.11.10 19:31
Оценка:
Здравствуйте, matumba, Вы писали:

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


__>>Предложение:

__>>Описываем свойство, а поле генерируется по имени свойства:

M>
M>J : int { get; set; };
M>// mutable _j : int;
M>// J : int { get { _j } set { _j = value } };
M>


M>Ребят, пните начинающего, хотел вот попробовать реализовать это (в сильно упрощённом виде), но чую, сделал совсем не то и не так.

M>Для начала, я не нашёл как втиснуться в класс под видом объявления проперти — решил просто через синтаксис "prop ИмяСвойства Тип;", но хотелось бы именно как у _нн_ — "Джи : инт {get;set;}" (а то и вообще "J : int R;" / "J : int RW;"). Вторая грабля — это правильно достучаться к названию переменной. Моя storage_name — строка, а компилер ругаицца "in argument #1 (expr), needed a Nemerle.Compiler.Parsetree.PExpr, got string: System.String is not a subtype of Nemerle.Compiler.Parsetree.PExpr [simple require]" (это он на строку с mutable).
M>Теперь я догадываюсь, почему это КВАЗИцитирование — потому что, блин, всё так сложно, что Макросы становятся вообще высшим дзеном, хотя по идее, ничего сверхсложного из себя не представляют — взял исходник, преобразовал, выдал AST или вообще тупую строку-подстановку.
M>Вот мои мозолистые 3-часовые труды (где мозоль — не скажу ) :

M>
M>public macro prop (prop_type, name)
M>  syntax ("prop", prop_type, name)
M>  {
M>      def storage_name = "_" + name.ToString().ToLower();
M>      <[
M>          mutable $storage_name : $prop_type;
M>      ]>
M>  }
M>


Ты создаешь макрос уровня выражения. Он может использоваться только внутри методов.
Макросы уровня класса (не уверен, что они именно так называются) писать чуть сложнее. Насколько я понимаю, твой синтаксис в Nemerle 1 вообще невозможно реализовать.

Менее глобально, надо вместо $storage_name написать $(storage_name : usesite). (не проверял, к сожалению, но копать надо в эту сторону)
Re[3]: Nemerle Enhancement Proposal 1
От: matumba  
Дата: 21.11.10 20:14
Оценка:
catbert, спасибо, ХОТЯ БЫ СКОМПИЛИРОВАЛОСЬ!

C>Ты создаешь макрос уровня выражения.


Это-то и пугает! Разве не унифицированным должен быть подход к макросам? Сейчас-то я уже нашёл волшебные строчки, но от них ещё страшнее:

def ctx = Nemerle.Macros.ImplicitCTX ();
def builder = ctx.Env.Define (<[ decl:
builder.Define (<[ decl: foo : int;
builder.Compile ();
builder.CannotFinalize = true;


(это я надёргал из примера) Что-то мне подсказывает, что всех этих ImplicitCTX/Define/Compile вообще не должно быть — макрос должен писаться одинаково везде.
Re[2]: Nemerle Enhancement Proposal 1
От: _nn_ www.nemerleweb.com
Дата: 22.11.10 08:19
Оценка:
Здравствуйте, matumba, Вы писали:

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


__>>Предложение:

__>>Описываем свойство, а поле генерируется по имени свойства:

M>
M>J : int { get; set; };
M>// mutable _j : int;
M>// J : int { get { _j } set { _j = value } };
M>


M>Ребят, пните начинающего, хотел вот попробовать реализовать это (в сильно упрощённом виде), но чую, сделал совсем не то и не так.

M>Для начала, я не нашёл как втиснуться в класс под видом объявления проперти — решил просто через синтаксис "prop ИмяСвойства Тип;", но хотелось бы именно как у _нн_ — "Джи : инт {get;set;}" (а то и вообще "J : int R;" / "J : int RW;"). Вторая грабля — это правильно достучаться к названию переменной. Моя storage_name — строка, а компилер ругаицца "in argument #1 (expr), needed a Nemerle.Compiler.Parsetree.PExpr, got string: System.String is not a subtype of Nemerle.Compiler.Parsetree.PExpr [simple require]" (это он на строку с mutable).

Так синтаксис J : int { get; set; } и так уже рабочий.
Там ничего не нужно менять.

Мое предложение было в унифицировании имен полей.
Но все же видится мне более правильным решением указывать их явно.

Еслия я правильно понимаю тут разбор "get", "set", а значит там можно повлиять на генерируемое поле:
http://code.google.com/p/nemerle/source/browse/nemerle/trunk/ncc/parsing/MainParser.n#1486
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Nemerle Enhancement Proposal 1
От: _nn_ www.nemerleweb.com
Дата: 22.11.10 08:22
Оценка:
Здравствуйте, hi_octane, Вы писали:

__>>Что насчет автоматической подстановки поля вместо свойства в get свойствах ?

__>>http://rsdn.ru/forum/nemerle/4041734.1.aspx
Автор: _nn_
Дата: 17.11.10

_>Совсем свойство не выкинуть, т.к. оно может быть частью реализации интерфейса, оно может понадобиться через рефлексию, может использоваться каким-либо макросом для чего-то. Экономия на get несущественная, да и оптимизация доступа к свойствам — вроде как работа jit'a, и он вроде даже с ней в релизе справляется... короче оно того стоит? Какое преимущество ожидается от этой фичи?

Так я и не предлагаю его выкинуть
Для get свойство придется всегда устанавливать имя поля, что сводит все преимущество на нет:
[Field(Name = "x")] X : int { get; }
[Accessor] x : int;


Раз get свойство всегда создает readonly переменную, которую можно изменять только в конструкторе.
Мне кажется логичным подстановка поля вместо свойства там.
Надо только понять если не приведет это к каким-нибудь проблемам.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Nemerle Enhancement Proposal 1
От: hi_octane Беларусь  
Дата: 22.11.10 10:12
Оценка: 3 (1)
__>Раз get свойство всегда создает readonly переменную, которую можно изменять только в конструкторе.
__>Мне кажется логичным подстановка поля вместо свойства там.
__>Надо только понять если не приведет это к каким-нибудь проблемам.
Ну например в макросах разбирая AST метода по-разному работать с автосвойствами, которые заменяются на поля и с обычными свойствами совсем не хочется. А если макрос ещё захочет обратиться к аттрибутам свойства, вместо которого подставилось поле — то ещё больший лишний гемор. Получается эта оптимизация должна идти на самых последних этапах, когда макросы уже отработали, т.е. хардкод в компилятор одного особенного случая.

И главное, какой профит с этого? Минимальная оптимизация которую должен jit делать, но вручную? Может лучше вложить время в поддержку WPF?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.