Day 10 – The Magic Of Q

Santa continued their dabbling in the Raku Programming Language, but got confused by single quotes, double quotes, and all the things that start with q/. So they decided to have Lizzybel do an exposé about the mechanisms behind quoting.

But I already did that 9 years ago! Lizzybel exclaimed! Well, I certainly don’t remember that, said Santa, and we got a bunch of new elves, so maybe it will be of help to them as well.

Lizzybel thought: I guess it is a good idea, since an exciting new feature is on the horizon. After a little work, they called Santa and the new elves together, and started presenting:

Quoting strings in Raku

In the Raku Programming Language, one can indicate static strings with single quotes. And one can easily interpolate scalar variables in any string with double quotes:

my $a = 42;
say 'a = $a'; # a = $a
say "a = $a"; # a = 42

Both of these quoting constructs are just a special case of a much more generic and malleable quoting construct, named Q.

Note that say will always add a newline after the string: for the sake of this presentation, these will not be shown in the examples.

Q’s Basic Features

In its most generic form, Q just copies the string without any changes or interpretation:

my $a = 42;
say Q/foo $a \n/; # foo $a \n

You can add adverbs to Q/…/, to change the way the resulting string will be formatted. For instance, if you want to have interpolation of scalars, you can add :s. If you want interpretation of backslashes like \n, you can add :b. And you can combine them:

my $a = 42;
say Q:s/foo $a\n/;   # foo 42\n
say Q:b/foo $a\n/;   # foo $a␤
say Q:s:b/foo $a\n/; # foo 42␤

If you wonder what a  is, it is a U+2424 SYMBOL FOR NEWLINE [So] (␤) and should be show up in your browser as a character containing an N and an L as a visible representation of a new line character. This is done in these examples because you wouldn’t be able to really see newlines otherwise.

In fact, the list of adverbs of basic quoting features is:

  short   long        what does it do
===== ==== ===============
:q :single Interpolate \\, \q and \'
:s :scalar Interpolate $ vars
:a :array Interpolate @ vars
:h :hash Interpolate % vars
:f :function Interpolate & calls
:c :closure Interpolate {...} expressions
:b :backslash Interpolate \n, \t, etc. (implies :q at least)

The :q (or :single) adverb gives you single quoted string semantics. And to make life easier for you, Q:q/present/ can be shortened to q/present/, and would be the same as the more familiar 'present'.

The other adverbs together give you typically the functionality that you would expect from double quoted strings. If you really want to be verbose on your double quoted strings, you can write them like this:

my $a = 42;
say Q :scalar :array :hash :function :closure :backslash /foo $a\n/; # foo 42␤

Of course, you can also specify the short versions of the adverbs, and not separate them by whitespace. So, if you want to be less verbose:

my $a = 42;
say Q:s:a:h:f:c:b/foo $a\n/; # foo 42␤

As with any adverbs (which are just named arguments, really), the order does not matter:

my $a = 42;
say Q:f:s:b:a:c:h/foo $a\n/; # foo 42␤

.oO( is that Franz Sebastian, a brother of Johann Sebastian? )

Actually, the story about the order of the named arguments is a little bit more complicated than this. But for this set of adverbs, it does not matter in which order they are specified.

But seriously, that is still a mouthful. So an even shorter shortcut is provided: :qq.

  short   long        what does it do
===== ==== ===============
:qq :double Interpolate with :s, :a, :h, :c, :b

So these are all essentially the same under the hood:

my $a = 42;
say Q:double/foo $a\n/; # foo 42␤
say Q:qq/foo $a\n/;     # foo 42␤

All that for simply doing a double quoted string with interpolation?

Well, because people are using double quoted strings a lot, the simple " (U+22 QUOTATION MARK) remains the quickest way of interpolating values into a string. However, underneath that all, it’s really Q:qq, which in turn is really Q:f:s:b:a:c:h (or Franz Sebastian Bach, as a mnemonic).

But what about a double quoted string that has double quotes in it, you might ask? That’s one of the use cases for the Q:qq form! But that is still quite verbose.

Fortunately, all simple quote-like forms derive from Q with adverbs! Which means we can shorten the Q:qq in that last example to qq (and thus have double quotes in the double quoted string without any problems):

my $a = 42;
say qq/foo "$a"\n/; # foo "42"␤

Both q// and qq// also support (the same) adverbs as Q. This initially seems the most useful with q//, for instance in combination with :s, which would allow you to interpolate (just) scalars:

my $a = 42;
say q:s/foo "$a"\n/; # foo "42"\n

However, adverbs (just as named parameters) are just a shortcut for a Pair: :s is really s => True. And :!s is really just s => False. Can we also apply this to quoting constructs? The answer is: yes, you can!

say qq:!s:!c/foo "$x{$y}"\n/; # foo "$x{$y}"␤

In this example, even though we specified qq//, the scalar is not interpolated, because of the :!s adverb. And the scope is not interpolated, because of the :!c. This can for instance be handy when building strings to be EVALled.

So, if you want all quoting features except one or more, you can easily de-activate that feature by negating the appropriate adverbs.

Non-stringy quoting

All of the above quoting adverbs produce a single string. But some quoting adverbs actually produce something else! They are:

  short   long         what does it do
===== ==== ===============
:v :val Process result(s) with val()
:w :words Split text as words (no quote protection)
:ww :quotewords Split text as words (with quote protection)

The :v adverb causes the result(s) of the quoting construct to be passed to the val() function, which will produce an allomorph if possible.

say q:v/foo/;        # foo
say q:v/foo/.^name;  # Str
say q:v/42/;         # 42
say q:v/42/.^name;   # IntStr
say q:v/42e0/;       # 42e0
say q:v/42e0/.^name; # NumStr
say q:v/42.0/;       # 42.0
say q:v/42.0/.^name; # RatStr
say q:v/42i/;        # 42i
say q:v/42i/.^name;  # ComplexStr

Note that unless you really look carefully (in this case by using the ^name method that shows the name of the class of the object) you would not see the difference with an ordinary string.

The :w and :ww adverbs both split the string on whitespace. If there is only one part found, it will produce a Str of that one part found. Otherwise it will produce a List with those parts, which could be an empty List if the string consisted of whitespace only, or was empty.

say q:w/foo bar  baz/;  # (foo bar baz)
say q:ww/foo bar  baz/; # (foo bar baz)

So what is the difference between :w and :ww? The :ww adverb applies so-called “quote protection“. This means that if a balanced quoting construct is found in the string, it will be preserved. For example:

say q:ww/foo 'bar  baz'/; # (foo bar  baz)
dd  q:ww/foo 'bar  baz'/; # ("foo", "bar  baz")

Note that we also used dd to show the result, because otherwise it would be hard to see the difference with :w.

Single adverb shortcut

If you want to use a quoting construct with just a single short adverb, you can write that without the colon. Some examples you might encounter in existing code:

  long      short    notes
==== ===== =====
q:w/…/ qw/…/ word quoting
q:ww/…/ qww/…/ word quoting with quote protection
qq:w/…/ qqw/…/ word quoting with interpolation
qq:ww/…/ qqww/…/ Word quoting with interpolation & quote protection
q:s/…/ qs/…/ Scalar value interpolation only

So these are not completely different quoting constructs, they are just shortcuts.

Quoting without q

So far, we’ve seen two types of quoting that do not start with q (or Q):

  quote    Q-repr    q-repr   notes
===== ====== ====== ===============
'…' Q:q/…/ q/…/ No escaping except \, q and /
"…" Q:qq/…/ qq/…/ Alternately: Q:f:s:b:a:c:h

There are a number of other shortcuts for often used quoting constructs that you may find familiar.

  quote    Q-repr        q-repr     notes
===== ====== ====== ===============
「…」 Q/…/ No escaping whatsoever
<…> Q:q:w:v/…/ qw:v/…/ Split on ws, do val() processing
<<…>> Q:qq:ww:v/…/ qqww:v/…/ Same, but keep quoted string
«…» Q:qq:ww:v/…/ qqww:v/…/ Same as << >>, using non-ASCII

Any other quoting constructs using unicode alternatives to the single quote and the double quote, act as their ASCII counterparts….






Santa had started to move around their chair nervously, while some of the elves started fidgeting. I think that’s quite enough for one day, Santa said while getting up, Let’s do the rest another day! Lizzybel was a bit disappointed, as they were just getting up to speed.

On the other hand, it was a lot of stuff to fully grasp. I hope you all got the basics so far?, Lizzybel asked. The mumbling from the class was undeterminable, and the elves also started leaving. If at least one elf got what I just tried to teach, it’ll be a net gain, thought Lizzybel, while closing the presentation room after the last elf had left.

2 thoughts on “Day 10 – The Magic Of Q

  1. thank you for the exhaustive lesson in q-ing! i have a question: how does associative indexing engage quoting constructs? if the canonical form is %hash{‘one’, ‘two’}, then is the angle bracket %hash<> form like eg. %hash<three four> a shortcut for %hash{qw:v/three four/} then, maybe?

    Like

    1. Yes, it is. < > quoting is also applied when it is used in associative indexing. Normally, you wouldn’t notice this at all, but it can be made manifest with an object hash: my %a{IntStr}; %a = “foo” would be ok, but %a{42} = “foo” would not.

      Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.