Raku operator overloading - operator-overloading

Using the following code:
use v6d;
# sub circumfix:<α ω>( #a ) {
# #a[0] >= #a[1] & #a[0] <= #a[2];
# };
sub circumfix:<α ω>( $a, $b, $c ) {
$a >= $b & $a <= $c;
};
if (α <5 0 10> ω) {
say 'Truthy';
}
else {
say 'Falsey';
}
Results in:
(base) hsmyers#BigIron:~/board$ perl6 ./op.p6
Too few positionals passed; expected 3 arguments but got 1
in sub circumfix:<α ω> at ./op.p6 line 7
in block <unit> at ./op.p6 line 11
Whereas switching the commented block for the other definition results in:
(base) hsmyers#BigIron:~/board$ perl6 ./op.p6
Truthy
The broken version (with three parameters) is the one I want, could someone explain why it is broken?

<5 0 10> literally constructs a List, a single List.
An analogy would be a list of things to do, a todo list. How many things is a todo list? It's 1 -- one todo list.
Thus you get the error message:
expected 3 arguments but got 1
What you want is to specify that you want one value that is itself made up of several values. Here's one way to do that:
sub circumfix:<α ω>( ( $a, $b, $c ) ) ...
The additional surrounding ( and ) cause destructuring.

D:\>6e "say <5 0 10>"
(5 0 10)
These aren't three arguments. It's a list of three values (of type IntStr) and therefore a single argument.

Related

Really binding an argument to a parameter? (Perl6)

The Perl6 docs state "By default, parameters are bound to their argument and marked as read-only." But running the following code:
# Example 1
sub f1 ( $x ) { say $x.VAR.WHAT; say $x.WHAT; say $x }
f1(1);
yields:
(Scalar)
(Int)
1
while this code:
# Example 2
my $y := 1;
say $y.VAR.WHAT; say $y.WHAT; say $y;
yields:
(Int)
(Int)
1
It's the (Scalar) in the output of Example1 that I do not understand: why is there a Scalar when I supposedly bind the Int 1 - argument to the identifier $x ? It seems as if the value 1 got "assigned" to $x, rather than "bound".
Scalar containers are also used to indicate items, and thus prevent flattening of them. In the absence of a type constraint, the implementation will conservatively wrap the incoming argument into a read-only Scalar container to avoid any unexpected flattening taking place. Contrast this:
sub foo($x) {
my #a = $x;
say #a.elems;
}
foo([1,2,3]);
Which outputs 1 (no flattening), with a sigilless binding:
sub foo(\x) {
my #a = x;
say #a.elems;
}
foo([1,2,3])
Which outputs 3, since no item context is imposed. Were the Scalar container not there, both would output 3.
In the presence of a non-Iterable type constraint, this wrapping will be omitted. Thus writing:
sub f1(Int $x) {
say $x.VAR.WHAT;
say $x.WHAT;
say $x
}
f1(1)
Will output:
(Int)
(Int)
1
With .VAR simply yielding identity on a non-container.

Where does a Perl subroutine get values missing from the actual parameters?

I came across the following Perl subroutine get_billable_pages while chasing a bug. It takes 12 arguments.
sub get_billable_pages {
my ($dbc,
$bill_pages, $page_count, $cover_page_count,
$domain_det_page, $bill_cover_page, $virtual_page_billing,
$job, $bsj, $xqn,
$direction, $attempt,
) = #_;
my $billable_pages = 0;
if ($virtual_page_billing) {
my #row;
### Below is testing on the existence of the 11th and 12th parameters ###
if ( length($direction) && length($attempt) ) {
$dbc->xdb_execute("
SELECT convert(int, value)
FROM job_attribute_detail_atmp_tbl
WHERE job = $job
AND billing_sub_job = $bsj
AND xqn = $xqn
AND direction = '$direction'
AND attempt = $attempt
AND attribute = 1
");
}
else {
$dbc->xdb_execute("
SELECT convert(int, value)
FROM job_attribute_detail_tbl
WHERE job = $job
AND billing_sub_job = $bsj
AND xqn = $xqn
AND attribute = 1
");
}
$cnt = 0;
...;
But is sometimes called with only 10 arguments
$tmp_det = get_billable_pages(
$dbc2,
$row[6], $row[8], $row[7],
$domain_det_page, $bill_cover_page, $virtual_page_billing,
$job1, $bsj1, $row[3],
);
The function does a check on the 11th and 12th arguments.
What are the 11th and 12th arguments when the function is passed only 10 arguments?
Is it a bug to call the function with only 10 arguments because the 11th and 12th arguments end up being random values?
I am thinking this may be the source of the bug because the 12th argument had a funky value when the program failed.
I did not see another definition of the function which takes only 10 arguments.
The values are copied out of the parameter array #_ to the list of scalar variables.
If the array is shorter than the list, then the excess variables are set to undef. If the array is longer than the list, then excess array elements are ignored.
Note that the original array #_ is unmodified by the assignment. No values are created or lost, so it remains the definitive source of the actual parameters passed when the subroutine is called.
ikegami suggested that I should provide some Perl code to demonstrate the assignment of arrays to lists of scalars. Here is that Perl code, based mostly on his edit
use strict;
use warnings;
use Data::Dumper;
my $x = 44; # Make sure that we
my $y = 55; # know if they change
my #params = (8); # Make a dummy parameter array with only one value
($x, $y) = #params; # Copy as if this is were a subroutine
print Dumper $x, $y; # Let's see our parameters
print Dumper \#params; # And how the parameter array looks
output
$VAR1 = 8;
$VAR2 = undef;
$VAR1 = [ 8 ];
So both $x and $y are modified, but if there are insufficient values in the array then undef is used instead. It is as if the source array was extended indefinitely with undef elements.
Now let's look at the logic of the Perl code. undef evaluates as false for the purposes of conditional tests, but you apply the length operator like this
if ( length($direction) && length($attempt) ) { ... }
If you have use warnings in place as you should, Perl would normally produce a Use of uninitialized value warning. However length is unusual in that, if you ask for the length of an undef value (and you are running version 12 or later of Perl 5) it will just return undef instead of warning you.
Regarding "I did not see another definition of the function which takes only 10 arguments", Perl doesn't have function templates like C++ and Java - it is up to the code in the subroutine to look at what it has been passed and behave accordingly.
No, it's not a bug. The remaining arguments are "undef" and you can check for this situation
sub foo {
my ($x, $y) = #_;
print " x is undef\n" unless defined $x;
print " y is undef\n" unless defined $y;
}
foo(1);
prints
y is undef

Test::Base::Filter arguments

In the POD for Test::Base, there is an example on rolling my own filters, which the documentation says is "self explanatory". I am having trouble understanding it and I think it may be a problem in my filter writing. The code is reproduced below:
use Test::Base;
filters 'foo', 'bar=xyz';
sub foo {
transform(shift);
}
sub Test::Base::Filter::bar {
my $self = shift; # The Test::Base::Filter object
my $data = shift;
my $args = $self->current_arguments;
my $current_block_object = $self->block;
# transform $data in a barish manner
return $data;
}
The filters function sets the named subroutines as filters on the incoming data. The declared filters are 'foo' and 'bar', which has arguments.
My question is why the structure of foo and bar are so different. Why is foo in the current namespace while bar is declared in the Test::Base::Filter namespace? And why does foo alter its first argument, while bar must grab the data from the second argument?
Another example. In MyTest.pm:
package t::MyTest;
use Test::Base -Base;
#some stuff here
package t::MyTest::Filter;
use base 'Test::Base::Filter';
sub choose {
print #_;
return {foo => 'bar'} if($_[0] eq '1');
return undef;
}
sub is_defined{
print #_;
defined $_[0];
}
And in test.t:
use t::MyTest;
filters {input => [qw(choose is_defined)] };
__END__
=== First
--- input
1
--- expected: 1
=== Second
--- input
0
--- expected: 0
If you place both of those in a "t" folder and run prove -v, this is the output:
t\01-test.t .. Use of uninitialized value $_[1] in print at t/MyTest.pm line 14,
<DATA> line 1.
1
t::MyTest::Filter=HASH(0x2af1670)ok 1 - First
1..1
Failed 1/1 subtests
Test Summary Report
-------------------
t\01-test.t (Wstat: 0 Tests: 0 Failed: 0)
Parse errors: Bad plan. You planned 1 tests but ran 0.
Files=1, Tests=0, 1 wallclock secs ( 0.06 usr + 0.23 sys = 0.30 CPU)
Result: FAIL
Nevermind the warning (which I don't completely understand the root of). Why is the first filter passed the input (like it's supposed to be), but the second one is passed some Filter object? Shouldn't the input of the second filter be the output of the first? If it isn't, then I have to worry about filter ordering all over the place.
I figured this out. I'm pretty sure it's a bug in the way filters work.
The POD says:
Each filter can take either a scalar or a list as input, and will return either a scalar or a list. Since filters are chained together, it is important to learn which filters expect which kind of input and return which kind of output.
Perldoc tells me that undef is a valid scalar in Perl, but Test::Base::Filter ignores it. Normally the input to a Filter would be first the data, and then some other stuff. However, if a filter returns undef, then its return value is ignored and the next filter gets one less argument, instead of getting undef as its first argument. I'll file this in RT.

In Perl, what's the difference between "if defined $count" and "if $count"?

I have the following script:
#!/usr/bin/perl
use warnings;
use strict;
my $count = 0;
my ( #first , #second , #third );
while ($count <= 7){
push ( #first , $count);
push ( #second , $count) if defined $count;
push ( #third , $count) if $count;
$count++;
}
print "first: #first\n";
print "second: #second\n";
print "third: #third\n";
This produces the following output:
first: 0 1 2 3 4 5 6 7
second: 0 1 2 3 4 5 6 7
third: 1 2 3 4 5 6 7
What's the difference between putting if defined $count vs. if $count, other than the latter method won't add the zero to the array? I've searched the perldocs but couldn't find the answer.
Truth and Falsehood in perlsyn explains what values are considered false in a boolean context:
The number 0, the strings '0' and '',
the empty list (), and undef are
all false in a boolean context. All other values are true.
undef is the value of a variable that has never been initialized (or that has been reset using the undef function). The defined function returns true if the value of the expression is not undef.
if $count is false if $count is the number 0, the string '0', the empty string, undef, or an object that has been overloaded to return one of those things when used in a boolean context. Otherwise, it's true. (The empty list can't be stored in a scalar variable.)
if defined $count is false only if $count is undef.
if you see the documentation of defined in perldoc then you will find that
Returns a Boolean value telling
whether EXPR has a value other
than the undefined value undef. If EXPR is not present, $_ is
checked.
A simple Boolean test will not
distinguish among undef, zero, the
empty string, and "0" , which are all
equally false.
that means,
push ( #second , 'undef') if defined $count;
when $count = 0, then it is defined because 0 is different from undef and defined returns true, but in this case push ( #third , 'undef') if $count; if condition fails, that's why it is not pushing 0 into the array.
The defined predicate tests to see whether the variable ($count in this case) is defined at all. In the code you've written, it always will be defined inside the loop because it's always got some value.
If you were to add:
undef $count;
push ( #first , 'undef');
push ( #second , 'undef') if defined $count;
push ( #third , 'undef') if $count;
after the loop, you would see the difference. (Note that I changed the code to add the literal 'undef' instead of $count because you'll get misleading effects from adding the actual undef value.
The if decides to run its block (or single statement) by looking at the value of the expression you give it:
if( EXPR ) { ... }
If that expression is true, it runs its block. If that expression is false, it doesn't.
That expression can be just about anything. Perl evaluates the expression, reducing it to a value that is either true or false. The if() then looks at that value.
So, removing that part of your question, you're left with "What's the difference between defined $count and $count". Well, one is the return value for defined and the other is whatever value is stored in $count.
When you want to figure out what a particular bit of code is doing, reduce it in the same logical process that perl would, one step at a time. See what each step does, and you'll often be able to answer your own questions. :)
You say that you searched the documentation, but I'm not sure where you looked. If you want to look up a built-in function, you can use perldoc's -f switch:
$ perldoc -f defined
If you want to read about Perl's syntax for things such as if, that's in perlsyn.
I have a beginner's guide to the Perl docs in Perl documentation documentation.
The way I read it.
if $count is only true when $count evaluates != 0, hence the third array has no 0 in it.
if defined $count checks to see if the $count as a scalar has been created, and as you have $count scalar, it's the same as the first one.

What pseudo-operators exist in Perl 5?

I am currently documenting all of Perl 5's operators (see the perlopref GitHub project) and I have decided to include Perl 5's pseudo-operators as well. To me, a pseudo-operator in Perl is anything that looks like an operator, but is really more than one operator or a some other piece of syntax. I have documented the four I am familiar with already:
()= the countof operator
=()= the goatse/countof operator
~~ the scalar context operator
}{ the Eskimo-kiss operator
What other names exist for these pseudo-operators, and do you know of any pseudo-operators I have missed?
=head1 Pseudo-operators
There are idioms in Perl 5 that appear to be operators, but are really a
combination of several operators or pieces of syntax. These pseudo-operators
have the precedence of the constituent parts.
=head2 ()= X
=head3 Description
This pseudo-operator is the list assignment operator (aka the countof
operator). It is made up of two items C<()>, and C<=>. In scalar context
it returns the number of items in the list X. In list context it returns an
empty list. It is useful when you have something that returns a list and
you want to know the number of items in that list and don't care about the
list's contents. It is needed because the comma operator returns the last
item in the sequence rather than the number of items in the sequence when it
is placed in scalar context.
It works because the assignment operator returns the number of items
available to be assigned when its left hand side has list context. In the
following example there are five values in the list being assigned to the
list C<($x, $y, $z)>, so C<$count> is assigned C<5>.
my $count = my ($x, $y, $z) = qw/a b c d e/;
The empty list (the C<()> part of the pseudo-operator) triggers this
behavior.
=head3 Example
sub f { return qw/a b c d e/ }
my $count = ()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats = ()= $string =~ /cat/g; #$cats is now 3
print scalar( ()= f() ), "\n"; #prints "5\n"
=head3 See also
L</X = Y> and L</X =()= Y>
=head2 X =()= Y
This pseudo-operator is often called the goatse operator for reasons better
left unexamined; it is also called the list assignment or countof operator.
It is made up of three items C<=>, C<()>, and C<=>. When X is a scalar
variable, the number of items in the list Y is returned. If X is an array
or a hash it it returns an empty list. It is useful when you have something
that returns a list and you want to know the number of items in that list
and don't care about the list's contents. It is needed because the comma
operator returns the last item in the sequence rather than the number of
items in the sequence when it is placed in scalar context.
It works because the assignment operator returns the number of items
available to be assigned when its left hand side has list context. In the
following example there are five values in the list being assigned to the
list C<($x, $y, $z)>, so C<$count> is assigned C<5>.
my $count = my ($x, $y, $z) = qw/a b c d e/;
The empty list (the C<()> part of the pseudo-operator) triggers this
behavior.
=head3 Example
sub f { return qw/a b c d e/ }
my $count =()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats =()= $string =~ /cat/g; #$cats is now 3
=head3 See also
L</=> and L</()=>
=head2 ~~X
=head3 Description
This pseudo-operator is named the scalar context operator. It is made up of
two bitwise negation operators. It provides scalar context to the
expression X. It works because the first bitwise negation operator provides
scalar context to X and performs a bitwise negation of the result; since the
result of two bitwise negations is the original item, the value of the
original expression is preserved.
With the addition of the Smart match operator, this pseudo-operator is even
more confusing. The C<scalar> function is much easier to understand and you
are encouraged to use it instead.
=head3 Example
my #a = qw/a b c d/;
print ~~#a, "\n"; #prints 4
=head3 See also
L</~X>, L</X ~~ Y>, and L<perlfunc/scalar>
=head2 X }{ Y
=head3 Description
This pseudo-operator is called the Eskimo-kiss operator because it looks
like two faces touching noses. It is made up of an closing brace and an
opening brace. It is used when using C<perl> as a command-line program with
the C<-n> or C<-p> options. It has the effect of running X inside of the
loop created by C<-n> or C<-p> and running Y at the end of the program. It
works because the closing brace closes the loop created by C<-n> or C<-p>
and the opening brace creates a new bare block that is closed by the loop's
original ending. You can see this behavior by using the L<B::Deparse>
module. Here is the command C<perl -ne 'print $_;'> deparsed:
LINE: while (defined($_ = <ARGV>)) {
print $_;
}
Notice how the original code was wrapped with the C<while> loop. Here is
the deparsing of C<perl -ne '$count++ if /foo/; }{ print "$count\n"'>:
LINE: while (defined($_ = <ARGV>)) {
++$count if /foo/;
}
{
print "$count\n";
}
Notice how the C<while> loop is closed by the closing brace we added and the
opening brace starts a new bare block that is closed by the closing brace
that was originally intended to close the C<while> loop.
=head3 Example
# count unique lines in the file FOO
perl -nle '$seen{$_}++ }{ print "$_ => $seen{$_}" for keys %seen' FOO
# sum all of the lines until the user types control-d
perl -nle '$sum += $_ }{ print $sum'
=head3 See also
L<perlrun> and L<perlsyn>
=cut
Nice project, here are a few:
scalar x!! $value # conditional scalar include operator
(list) x!! $value # conditional list include operator
'string' x/pattern/ # conditional include if pattern
"#{[ list ]}" # interpolate list expression operator
"${\scalar}" # interpolate scalar expression operator
!! $scalar # scalar -> boolean operator
+0 # cast to numeric operator
.'' # cast to string operator
{ ($value or next)->depends_on_value() } # early bail out operator
# aka using next/last/redo with bare blocks to avoid duplicate variable lookups
# might be a stretch to call this an operator though...
sub{\#_}->( list ) # list capture "operator", like [ list ] but with aliases
In Perl these are generally referred to as "secret operators".
A partial list of "secret operators" can be had here. The best and most complete list is probably in possession of Philippe Bruhad aka BooK and his Secret Perl Operators talk but I don't know where its available. You might ask him. You can probably glean some more from Obfuscation, Golf and Secret Operators.
Don't forget the Flaming X-Wing =<>=~.
The Fun With Perl mailing list will prove useful for your research.
The "goes to" and "is approached by" operators:
$x = 10;
say $x while $x --> 4;
# prints 9 through 4
$x = 10;
say $x while 4 <-- $x;
# prints 9 through 5
They're not unique to Perl.
From this question, I discovered the %{{}} operator to cast a list as a hash. Useful in
contexts where a hash argument (and not a hash assignment) are required.
#list = (a,1,b,2);
print values #list; # arg 1 to values must be hash (not array dereference)
print values %{#list} # prints nothing
print values (%temp=#list) # arg 1 to values must be hash (not list assignment)
print values %{{#list}} # success: prints 12
If #list does not contain any duplicate keys (odd-elements), this operator also provides a way to access the odd or even elements of a list:
#even_elements = keys %{{#list}} # #list[0,2,4,...]
#odd_elements = values %{{#list}} # #list[1,3,5,...]
The Perl secret operators now have some reference (almost official, but they are "secret") documentation on CPAN: perlsecret
You have two "countof" (pseudo-)operators, and I don't really see the difference between them.
From the examples of "the countof operator":
my $count = ()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats = ()= $string =~ /cat/g; #$cats is now 3
From the examples of "the goatse/countof operator":
my $count =()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats =()= $string =~ /cat/g; #$cats is now 3
Both sets of examples are identical, modulo whitespace. What is your reasoning for considering them to be two distinct pseudo-operators?
How about the "Boolean one-or-zero" operator: 1&!!
For example:
my %result_of = (
" 1&!! '0 but true' " => 1&!! '0 but true',
" 1&!! '0' " => 1&!! '0',
" 1&!! 'text' " => 1&!! 'text',
" 1&!! 0 " => 1&!! 0,
" 1&!! 1 " => 1&!! 1,
" 1&!! undef " => 1&!! undef,
);
for my $expression ( sort keys %result_of){
print "$expression = " . $result_of{$expression} . "\n";
}
gives the following output:
1&!! '0 but true' = 1
1&!! '0' = 0
1&!! 'text' = 1
1&!! 0 = 0
1&!! 1 = 1
1&!! undef = 0
The << >> operator, for multi-line comments:
<<q==q>>;
This is a
multiline
comment
q