parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

Все не так...

Sumo 23.02.2015 21:44

Объект в парсере — это специальная версия хеша. Синтаксическая конструкция $var[$obj $.field[...]] эквивалентна $obj.field[...] $var[$obj]. Возьми объект из переменной obj, добавь в него поле field со значением «...» и положи ссылку на него в var.

И var и obj будут ссылаться на один и тот же объект. Если я напишу $var.field[var2], то $obj.field eq $var.field eq "var2".

Если вместо obj написать конструктор ($var[^class::create[] $.field[...]]), то сначала будет вызван конструктор класса class, который создаст объект в памяти, после чего в объект будет добавлено поле field со значением «...». Ссылка на объект будет в переменной var.

Нужна эта конструкция, если мы хотим добавить несколько полей в один объект/хеш и не повторять имя переменной с объектом и использовать синтаксис, похожий на создание хеша:
@main[]
   $h[
      $.field1[one]
      $.field2[two]
   ]
   ^method1[$h]
   ^method3[$h]

@method1[aHash]
  ...
  ^method2[$aHash
#   Добавляем поле
     $.newField1[four]
#   Меняем существующее
     $.field2[three]
  ]
В этом коде есть проблема. Мы добавили поля в оригинальный объект. В переменной h, после вызова method1 будет новое поле newFiled1, а в поле field2 будет лежать строка «three». Программист очень удивиться, когда в методе method3 окажется хеш в котором field2 eq three. Ведь парой строк выше написано совсем иное.

Тот, кто писал method1 не подумал про побочный эффект своего кода и подложил нам свинью. Отлаживать такой код очень непросто.

Исправим ситуацию:
@main[]
   $h[
      $.field1[one]
      $.field2[two]
   ]
   ^method1[$h]
   ^method3[$h]

@method1[aHash]
  ...
  ^method2[^hash::create[$aHash]
#   Добавляем поле
     $.newField1[four]
#   Меняем существующее
     $.field2[three]
  ]
Вот тут все будет нормально. Мы сделали копию параметра, добавили в него поле и передали в method3. В переменной h лежит оригинальный объект.

Именно этот случай, главное применение для этого синтаксического выверта. Но не стоит им злоупотреблять. Если бы я изначально написал:
@method1[aHash]
  ...
  $aHash.newField1[...]
  $aHash.field[three]
  ^method2[$aHash]
То сразу бы увидел, что я меняю оригинальный объект и надо бы сделать копию. Всегда помните, что объекты передаются по ссылкам, т.е. в параметрах метода приходит оригинальный объект. Методы не должны менять ничего, что в них пришло, а результат возвращать через result. Если удобно использовать оригинальный объект — сначала сделай копию. Иначе поиск ошибок будет тяжелым. :)