Я был сторонником принятия Moose (и MooseX:: Declare) на работу в течение нескольких месяцев. Стиль, который он поощряет, действительно поможет ремонтопригодности нашей кодовой базы, но не без начальных затрат на изучение нового синтаксиса, и особенно в обучении анализу ошибок проверки типов.
Я видел дискуссию в Интернете по этой проблеме и думал, что отправлю запрос в это сообщество для:
a) известные решения
b) обсуждение того, какие сообщения об ошибках проверки должны выглядеть как
c) предложить доказательство концепции, которая реализует некоторые идеи
Я также свяжусь с авторами, но я тоже хорошо знаком с этим форумом, поэтому я решил опубликовать что-то публичное.
#!/usr/bin/perl
use MooseX::Declare;
class Foo {
has 'x' => (isa => 'Int', is => 'ro');
method doit( Int $id, Str :$z, Str :$y ) {
print "doit called with id = " . $id . "\n";
print "z = " . $z . "\n";
print "y = " . $y . "\n";
}
method bar( ) {
$self->doit(); # 2, z => 'hello', y => 'there' );
}
}
my $foo = Foo->new( x => 4 );
$foo->bar();
Обратите внимание на несоответствие в вызове Foo:: doit с сигнатурой метода.
Сообщение об ошибке:
Validation failed for 'MooseX::Types::Structured::Tuple[MooseX::Types::Structured::Tuple[Object,Int],MooseX::Types::Structured::Dict[z,MooseX::Types::Structured::Optional[Str],y,MooseX::Types::Structured::Optional[Str]]]' failed with value [ [ Foo=HASH(0x2e02dd0) ], { } ], Internal Validation Error is: Validation failed for 'MooseX::Types::Structured::Tuple[Object,Int]' failed with value [ Foo{ x: 4 } ] at /usr/local/share/perl/5.10.0/MooseX/Method/Signatures/Meta/Method.pm line 441
MooseX::Method::Signatures::Meta::Method::validate('MooseX::Method::Signatures::Meta::Method=HASH(0x2ed9dd0)', 'ARRAY(0x2eb8b28)') called at /usr/local/share/perl/5.10.0/MooseX/Method/Signatures/Meta/Method.pm line 145
Foo::doit('Foo=HASH(0x2e02dd0)') called at ./type_mismatch.pl line 15
Foo::bar('Foo=HASH(0x2e02dd0)') called at ./type_mismatch.pl line 20
Я думаю, что большинство согласны с тем, что это не так прямо, как могло бы быть. Я реализовал взломать мою локальную копию MooseX:: Method:: Signatures:: Meta:: Method, которая дает этот результат для одной и той же программы:
Validation failed for
'[[Object,Int],Dict[z,Optional[Str],y,Optional[Str]]]' failed with value [ [ Foo=HASH(0x1c97d48) ], { } ]
Internal Validation Error:
'[Object,Int]' failed with value [ Foo{ x: 4 } ]
Caller: ./type_mismatch.pl line 15 (package Foo, subroutine Foo::doit)
Супер-взломанный код, который делает это,
if (defined (my $msg = $self->type_constraint->validate($args, \$coerced))) {
if( $msg =~ /MooseX::Types::Structured::/ ) {
$msg =~ s/MooseX::Types::Structured:://g;
$msg =~ s/,.Internal/\n\nInternal/;
$msg =~ s/failed.for./failed for\n\n /g;
$msg =~ s/Tuple//g;
$msg =~ s/ is: Validation failed for/:/;
}
my ($pkg, $filename, $lineno, $subroutine) = caller(1);
$msg .= "\n\nCaller: $filename line $lineno (package $pkg, subroutine $subroutine)\n";
die $msg;
}
[Примечание. С помощью нескольких минут сканирования кода выглядит так: MooseX:: Meta:: TypeConstraint:: Structured:: validate немного ближе к коду, который нужно изменить. В любом случае стоит вопрос об идеальном сообщении об ошибке, и кто-то активно работает над подобными изменениями или думает о них.]
Что выполняет 3 вещи:
1) Менее подробный, более простой (я обсуждал, в том числе s/Tuple//, но сейчас придерживаюсь его)
2) Включая вызывающий файл/строку (с хрупким использованием вызывающего абонента (1))
3) вместо того, чтобы признаться, умереть, поскольку, как я вижу, главное преимущество исповедания заключалось в том, чтобы найти точку входа пользователя в typechecking в любом случае, чего мы можем достичь менее подробными способами.
Конечно, я действительно не хочу поддерживать этот патч. Мой вопрос: каков наилучший способ сбалансировать полноту и лаконичность этих сообщений об ошибках, и есть ли какие-либо планы по размещению чего-то подобного на месте?