Method returning a regex in Perl 6? - class

I'm only beginning to study classes, so I don't understand the basics.
I want a method to construct regex using attributes of the object:
class TEST {
has Str $.str;
method reg {
return
rx/
<<
<[abc]> *
$!str
<!before foo>
/;
}
}
my $var = TEST.new(str => 'baz');
say $var.reg;
When trying to run this program, I get the following error message:
===SORRY!=== Error while compiling /home/evb/Desktop/p6/e.p6
Attribute $!str not available inside of a regex, since regexes are methods on Cursor.
Consider storing the attribute in a lexical, and using that in the regex.
at /home/evb/Desktop/p6/e.p6:11
------> <!before foo>⏏<EOL>
expecting any of:
infix stopper
So, what's the right way to do that?

Looks like this would work:
class TEST {
has Str $.str;
method reg {
my $str = $.str;
return
regex {
<<
<[abc]> *
$str
<!before foo>
}
}
}
my $var = TEST.new(str => 'baz');
say $var.reg;
say "foo" ~~ $var.reg;
say "<<abaz" ~~ $var.reg
You are returning an anonymous regex, which can be used as an actual regex, as it's done in the last two sentences.

Using EVAL solved my problem. So, I wonder, whether there are any drawbacks in this method.
class TEST {
has Str $.str;
method reg {
return
"rx/
<<
<[abc]> *
$!str
<!before foo>
/".EVAL;
}
}
my $var = TEST.new(str => 'baz');
say "abaz" ~~ $var.reg; # abaz
say "cbazfoo" ~~ $var.reg; # Nil

Related

pointer to constructor to a class in perl6

I am trying to write some classes with Perl 6 just for testing out Perl 6 classes and methods.
Here is the code:
class human1 {
method fn1() {
print "#from human1.fn1\n";
}
}
class human2 {
method fn1() {
print "#from human2.fn1\n";
}
}
my $a = human1.new();
my $b = human2.new();
$a.fn1();
$b.fn1();
print "now trying more complex stuff\n";
my $hum1_const = &human1.new;
my $hum2_const = &human2.new;
my $c = $hum2_const();
$c.fn1();
Essentially I want to be able to use either the human1 constructor or human2 constructor to be able to build $c object dynamically. But I'm getting the following error:
Error while compiling /usr/bhaskars/code/perl/./a.pl6
Illegally post-declared types:
human1 used at line 23
human2 used at line 24
How do I create $c using the function pointers to choose which constructor I use?
I think this is a case of an LTA error. What I understand you want to achieve, is a lambda that will create a new human1 or human2 object for you. The way you do that is not correct, and the error it causes is confusing.
my $hum1_const = -> { human1.new };
my $hum2_const = -> { human2.new };
would be a correct way of doing this. Although, I would consider this a bit of an obfuscation. Since human1 and human2 are already constants, you can assign them to a variable, and then just call new on that:
my $the_human = $condition ?? human1 !! human2;
my $c = $the_human.new;
$c.fn1;
Does that make sense?
To get a “reference” to .new you have to use the meta object protocol.
Either .^lookup, or .^find_method.
my $hum1-create = human1.^find_method('new');
That is still not quite what you are looking for, as methods require either a class object or an instance, as their first argument.
my $c = $hum1-create( human1 );
So you would probably want to curry the class as the first argument to the method.
my $hum1-create = human1.^find_method('new').assuming(human1);
my $c = $hum1-create();
Note that .assuming in this case basically does the same thing as
-> |capture { human1.^find_method('new').( human1, |capture ) }
So you could just write:
my $hum1-create = -> |capture { human1.new( |capture ) }
Or if you are never going to give it an argument
my $hum1-create = -> { human1.new }
Also you can store it in a & sigiled variable, so you can use it as if it were a normal subroutine.
my &hum1-create = human1.^find_method('new').assuming(human1);
my $c = hum1-create;

Perl syntactical details - list context with or without parens?

This works:
my $r = someSubroutine( map { ( 0 => $_ ) } #hosts)
This does not work, giving a syntax error:
my $r = someSubroutine( map { 0 => $_ } #hosts)
What I think I understand is that the { } after the map amounts to a closure or anonymous subroutine.
But if I put a "value, value" at the end of a normal subroutine, it will return a list of those values. If I use this brevity with the map, it is a syntax error.
First of all, this is a very strange statement. The list that map produces will look like
0, $hosts[0], 0, $hosts[1], 0, $hosts[2], ...
so it's useless for assignment to a hash as it would be the same as
my %hash = (0 => $hosts[-1])
map will accept either a BLOCK (which is what you're using) or a simple EXPRESSION for its first parameter. The problem here is that { 0 => $_ } looks very like an anonymous hash with a single element, which is an EXPRESSION, and that is what the parser guesses it is. An EXPRESSION requires a comma after it, before the second parameter, but when perl gets to the closing brace in map { 0 => $_ } #hosts it doesn't find one so it has to throw a syntax error as it is too far to backtrack to the opening brace and assume a block instead
The documentation puts it like this
{ starts both hash references and blocks, so map { ... could be either the start of map BLOCK LIST or map EXPR, LIST. Because Perl doesn't look ahead for the closing } it has to take a guess at which it's dealing with based on what it finds just after the {. Usually it gets it right, but if it doesn't it won't realize something is wrong until it gets to the } and encounters the missing (or unexpected) comma. The syntax error will be reported close to the }, but you'll need to change something near the { such as using a unary + or semicolon to give Perl some help
The solution is to disambiguate it as you discovered. Any of these will work
map +( 0 => $_ ), #hosts
map(( 0 => $_ ), #hosts)
map { +0 => $_ } #hosts
map { ( 0 => $_ ) } #hosts
map { ; 0 => $_ } #hosts
map has two syntax:
map BLOCK LIST e.g. map { f() } g()
map EXPR, LIST e.g. map f(), g()
When Perl encounters map, it needs to determine which syntax was used. Let's say the first token after map is {. That's the start of a BLOCK, right? Hold on! Expressions can start with { too!
my $hash_ref = { key => 'val' };
The grammar is ambiguous. Perl has to "guess" which syntax you are using. Perl looks ahead at the next token to help guess, but sometimes it guesses incorrectly nonetheless. This is one of those cases.
The following are the standard workarounds for this:
map {; ... } LIST # Force Perl to recognize the curly as the start of a BLOCK
map +{ ... }, LIST # Force Perl to recognize the curly as the start of a hash constructor
; can't be part of a hash constructor, so the { can only start a BLOCK.
+ necessarily starts an EXPR (and not a BLOCK). It's an operator that does nothing but help in situations like this.
For example,
map {; +{ $row->{id} => $row->{val} } } #rows
This is described in perldoc on map: http://perldoc.perl.org/functions/map.html
In short you should use little helper like parens or +-symbol so perl will be able to parse {...} construct correctly:
my $r = someSubroutine( map { + 0 => $_ } #hosts)

Odd use of False constant in if-then statement

Python is my main language, but have to maintain a rather large legacy Perl codebase.
I have an odd logic statement that I can't make heads or tails over.
At top, a constant is defined as:
use constant FALSE => 0;
sub thisFunc {
FALSE if ($self->{_thisVar} ne "tif");
...
...
return statement,etc..
}
So I'm reading that as a kinda' fancy, non-standard if-then statement,
that if $thisVar string is not equal to "tif", then FALSE. Huh?
Not something like $that = FALSE, just FALSE.
The form of this statement appears in the file several times.
This codebase is in use, and vetted over the years by very good team,
so I think it is valid and has meaning. "use strict;" is set at top.
Could someone be so kind as to explain what is meant by logic.
I've Google'd it but no joy.
Thanks in advance,
"if" logic in Perl can be constructed in couple of ways:
the obvious one:
if ($flag) { do_something() }
less obvious one:
do_something() if ($flag);
This example shows how exactly behaves that odd "FALSE if" statement - which only meaning is found when it is LAST statement in subroutine:
use strict;
use constant FALSE => 0;
sub thisFunc {
my $arg = shift;
FALSE if ($arg ne "tif");
}
print "return val: ".thisFunc("ble")."\n";
print "return val: ".thisFunc("tif")."\n";
output from running above is:
return val: 0
return val:
It is pointless. I suspect it's suppose to be
return FALSE if $self->{_thisVar} ne "tif";
There is a similar construct that isn't pointless. If the loop condition has side-effects, the following isn't pointless:
1 while some_sub();
aka
while (some_sub()) { }
aka
while (1) {
some_sub()
or last;
}
Practical example:
$ perl -E'$_ = "xaabbx"; 1 while s/ab//; say'
xx

(m/regexp/) or {multiple ; commands; after; or; }

I like very much this syntax:
try_something() or warn "Cant do it";
How can I add more commands after or?
For example it would be useful in this code:
foreach (#array)
{
m/regex/ or {warn "Does not match"; next;} # this syntax is wrong
...
}
One way I found is
try_something() or eval {warn "Can't do it"; next;};
but I think it is bad idea.
BEST ANSWERS:
do is better than eval.
The comma operator is even better: do_smth() or warn("Does not match"), next; Nota bene: parentheses are mandatory for warn so that next does not parse as one of its arguments.
I think that will end up being pretty unreadable pretty fast, but you can do:
foo() or do { bar(); baz(); };
sub foo {
return $_[0] == 2;
}
for (1..3) {
print $_;
foo($_) or do { print " !foo\n"; next; };
print " foo!\n";
}
For the case in your question, I would use unless.
for (#array) {
unless (/regex/) {
warn "Does not match";
next;
}
...
}
You can sometimes get away with using the comma operator. It evaluates its left-hand argument, throws away the result, evaluates the right-hand argument and returns that result. Applied to your situation it looks like
for (#array) {
/regex/ or warn("Does not match"), next;
...
}
Note the extra parentheses. You have to be a bit more careful about parentheses and grouping this way. Be judicious in your use of this technique: it can get ugly quickly.
In a comment below, Zaid suggests
warn('Does not match'), next unless /regex/;
The choice is a matter of style. Perl was created by a linguist. Natural languages allow us to express the same thought in different ways depending on which part we want to emphasize. In your case, do you want to emphasize the warning or the pattern match? Place the more important code out front.
I figured out (and tested) that you can also use 'and':
try_something() or warn "Cant do it" and print "Hmm." and next;
If try_something() is success then it doesn't do anything after or.
If try_something() fails then it warns and prints and next.

perl - universal operator overload

I have an idea for perl, and I'm trying to figure out the best way to implement it.
The idea is to have new versions of every operator which consider the undefined value as the identity of that operation. For example:
$a = undef + 5; # undef treated as 0, so $a = 5
$a = undef . "foo"; # undef treated as '', so $a = foo
$a = undef && 1; # undef treated as false, $a = true
and so forth.
ideally, this would be in the language as a pragma, or something.
use operators::awesome;
However, I would be satisfied if I could implement this special logic myself, and then invoke it where needed:
use My::Operators;
The problem is that if I say "use overload" inside My::Operators only affects objects blessed into My::Operators.
So the question is: is there a way (with "use overoad" or otherwise) to do a "universal operator overload" - which would be called for all operations, not just operations on blessed scalars.
If not - who thinks this would be a great idea !? It would save me a TON of this kind of code
if($object && $object{value} && $object{value} == 15)
replace with
if($object{value} == 15) ## the special "is-equal-to" operator
It is possible. It would take a lot of work, but you could write an "op checker" that replaces the ops for && with custom op that's your reimplementation of &&.
But it would be a very bad idea. For starters,
if ($a && $b) {
...
}
would stop being equivalent to
if ($a) {
if ($b) {
...
}
}
To take your own example,
if ($object && $object{value} && $object{value} == 15) {
...
}
With your requested model, it would have to be written
if ($object{value}) { if ($object{value} == 15) {
...
}}
You actually want the exact opposite of what you asked for. You actually want the current behaviour. Without your module, you can write:
if ($object{value} && $object{value} == 15) {
...
}
or
no warnings 'uninitialized';
if ($object{value} == 15) {
...
}
or
if (($object{value} // 0) == 15) {
...
}
As mob said, your pragma already exists. It's spelled no warnings 'uninitialized';. Perl already treats undef as either 0 or the empty string (depending on context). This just suppresses the warning you usually get (assuming you have warnings turned on, which you should).
If you want to create a package that does this automatically, you can:
package operators::awesome;
use strict;
use warnings;
sub import {
warnings->unimport('uninitialized');
}
Now use operators::awesome; will turn off warnings about uninitialized values.
Here's a fancier version of import that turns on strict and warnings, but turns off warnings about uninitialized values:
sub import {
strict->import;
warnings->import;
warnings->unimport('uninitialized');
}
All of those operations already work the way you expect them to:
In the context of numbers, undef is 0.
In the context of strings, undef is the empty string ''.
In the context of booleans, undef is 0.
If you use warnings, then perl will let you know that the value is uninitialized, but it will still work just fine.