perl6 rakudo 2016.11 match пытается присвоить переменную только для чтения, почему не в 2016.07?

У меня есть следующий метод в классе действий, который хорошо работал в Rakudo 2016.07, но я только что установил 2016.11, и теперь новый Rakudo говорит, что мой метод пытается присвоить переменную только для чтения, и я просто не вижу проблемы:

method ptName ($/) { 
    my $nameStr = $/.Str, my $lastName, my $firstName; 
    my $newMatch  # this is line 182; 
                  # Cannot assign to a readonly variable or a value
       = $nameStr.match(/ \" (<alpha>+) .*? \, \s* (<alpha>+) .*? \" /);
    $lastName  = $newMatch[0];
    $firstName = $newMatch[1];
    make "$lastName $firstName"; 
}

Все сообщение об ошибке

Cannot assign to a readonly variable or a value
  in method ptName at /home/lisprog/Binary/grammar.pl line 182
  in regex ptName at /home/lisprog/Binary/grammar.pl line 151
  in regex TOP at /home/lisprog/Binary/grammar.pl line 137
  in block <unit> at /home/lisprog/Binary/grammar.pl line 217

Какие спецификации языка изменились? Пожалуйста помоги. Благодарю.

================================================== ===

Спасибо, Райф, Кристоф, ZZ!! Я не знаю, как добавить длинный комментарий с правильным форматированием. Итак, я добавляю комментарии к своему посту.

Я написал тестовую программу, и теперь кажется, что если я не использую ($/) в сигнатуре метода, потому что я должен использовать.match внутри метода, я больше не могу ничего делать. Что я сделал не так? Вот программа испытаний и результаты:

Тестовая программа:

grammar test {
    regex TOP   { <foo><bar> }
    regex foo   { :i \s* foo \s* }
    regex bar   { :i \s  bar \s* }
}

class actTest {
    method foo ($x) { # program fails if I use $/ in signature
      print "1 "; say $x; # how to combine the 2 and show $x as match?
      print "2 "; say $x.WHAT;
      my $newStr = $x.Str;
      print "3 "; say $newStr;
      my $newMatch 
           = $newStr.match(/:i(f)(oo)/); # adverb cannot be outside?
      print "4 "; say $newMatch.WHAT;
      print "5 "; say $newMatch;
      print "6 "; say $/;
      my $oo = $newMatch[1].Str;
      print "10 "; say $oo;
      my $f = $newMatch[0].Str;
      print "11 "; say $f;
      my $result = $oo ~ $f;
      print "12 "; say $result;
      make $result; # now I cannot make anything; huh???
    }
    method TOP ($/) { 
      print "8 "; say $<bar>;
      print "9 "; say $<foo>.made; # failed, method 'foo' makes nothing
      make $<bar> ~ $<foo>.made; 
    }
}

my $m = test.parse("Foo bar", actions => actTest.new);
print "7 "; say $m;

И результаты:

1 「Foo 」
2 (Match)
3 Foo 
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
1 「Foo」
2 (Match)
3 Foo
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
8 「 bar」
9 (Any)
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to
something meaningful.
in method TOP at matchTest.pl line 28
7 「Foo bar」
 foo => 「Foo」
 bar => 「 bar」

3 ответа

Решение

Здесь есть два вопроса, и я отвечу на каждый по очереди:

1) match tries to assign to read-only variable

Он пытается установить $/, который у вас уже есть в вашей области видимости и только для чтения. Вы можете просто использовать другое имя в подписи для грамматики $/. Я вижу, что вы сразу принуждаете его к Str, так почему бы не позволить подписи сделать это:

method ptName (Str() $nameStr) { ... }

2) why not in 2016.07?

Новое поведение не является ошибкой, и основная команда решила, что текущее поведение желательно (РЕДАКТИРОВАТЬ: фактически, при дальнейшем рассмотрении кажется, что старое поведение было ошибкой, когда.match молча не смог установить $/, если он был только для чтения),

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

Хотя существует очевидная цель, чтобы поведение оставалось неизменным, чтобы пользователи могли на него полагаться, нам также необходимо улучшить работу и двигаться вперед. Как это работает, у нас есть огромный набор тестов, который мы называем Roast. Если в код внесено изменение, которое нарушает тест, это изменение нельзя сделать на текущем языке, и его следует отложить до следующего языкового выпуска (с тех пор пользователи могут использовать use v6.c или что-то еще, чтобы старое поведение).

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

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

Это в настоящее время имеет место с .match метод, который вы использовали. Я не уверен, где вы узнали об этом, так как в конце сентября я создал документ, в котором указывается .match не было документировано, так что тогда его не было в документации, и он ожидал, что поработает lizmat, который изменил поведение, которое вас укусило.

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

Ура, ZZ

В соответствии с git blame src/core/Str.pm Лизмат работал на это в октябре. Str.match теперь будет возиться с лексическим $/ вызывающего блока, когда он, очевидно, не делал этого раньше.

Это означает Str.match вернет свой результат дважды: сначала как его возвращаемое значение, а второй раз вне диапазона, установив $/, В то время как регулярное выражение приложения через ~~ делает это также (что необходимо, чтобы вы могли использовать синтаксический сахар, как $0 или же $<foo>) Я не уверен Str.match должен. Если раньше он этого не делал, я подозреваю, что это может быть ошибкой: либо сообщите об этом, либо спросите в #perl6 на Freenode об этом.

Как указывает Zoffix, это было старое поведение, $/ всегда должен был быть установлен, но неспособность сделать это просто не вызывала исключения.

Я хочу поблагодарить ZZ, Christoph, raiph и smls за то, что они уделили мне драгоценное время. Моя проблема была решена

(1) использование сигнатуры метода, отличного от $/, и (2) использование объекта соответствия сигнатуры для создания вместо использования $ / для создания.

Пожалуйста, также обратитесь к ответам на https://stackru.com/posts/41027321/revisions

Большое спасибо!!

You can also use an immediately-invoked lambda: -> $x { my $/; $x.match(/regex/) }($/)

Другие вопросы по тегам