TL; DR Ответ JJ - это предложение where
во время выполнения, которое вызывает пару методов для рассматриваемого аргумента. Ответы всех остальных выполняют ту же работу, но с использованием конструкций времени компиляции, которые обеспечивают лучшую проверку и намного лучшую производительность. Этот ответ сочетает в себе мой взор с ответами Лиз и Брэда.
Ключевые сильные и слабые стороны ответа JJ
В ответе JJ все логики c содержатся внутри предложения where
. Это его единственная сила относительно решения в ответах всех остальных; он вообще не добавляет Lo C.
Решение JJ имеет два существенных недостатка:
Проверка и издержки отправки для предложения where
для параметра: понесенный во время выполнения 1 . Это дорого, даже если предикат нет. В решении JJ предикаты являются дорогостоящими, что еще больше ухудшает ситуацию. И в довершение всего, издержки в худшем случае при использовании множественная отправка составляют sum of all предложения where
, используемые в все multi
с.
В коде where .^api() == 1 && .^name eq "WithApi"
42 из 43 символов дублируются для каждого варианта multi
. Напротив, ограничение типа не-1038 * гораздо короче и не скрывает разницу. Конечно, JJ может объявить subset
s схожим эффектом, но тогда это устранит единственную силу их решения, не исправляя его наиболее существенную слабость.
Добавление времени компиляции метаданные; использование его в многократной рассылке
Прежде чем перейти к проблеме JJ, в частности, вот пара вариантов общей техники:
role Fruit {} # Declare metadata `Fruit`
my $vegetable-A = 'cabbage';
my $vegetable-B = 'tomato' does Fruit; # Attach metadata to a value
multi pick (Fruit $produce) { $produce } # Dispatch based on metadata
say pick $vegetable-B; # tomato
То же самое, но параметризовано:
enum Field < Math English > ;
role Teacher[Field] {} # Declare parameterizable metadata `Teacher`
my $Ms-England = 'Ms England';
my $Mr-Matthews = 'Mr Matthews';
$Ms-England does Teacher[Math];
$Mr-Matthews does Teacher[English];
multi field (Teacher[Math]) { Math }
multi field (Teacher[English]) { English }
say field $Mr-Matthews; # English
Я использовал role
в качестве метаданных, но это случайно. Цель заключалась в том, чтобы иметь метаданные, которые можно присоединить во время компиляции и которые имеют имя типа, чтобы кандидаты для разрешения диспетчеризации могли быть установлены во время компиляции.
Версия метаданных времени компиляции JJ во время выполнения ответ
Решение состоит в том, чтобы объявить метаданные и при необходимости присоединить их к классам JJ.
Вариант решения Брэда:
class WithApi1 {}
class WithApi2 {}
constant one = anon class WithApi:ver<0.0.1>:auth<github:JJ>:api<1> is WithApi1 {}
constant two = anon class WithApi:ver<0.0.1>:auth<github:JJ>:api<2> is WithApi2 {}
constant three = anon class WithApi:ver<0.0.2>:api<1> is WithApi1 {}
multi sub get-api( WithApi1 $foo ) { "That's api 1" }
multi sub get-api( WithApi2 $foo ) { "That's api deuce" }
say get-api(one.new); # That's api 1
say get-api(two.new); # That's api deuce
say get-api(three.new); # That's api 1
Альтернативой является написание одного Параметризуемый элемент метаданных:
role Api[Version $] {}
constant one = anon class WithApi:ver<0.0.1>:auth<github:JJ>:api<1> does Api[v1] {}
constant two = anon class WithApi:ver<0.0.1>:auth<github:JJ>:api<2> does Api[v2] {}
constant three = anon class WithApi:ver<0.0.2>:api<v1> does Api[v1] {}
multi sub get-api( Api[v1] $foo ) { "That's api 1" }
multi sub get-api( Api[v2] $foo ) { "That's api deuce" }
say get-api(one.new); # That's api 1
say get-api(two.new); # That's api deuce
say get-api(three.new); # That's api 1
Соответствующие диапазоны версий
В комментарии ниже JJ пишет:
Если вы используете where
предложения, вы можете иметь multi
s, которые отправляют версии до числа (поэтому не нужно создавать по одной для каждой версии)
Решение role
, описанное в этом ответе, также может отправлять диапазоны версий, добавив другую роль :
role Api[Range $ where { .min & .max ~~ Version }] {}
...
multi sub get-api( Api[v1..v3] $foo ) { "That's api 1 thru 3" }
#multi sub get-api( Api[v2] $foo ) { "That's api deuce" }
Отображает That's api 1 thru 3
для всех трех вызовов. Если второй мультиэкранный комментарий не закомментирован, он имеет приоритет для вызовов v2
.
Обратите внимание, что обычная диспетчеризация get-api
все еще проверяется, и кандидат разрешается во время компиляции, несмотря на то, что сигнатура роли включает where
пункт. Это связано с тем, что время выполнения предложения роли where
выполняется во время компиляции подпрограммы get-api
; когда get-api
подпрограмма называется условие роли where
больше не актуально.
Сноски
1 В Несколько Ограничения , Ларри писал:
Для 6.0.0 ... любая информация о типе структуры, выводимая из предложения where
, будет игнорироваться [во время компиляции]
Но на будущее он предположил:
my enum Day ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
Int $n where 1 <= * <= 5 # Int plus dynamic where
Day $n where 1 <= * <= 5 # 1..5
Первый where
считается динамическим c не из-за характера сравнений, а потому, что Int
не является конечно-перечислимым , [Второе ограничение] ... может вычислить членство в наборе во время компиляции, потому что оно основано на перечислении Day
, и, следовательно, [ограничение, включающее в себя предложение where
] считается stati c, несмотря на использование а where
.