perlquestion
tomgracey
<p>Hello Monks</p>
<p>After some consideration I've decided to continue posting my Raku questions on perlmonks. It is tempting to just go directly to the Raku IRC channel, however then the question/answer doesn't get recorded and thereby potentially help someone else out. When I was getting to grips with Perl I rarely needed to ask questions as I could nearly always find someone who had already posted a similar problem. With Raku searching doesn't seem to bring up so many Q and A type threads. No doubt much of this is due to it being so new, but I can't wondering if encouraging people to resolve problems via chat is actually that helpful. I don't know. Could be wrong. Just what immediately springs to mind. (Of course there is stackoverflow, but lets just say I am not such a great fan of their moderation methodology)</p>
<p>Anyway the show must go on, so here is my question:</p>
<p>Lets say I have the following (contrived) code:</p>
<code>
class Hamper {
has $.name = 'Christmas Basket';
has @.items is rw = 'Mince Pie', 'White Wine', 'Stinky Cheese';
}
my $hamper = Hamper.new;
say "Name: " ~ $hamper.name;
say "Items: " ~ $hamper.items;
</code>
<p>This works as expected (that is I expect!), spitting out</p>
<code>
Name: Christmas Basket
Items: Mince Pie White Wine Stinky Cheese
</code>
<p>However, say I want to limit the size of <code>@!items</code> to 3 elements. That is, I want the code to fall over with an error if I try to put 4 elements into it. And this is where I'm already not sure if I'm even going about it in the right way in the first place. My understanding (mentioned in <a href='https://docs.raku.org/type/Array'>the docs</a>, and also e.g <a href='https://stackoverflow.com/questions/50723156/how-to-declare-native-array-of-fixed-size-in-perl-6'>this post</a>) is that I ought to be able to limit the size of the "positional" by changing the line which defines <code>@.items</code> to:</p>
<code>
has @.items[3] is rw = 'Mince Pie', 'White Wine', 'Stinky Cheese';
</code>
The output is then:
<code>
===SORRY!=== Error while compiling /path/script.raku
Defaults on compound attribute types not yet implemented. Sorry.
Workaround: Create/Adapt TWEAK method in class Hamper, e.g:
method TWEAK() {
@!items := (initial values) unless @!items;
}
at /path/script.raku:3
</code>
<p>I assume this to mean I created my fixed length positional successfully, but need to assign defaults separately because the compiler has not yet been trained on this particular scenario. Fair enough. So I do literally as the error message recommends, adding in the <code>TWEAK</code> method. My code now reads:</p>
<code>
class Hamper {
has $.name = 'Christmas Basket';
has @.items[3] is rw;
method TWEAK(){
@!items := 'Mince Pie', 'White Wine', 'Stinky Cheese' unless @!items;
}
}
my $hamper = Hamper.new;
say "Name: " ~ $hamper.name;
say "Items: " ~ $hamper.items;
</code>
<p>Now the output is</p>
<code>
Name: Christmas Basket
Use of uninitialized value element[0] of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
in block <unit> at script.raku line 16
Use of uninitialized value element[1] of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
in block <unit> at script.raku line 16
Use of uninitialized value element[2] of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
in block <unit> at script.raku line 16
Items:
</code>
<p>Yuck! The defaults for <code>@!items</code> do not appear to get assigned. But if I remove <code>unless @!items</code> then I get:</p>
<code>
Name: Christmas Basket
Items: Mince Pie White Wine Stinky Cheese
</code>
<p>as desired. But now the "defaults" overwrite any user specified values. E.g. if I change the <code>my $hamper</code> line to be</p>
<code>
my $hamper = Hamper.new( items => ('Dog', 'Cat', 'Sausage') );
</code>
<p>The output without the <code>unless @!items</code> is still</p>
<code>
Name: Christmas Basket
Items: Mince Pie White Wine Stinky Cheese
</code>
<p>which is not what anyone would want. So is that error message bad advice - or otherwise what is happening? Why is it that <code>unless @!items</code> seems to be triggered when <code>@!items</code> is surely empty?</p>
<p>Unfortunately I'm nowhere near done yet!</p>
<p>Say I keep the line which assigns the "defaults", without the <code>unless @!items</code> - ie accepting (for the time being) it writes over user specified values</p>
<p>What happens if I try to assign more than 3 values to <code>@!items</code>?</p>
<code>
method TWEAK(){
@!items := ('Mince Pie', 'White Wine', 'Stinky Cheese', 'Sardines', 'Dogfood');
}
</code>
<p>The output is then:</p>
<code>
Name: Christmas Basket
Items: Mince Pie White Wine Stinky Cheese Sardines Dogfood
</code>
<p>Yup.. it appears to completely ignore the 3 element limit that (I believed) was placed on <code>@!items</code>. Shouldn't it be falling over? What is with that? (Ok as I write this I think I can hazard a guess - the answer is going to be something along the lines of "the fixed limit restriction applies to the accessor and not to the underlying attribute, and since in <code>TWEAK</code> you are accessing the attribute directly the restriction is circumvented." Fine if this is the case...
</p>
<p>But final thing. My <code>@!items</code> are all strings. Say I want to etch that in stone:</p>
<code>
has Str @.items[3];
</code>
<p>(At least, I am under the impression that <code>Str</code> used in that context should apply a restriction to the elements of <code>@.items</code>... or did I get that wrong?)</p>
<p>So now my code looks like this:</p>
<code>
class Hamper {
has $.name = 'Christmas Basket';
has Str @.items[3] is rw;
method TWEAK(){
@!items := ('Mince Pie', 'White Wine', 'Stinky Cheese');
}
}
my $hamper = Hamper.new;
say "Name: " ~ $hamper.name;
say "Items: " ~ $hamper.items;
</code>
<p>And drumroll for the output...</p>
<code>
Type check failed in binding; expected Positional[Str] but got List (("Mince Pie", "White...)
in method TWEAK at script.raku line 9
in block <unit> at script.raku line 13
</code>
<p>So what's going on there? Did I inadvertently define a 3 character string/some other weird entity? I realise the vagueness of my understanding of what a 'Positional' vs 'List' and/or 'Array' may be the bottleneck here.</p>
<p>I guess this is very rambling way of simply asking, "In Raku, how do you define an object attribute that is a fixed length list with typed elements, and assign defaults to it?" However, I thought I'd post in tedious detail in the hope of rectifying all aspects of my confusion.</p>
<p>Thanks for reading this far. You should think about going on holiday. You deserve it.</p>