Не могу перегрузить логические операторы (или, и) для моего класса

Я пытался перегрузить логический оператор or для пользовательского класса, но, похоже, он не работает. Это то, что я делаю:

class A { has $.a }
multi sub infix:<or> (A $a, A $b) {
    "works!({$a.a}, {$b.a})"
}
say A.new(:1a) or A.new(:2a); 

Я ожидаю получить works!(1, 2) в качестве вывода, но вместо этого я получаю A.new(a => 1), который является результатом стандартного оператора or.

Другие операторы (кроме and и xor), похоже, работают для меня:

class A { has $.a }
multi sub infix:<anything-else> (A $a, A $b) {
    "works!({$a.a}, {$b.a})"
}
say A.new(:1a) anything-else A.new(:2a); 

приводит к works!(1, 2).

Я что-то не так делаю или просто нет способа перегрузить стандартные операторы or, and, xor?

Ответ 1

Только операторы, которые компилируются в вызов подпрограммы, могут быть перегружены. Поскольку вызовы подпрограмм оценивают свои аргументы перед выполнением вызова, те операторы, которые требуют отложенной оценки одного из своих операндов, обрабатываются как специальные формы в компиляторе.

Логические операторы, как and, or, &&, и || , определены как оценивающие только их второй операнд в зависимости от истинности их первого операнда, и поэтому не могут быть скомпилированы в вызовы подпрограмм.

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