Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Documentation for the object Signature: " ... different name for a named argument than the variable name"

An example on the 'class Signature' page appears as:

sub named(:official($private)) { "Official business!" if $private }; named :official; <----- Note: That's where to example ends ... there is no output described or shown. So I typed in the code and when the method 'named' is executed it always prints "Official business!" no matter the value of $private. That is, if $private=True then invoking 'named' prints "Official business!" as you might expect but with $private=False invoking 'named' still prints 'Official business!' whereas I thought there should be no output generated. I'm missing something aren't I but what?

like image 601
Keith Hardy Avatar asked Nov 07 '21 17:11

Keith Hardy


3 Answers

I see how the doc example was confusing. Here's an expanded version of that explanation:

sub named(:official($private)) {
   # Inside the function, the argument the caller passed in
   # is bound to the variable $private.  Nothing is bound to official.
   say $private;
}

# Outside the function, the caller doesn't need to care what term the 
# function uses.  All it needs to know is the name of the parameter – :official
named(:official('foo')); # OUTPUT: «foo»

This is especially handy when the function is in a different module – the owner of the function can refactor the name of the their $private argument without breaking any external callers. And, if they think of a better name for external callers to use, they can even add that without breaking backwards compatibility: sub named(:official(:better-name(:$private))) { … } lets callers use either :official or :better-name as the parameter name, without having any impact on the variable name inside the function.

Does that make more sense?

Oh, and one note regarding this:

if $private=True then invoking 'named' prints "Official business!" as you might expect

If I'm understanding you correctly, you mean writing something like

sub named(:official($private)=True) { "Official business!" if $private }

Is that what you meant? If so, you should know that $private=True in that signature isn't really setting $private to anything – it's just providing a default value for the variable $private. So you can get this output:

sub named(:official($private)=True) {
      say $private;
}

named();               # OUTPUT: «True»
named(:official(42));  # OUTPUT: «42»

In any event, I'll send in a PR to the docs repo and try to clarify the named argument examples a bit. Hope you enjoy Raku!

like image 162
codesections Avatar answered Nov 19 '22 17:11

codesections


There are a couple of things going on in this short example:

sub named(:official($private)) { "Official business!" if $private }
           -------- --------
               |        |
               |        > '$private' is the name of this var within the sub
               |
               > 'official' is the (sigilless) name of this var outside
           
           ------------------
                   |
                   > ':official($private)' is the 
                            raku Pair 'official => $private'  

named :official
----- ---------
  |       |
  |       > the raku Pair 'official => True' (so $private ~~ True)
  |
  > the same as 'named( official => True );'

So when you try this in the repl...

> named :official;             #Official business!
> named( official => True )    #Official business! [same thing]
-or-
> named :!official             #()
> named( official => False )   #() [same thing]

At first encounter, in this example, raku is quite quirky. Why?

  • the raku Pair literal syntax makes it easy to handle common function argument cases such as :dothis but :!notthat adverbs
  • the :name(value) formulation is re-used here to map external to internal var names - nothing special needed since the Pair syntax already does it - but super useful for code encapsulation
  • similar situation with argument aliases ... you can think of this as Pairs of Pairs ... again, no special syntax needed since just using the built in Pair literal syntax

So, imho, raku is uniquely cool in that we just have to learn some basic elemental syntax (in this case, the Pair literals) and then they can be applied consistently in many ways to concisely solve quite thorny coding scenarios.

like image 7
p6steve Avatar answered Nov 19 '22 18:11

p6steve


Via pretzel logic I've concluded that:

  • You may have carefully written your Q to trick us, and you will reveal the truth if we correctly solve the riddle.

Or (a tad more likely perhaps... 🤡):

  • Adopting that mindset will help us all -- you, readers, answerers -- have fun as we try to solve the riddle inherent in your sincere Q even if you weren't planning to make this fun...

Either way, please read this answer and let me know if it contributes to solving the riddle. TIA. :)


I'm missing something aren't I but what?

Perhaps this is a key for solving the riddle: we're supposed to ask ourselves "What has Keith deliberately missed out of the Q?".

Of course, if this is so, the first thing you've omitted is that it's a riddle. In which case, major kudos! And if it's not an intentional riddle, well, it's still a riddle, so kudos anyway, and let's try solve it!


@codesection's answer points at perhaps the strongest clue. While you didn't write a minimal reproducible example, you did write the sub definition code, and you did say you'd written $private=False.

So let's presume you literally wrote that sub definition and you literally wrote $private=False.

Furthermore, that:

with $private=False invoking 'named' still prints 'Official business!' whereas I thought there should be no output generated.

means there was some output generated in all cases.

Anyhoo, how can all of these things be true at the same time?


These are compile-time errors:

sub named( :official( $private = True ) )   { "Official business!" if $private }
sub named( :official( $private = False ) )  { "Official business!" if $private }

So is this:

$private = False;

unless there was a prior my $private....

And this:

sub named( :official( $private ) ) {
  $private = True;
  "Official business!" if $private
}
named;

yields Cannot assign to a readonly variable or a value (currently at runtime) because, by default, parameters to routines are readonly.


You also said there was output (ostensibly Official business!, but perhaps sometimes something else, eg ()?).

You didn't mention a say or similar routine for displaying output. How could that be? Let's introduce a say.


So, putting these things together, and applying pretzel logic, I arrived here:

sub named(:official($private)) { "Official business!" if $private }
my $private;
$private = False;
say named :official;         # Official business!
say named :!official;        # ()
say named official => False; # ()
say named :official(False);  # ()
say named;                   # ()

An interpretation of this as solving the riddle:

  • () is not "no output". So it doesn't contradict your Q narrative.

  • We've written $private = False. It has no impact on the code, because of lexical scoping, but we did write it. :)


Am I warm?

like image 5
raiph Avatar answered Nov 19 '22 18:11

raiph