Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interpolate without creating a String context in Raku?

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).

like image 216
codesections Avatar asked Mar 15 '21 17:03

codesections


Video Answer


2 Answers

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 Quoting 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.

like image 99
Brad Gilbert Avatar answered Oct 23 '22 20:10

Brad Gilbert


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 Strs 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.

like image 33
jjmerelo Avatar answered Oct 23 '22 22:10

jjmerelo