11

I was gonna edit this into my other related question, but it feels different enough and I don't want to ask too many questions per question.


My mind... has exploded.

Consider:

use strict;

my Int $n = 6;
my Str $x = "a";
my @l = $n, $x;
say @l ~~ List;

Prints True, as expected.

Consider, then:

use strict;

my Int $n = 6;
my Str $x = "a";
my List @l = $n, $x; # <-- only change is the type notation
say @l ~~ List;

Which dies with:

Type check failed in assignment to @l; expected List but got Int

So... the type of List is List but I can't say it's List because that's a sin!

What's going on here? Is this a bug? Or am I bringing my irrelevant Python and Go idioms to Perl and breaking things?

12
  • 1
    @Hunter, you made the pretty colours go away! (The reason I tagged it with perl is so I could have syntax highlighting, but if you think organisation is more important then fair enough.)
    – cat
    Commented Jan 25, 2016 at 16:44
  • 1
    Apparently the perl6 tag doesn't have a default syntax highlighting hint associated with it. I've added Perl 5 hints for now. I haven't used Perl 6, but I'm guessing the syntax is close enough that the highlighting should be the same. Maybe I'll make a request on Meta. Commented Jan 25, 2016 at 16:56
  • 4
    @ThisSuitIsBlackNot There is quite a bit of new syntax, actually. Sometimes even vim has a hard time dealing with it, in my experience. Commented Jan 25, 2016 at 16:58
  • 1
    @ChristopherBottoms Good to know. Are the differences pronounced enough that the highlighting on SO is consistently bad/wrong? Google prettify is simplistic enough that it screws up Perl 5 highlighting sometimes, but it's fine for most questions, and generally better than no highlighting at all. Commented Jan 25, 2016 at 17:02
  • 2
    @ThisSuitIsBlackNot I think a post on Meta would be a good idea to get feedback, I for instance think the separation would be beneficial both for organization and getting the "right" people to look at the question. Knowledge of Perl5 doesn't imply any knowledge of Perl6. Users could subscribe to both if they were interested in both languages. Commented Jan 25, 2016 at 17:44

2 Answers 2

12
my List @l = $n, $x;

doesn't do what you think it does. It doesn't declare that @l is a List. It declares that the elements of @l will be Lists. You don't need to declare that @l will be an array; you already did that when you used the sigil.

You can move the explosion around by replacing List with Int to make Perl 6 expect a list of Ints.

3
  • @cat You can force it to be a particular class of Positional my class MyArray does Positional {...}; my @a is MyArray; This is useful for some uses of hashes my %h is SetHash; %h{$_}++ for 'HelloWorld'.comb; say %h => SetHash.new(r, l, W, H, e, d, o)␤ You currently can't combine this syntax with assignment though which makes my @a is List; rather pointless as you can't ever assign any elements to it (The default being Array which is mutable). Commented Jan 25, 2016 at 17:38
  • @BradGilbert: but you can use binding; a my @a is List variable cannot be bound to things that do not derive from List
    – Christoph
    Commented Jan 25, 2016 at 21:19
  • @Christoph I thought I tried binding after the declaration, I guess I didn't. Commented Jan 25, 2016 at 22:22
10
my List @l;

is shorthand notation for

my @l is Array of List;

which places a List type constraint on the elements of the array.

The type constraint on the container is already expressed via the @ sigil, corresponding to the role Positional, whereas a % sigil corresponds to the role Associative.

The case of $ variables is similar insofar as there's also a container involved (a Scalar) with a constraint on its single element. However, the constraint also allows direct rebinding to a decontainerized value1.


1 If the above does not make sense to you, you should look into the difference between assignment = and binding :=. It might also be instructive to inspect the variable via .VAR.WHAT.

Note that we can also rebind to another scalar container as long as its element meets the type constraint at time of binding.

This can be used to subvert the type system:

my Int $a;
my $b = 42;
$a := $b;
$b = "not cool";
say $a;

Not cool :(

6
  • 1
    Is that cheating of the type system intentionally allowed?
    – cat
    Commented Jan 25, 2016 at 23:46
  • 1
    @cat: looks like a bug (or at the very least a misfeature) to me; I can't think of anything obvious that would prevent fixing this
    – Christoph
    Commented Jan 26, 2016 at 4:27
  • This is not a bug. my Int $a creates a scalar container of type Int and with default of Int (that does not got a name) and binds the locally scoped name $a to it. With my $b = 42 you create a container of type Any and default Any and assign 42 to it. The binding of $a to $b changes the container of $a to the container of $b. The original container that $a was bound to is lost. Now the container of $a is of type Any and default Any. If the type constraint would stick to the name $a, you would never be able to bind anything to anything.
    – user5854207
    Commented Jan 28, 2016 at 23:06
  • @gfldex: I'm pretty sure I had a test case where the constraint survived the rebinding (possibly due to some static analysis?), but I cannot reproduce it; I'll see if I can figure out what I did before...
    – Christoph
    Commented Jan 29, 2016 at 5:14
  • @gfldex: I might have been mistaken; however, what does survive is the constraint on rebinding the variable, eg my Int $a; my $b = 42; $a := $b; $a := Str
    – Christoph
    Commented Jan 29, 2016 at 5:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.