В этом ли смысл замысла Раку?
Справедливо сказать, что Раку не совсем не придуман в этой области. Ваш вопрос затрагивает две темы в дизайне Raku, которые стоит немного обсудить.
Raku имеет первоклассные l-значения
Raku широко использует l-значения, будучи первым классная вещь. Когда мы пишем:
has $.x is rw;
Генерируемый метод:
method x() is rw { $!x }
Здесь is rw
указывает, что метод возвращает l-значение это то, что может быть назначено. Таким образом, когда мы пишем:
$obj.x = 42;
Это не syntacti c sugar: это действительно вызов метода, а затем к его результату применяется оператор присваивания. Это работает, потому что вызов метода возвращает контейнер атрибута Scalar
, который затем может быть назначен. Можно использовать связывание, чтобы разделить это на два шага, чтобы увидеть, что это не тривиальное преобразование syntacti c. Например, это:
my $target := $obj.x;
$target = 42;
будет присваиваться атрибуту объекта. Этот же механизм стоит за многими другими функциями, включая назначение списка. Например, это:
($x, $y) = "foo", "bar";
Работает путем построения List
, содержащего контейнеры $x
и $y
, и затем оператор присваивания в этом случае выполняет итерацию каждой стороны попарно для выполнения присваивания. Это означает, что мы можем использовать rw
объектные средства доступа:
($obj.x, $obj.y) = "foo", "bar";
И все это просто естественно работает. Это также механизм присвоения срезов массивов и хэшей.
Можно также использовать Proxy
, чтобы создать контейнер с l-значением, в котором его поведение читается и записывается. находятся под вашим контролем. Таким образом, вы можете поместить побочные действия в STORE
. Однако ...
Раку поощряет методы semanti c вместо "сеттеров"
Когда мы описываем ОО, часто встречаются такие термины, как "инкапсуляция" и "сокрытие данных". Ключевая идея здесь заключается в том, что модель состояния внутри объекта - то есть способ, которым он выбирает для представления данных, которые ему необходимы для реализации его поведения (методов) - может свободно развиваться, например, для обработки новых требований. Чем сложнее объект, тем более освобождающим становится этот объект.
Однако методы получения и установки - это методы, которые имеют неявную связь с состоянием. Хотя мы можем утверждать, что достигаем сокрытия данных, потому что мы вызываем метод, а не обращаемся непосредственно к состоянию, мой опыт показывает, что мы быстро оказываемся в месте, где внешний код выполняет последовательности вызовов установщика для выполнения операции, которая форма особенность зависти анти-шаблон. И если мы делаем , что , то вполне вероятно, что в итоге мы получим logi c вне объекта, который выполняет сочетание операций получения и установки для выполнения операции. Действительно, эти операции должны были быть представлены как методы с именами, которые описывают то, что достигается. Это становится еще более важным, если мы находимся в параллельной обстановке; Хорошо спроектированный объект часто довольно легко защитить на границе метода.
Тем не менее, многие применения class
действительно являются типами записей / продуктов: они существуют для простой группировки нескольких элементов данных. Не случайно, что символ .
не только генерирует метод доступа, но также:
- Определяет атрибут для установки по умолчанию при инициализации объекта logi c (то есть,
class Point { has $.x; has $.y; }
может быть создан как Point.new(x => 1, y => 2)
), а также отображается в методе .raku
. - Определяет атрибут в объекте
.Capture
по умолчанию, что означает, что мы можем использовать его при деструктурировании (например, sub translated(Point (:$x, :$y)) { ... }
).
Что бы вы хотели, если бы писали в более процедурном или функциональном стиле и использовали class
в качестве средства для определения типа записи.
Дизайн Raku не оптимизирован для умных действий в сеттерах, потому что это плохо для оптимизации. Это выше того, что нужно для типа записи; в некоторых языках мы можем утверждать, что хотим сделать проверку того, что присваивается, но в Raku мы можем обратиться к subset
типам для этого. В то же время, если мы действительно занимаемся проектированием ОО, нам нужен API осмысленного поведения, который скрывает модель состояния, а не думать с точки зрения геттеров / сеттеров, что, как правило, приводит к невозможности совместного размещения данные и поведение, что в любом случае является основной целью ОО.