Как добавить метод в существующий класс в Perl 6?

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

Я думал, что смогу сделать что-то вроде этого:

class Int {
    method is-even (Int:D $number ) returns Bool:D {
        return False if $number % 2;
        return True;
        }
    }

say 137.is-even;

Но это не работает:

===SORRY!===
P6opaque: must compose before allocating

Я не знаю, означает ли это, что я не могу этого сделать или что я делаю это неправильно.

Я мог бы легко создать новый класс, который наследуется от Int, но это не то, что меня интересует:

class MyInt is Int {
    method is-even () returns Bool:D {
        return False if self % 2;
        return True;
        }
    }

my $n = MyInt.new(138);
say $n.is-even;

Я не ищу обходных путей или альтернативных решений.

12 голосов | спросил brian d foy 29 TueEurope/Moscow2015-12-29T08:18:12+03:00Europe/Moscow12bEurope/MoscowTue, 29 Dec 2015 08:18:12 +0300 2015, 08:18:12

4 ответа


0

Для этого есть синтаксический сахар - augment:

use MONKEY-TYPING;

augment class Int {
    method is-even() returns Bool:D {
        return False if self % 2;
        return True;
    }
}

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

Таким образом, требование предоставить прагму MONKEY-TYPING, прежде чем вы сможете ее использовать.

Кроме того, обратите внимание, что is-even можно записать более компактно как self %% 2.

ответил Christoph 29 TueEurope/Moscow2015-12-29T13:19:09+03:00Europe/Moscow12bEurope/MoscowTue, 29 Dec 2015 13:19:09 +0300 2015, 13:19:09
0

Да, это работает, и я подумал, что пробовал раньше, и мне нравится больше, чем то, что я представил в вопросе.

Int.^add_method( 'is-even', method () returns Bool:D {
    return False if self % 2;
    return True;
    } );

say 137.is-even;

Я не уверен, что это должно сработать. add_method docs говорит, что мы должны делать это только перед составлением типа. Если я позвоню Int.^methods, то is-even не будет не показывай Тем не менее, это кажется вызываемым и делает правильные вещи.

Лексические методы

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

my &is-even = method (Int:D :) returns Bool:D { self %% 2 };

Это создает Callable (смотрите &is-even.WHAT

say 137.&is-even;
say 138.&is-even;
say "foo".&is-even;  # works, although inside is-even blow up

Это хорошо в другом измерении, так как оно лексическое, но не то, что объект неправильного типа может вызвать его. Ошибка появляется после того, как она думает, что имеет метод для отправки.

ответил brian d foy 29 TueEurope/Moscow2015-12-29T08:39:07+03:00Europe/Moscow12bEurope/MoscowTue, 29 Dec 2015 08:39:07 +0300 2015, 08:39:07
0

Вы также можете просто вызвать подпрограмму, подобную методу, добавив & sygil:

sub is-even(Int $n) { $n %% 2 }
say 4.&is-even;  # True

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

(я знаю, что вы «не ищете обходных путей или альтернативных решений», но вы сами опубликовали некоторые, поэтому я подумал, а почему бы и нет?)

ответил mscha 13 J0000006Europe/Moscow 2017, 15:58:33
0

Есть еще один интересный способ сделать это, если он нужен только для некоторых экземпляров класса Вы можете украсить объект с ролью:

 my $decorated = $object but role { ... }
ответил brian d foy 13 J0000006Europe/Moscow 2017, 01:34:06

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132