If I have a variable my $a = True
, then I get this output from the following code:
say «a list of words foo $a bar baz».raku;
# OUTPUT: ("a", "list", "of", "words", "foo", "True", "bar", "baz")
That is, even though the result is a List
, the element True
is stringified before being included in the list – the list contains "True"
, not True
. Is there any way to avoid that stringification while still using interpolation?
Would there be a way to do so if $a
were a class I'd defined (and thus can write the Str
method for) rather than a Bool
?
(I am aware that I can write the more verbose ("a", "list", "of", "words", "foo", $a, "bar", "baz")
or «a list of words foo».Slip, $a, «bar baz».Slip
, but I'm asking if there is a way to still use interpolation).
Interpolation is putting a thing into a string.
"a b c $thing d e f"
It does that by first turning the thing itself into a string, and concatenating the rest of the string around it.
Basically the above compiles into this code:
infix:<~>( 「a b c 」, $thing.Str, 「 d e f」 )
« a b c $thing »
Is short for:
Q :double :quotewords « a b c $thing d e f »
That is use the Q
uoting DSL, turning on :double
quote semantics (“”
) and turning on :quotewords
.
:quotewords
is the feature which splits the string into its individual parts.
It happens only after it has been turned into a string.
Imagine that the above compiles into:
Internals::quotewords( infix:<~>( 「 a b c 」, $thing.Str, 「 d e f 」 ) )
There is another way to get what you want, other than using .Slip
or prefix |
.
flat «a list of words foo», $a, «bar baz»
The whole purpose of the quoting DSL is that it produces a string.
That said :words
, :quotewords
, and :val
all change it so that it returns something other than a single string.
And the idea of them is that they alter the DSL.
So MAYBE you could convince enough people that such a change would be worth it. Thats a big maybe.
It would potentially break many existing codebases, so you would have an uphill battle to do so.
What happens here has little to do with quoting, and a lot to do with context. As @brad-gilbert has indicated, anything that goes passes through putting ~
in front, which is coercing the variable to a String
context.
But that yields an answer to your second question:
Would there be a way to do so if $a were a class I'd defined (and thus can write the Str method for) rather than a Bool?
Theoretically, something like this should work:
class A {
has Bool $.foo;
method Str { $.foo }
};
my $a = A.new( :foo(True) );
say «a b $a».raku
Alas, this returns «No such method 'WORDS_AUTODEREF' for invocant of type 'Bool'
so it probably needs a bit of work (or I might have bumped into some bug). So this is, for the time being, and for your precise example, a nanswer. As a matter of fact, only Str
s have that method, so I think that for the time being, and unless you bother to create that specialized method for a class, it's difficult to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With