Raku / user-experience

Identifying issues in and improving the Raku user experience
Artistic License 2.0
25 stars 5 forks source link

qw Word quoting returns Str with one word #46

Open iacore opened 2 years ago

iacore commented 2 years ago

The documentation says that qw split input into words.

However...

[14] > qw|a|.WHAT
(Str) #why???
[15] > qw||.WHAT
(List)
[16] > qw|a b|.WHAT
(List)

Example showing why this is problematic

test.raku:

sub gimme-positional(@pos) {
    say @pos.raku;
}

gimme-positional qww<a b>;
gimme-positional qww<a>;
> raku test.raku
===SORRY!=== Error while compiling test.raku
Calling gimme-positional(Str) will never work with declared signature (@pos)
at test.raku:6
------> <BOL>⏏gimme-positional qww<a>;

Even worse: (because you cannot use *@pos)

sub gimme-positional(:@keyed) {
    say @pos.raku;
}

gimme-positional keyed => qww<a b>;
gimme-positional keyed => qww<a>;

Some error here.

thundergnat commented 2 years ago

The behavior is due to the Single Argument Rule. Not to say that it isn't confusing at first, or that the docs for quoting constructs don't mention it. It is confusing if you don't know why, and the docs don't cover every possible situation.

Single Argument Rule is one of those thing along the DWIM / WAT continuum. It mostly exists to make things like below work more how most people expect. (When coming from a Perl background. Which is what Raku was primarily catering to for the first 10 years or so.)

my @a = 1,2,3;
my @b = @a;
.say for @b;

with the single argument rule:

1
2
3

without, it would be:

[1,2,3]

( @b would contain one item in slot 0 - the array [1,2,3] )

For a qw<> construct it shouldn't really be an issue. You won't ever get anything other than what is in there. If you know you will need a Positional and you only have one item, either use a different quoting form or explicitly coerce. When using qqw<> constructs that interpolate, you probably should explicitly coerce because you may not know how many items will be returned. Probably not a bad idea to always explicitly coerce anyway.

sub gimme-positional(:@keyed) {
    say @keyed.raku;
}

gimme-positional keyed => qww<a b>.list;
gimme-positional keyed => qww<a>.list
("a", "b")
("a",)
iacore commented 2 years ago

How to declare my own quoting construct?

I figured out that I can do @(<a>).raku.