Use of colon in method and function calls in Perl 6

743 views Asked by At

I'm wondering what colons have to do with method and function calls in Perl 6. For the record, I am using perl6 version 2015.05-55-gd84bbbc built on MoarVM version 2015.05.

I just saw the following in a Perl6 spec test (S32-io) (I added the comment):

$fh.print: "0123456789A";   # prints '0123456789A' to the file

As far as I can tell, this is equivalent to:

$fh.print("0123456789A");   # prints '0123456789A' to the file

Both of these seem to take multiple arguments and to flatten lists fine:

$fh.print: "012", "345", "6789A";   # prints '0123456789A' to the file
$fh.print("012", "345", "6789A");   # prints '0123456789A' to the file

my @a = <012 345 6789A>;

$fh.print(@a);   # prints '0123456789A' to the file
$fh.print: @a;   # prints '0123456789A' to the file

There must be some reason to have these two different syntaxes. Is there any reason to use one or the other syntax?

I also noticed that we have to use either : or () with print, when used as a method:

$fh.print(@a);   # Works
$fh.print: @a;   # Works!
$fh.print @a;    # ERROR!

There is also some interesting behavior when using a colon with the function print. In this case, : and () are not equivalent:

print @a;  # Prints '0123456789A' (no newline, just like Perl 5)
print(@a); # Ditto
print: @a; # Prints '012 345 6789A' followed by a newline (at least in REPL)

print  @a, @a; # Error (Two terms in a row)
print: @a, @a; # Prints '012 345 6789A 012 345 6789A' followed by a newline (in REPL) 

Then I tried using print in a script file. This works for prints to standard output:

print @a;

However, this does not print to standard output:

print: @a, @a;

But the method version works fine:

$fh.print: @a, @a; # Prints '0123456789A0123456789A' to the file

I feel like I almost understand this, but I can't put it into words. Could someone please explain these varieties of using print. Also, are these behaviors going to change due to the Great List Refactor?

2

There are 2 answers

2
Brad Gilbert On BEST ANSWER

One of the main reasons to use a colon instead of parens is that it can help declutter your code, by removing one set of parens. Otherwise they are exactly the same.

When you have print: @a, what you are really doing is putting a label on the line, and letting the @a fall-through. Which in the REPL will call say with the value.

If you don't use parens or a colon on a method call, then the method would get called with no arguments.


You can swap the order of the method, and the invocant if you use a colon.

say $*ERR: 'hello world'; # $*ERR.say('hello world')
0
Marty On

Just to clarify a little further - using the colon instead of parentheses is an alternative method calling syntax, not an alternative function calling syntax. It's very handy when passing a function or block as an argument to a method. Using grep or map are common examples - consider;

@measurements.map( { check_accuracy($_); fail "bad value" if $_ < 0 }  );

Notice I've put an extra space after the closing curly to try and separate the function I'm passing from the necessary syntax required to close off the method call. The reader of this code fully understands the whole block is an argument of the call and is usually focussed on what the contents of the block is going to achieve - and then comes across what I call the "Lone Paren" - and like the Lone Ranger is always seen with his trusty steed, Silver, the Lone Paren is nearly always next to his trusty steed, Semicolon.

Why not junk them both?

The alternative method call syntax combined with the semicolon being optional if a statement finishes with a closing curly, makes that possible;

@measurements.map:  { check_accuracy($_);  fail "bad value" if $_ < 0 }

Much better.
While the alternative method call format is another bit of syntax to learn, it's easily understood and in some circumstances, like above, makes the resultant code cleaner and easier to read.