For the last couple weeks I've been experimenting with Perl6 because I
finally became sufficiently annoyed with Python's lack of real (No GIL)
threading and a quick inspection of the Perl6 feature list looked
promising. I'm trying to keep an open mind because Perl is pretty
culturally different than the languages that I'm used to working with (C++
may give optimized code but it is not trying to be -Ofun) so although I've
run into a few stumbling blocks I mean for the points below to just be
observations -- I don't have a feel yet for whether or not some of these
things are hard for me because I'm not used to them or because they are
problem in the language design. Maybe you all can set me straight.

I've read both the "Perl 6 Introduction" and the "Learn Perl 6 in Y
minutes" (and a smattering of the advent calendar and the official
documentation). They are both well-written and super useful but they don't
cover some things that a new Perl6 programmer will run into immediately and
where the official documentation is almost completely opaque to an outsider:

* Sigils are initially explained in a way that makes them look like a
shorthand way to indicate whether or not you have an array or hash or a
scalar. But since you can store an array or hash in a $ variable, and
because you can put a sigil before the sigil, e.g. @$foo it's not
immediately obvious what to prefer and when. Examples using other container
types to illustrate that the built-in array and hash types are not special
would be useful to make this more clear. The temptation is for me to always
use $ and if it turns out I need to loop over something use @$x or %$x. I'm
not sure why you wouldn't just want that to be the way to do it in general
in the language. Also an explanation of how you implement your own
container to be @ or % compatible.

* I can find no concise easy-to-understand explanation for how to define
what other languages would call constructors. Instead there is a mess of
bless, magic inside Mu, new, BUILD, BUILDALL... It's not clear when you
should prefer to override BUILD or new or both. I also assume there are
some benefits to teasing apart object construction this way, but right now
I don't know what they are. This is also an area where I think there are
older blog posts confusing the situation because they discuss semantics
from an older version of Perl6.

* It would be nice for people coming from Python for a tutorial that
explained the basic module importing, the scope of things imported, and how
name collisions are avoided when importing from two modules that have the
same sub. The official documentation is trying to distinguish a bunch of
subtle and presumably useful for advanced users distinctions that are
completely lost on a newcomer. I just want to know what is the equivalent
of import, from foo import bar, and import foo as bar.

* Coming from almost any other language the => operator is dark magic
because of its implicit quoting of the left hand side. Likewise the
implicit quoting done by <foo>. Some explanation of why this is done, and
how you could write a sub or operator that does the same thing would
probably go a long way towards making it less confusing.

* I haven't been able to find any guidance on when I should be using a role
and when I should be using a class. The former seem to give you better
error messages when you forget to define a method from a base role... So
never use classes? I suspect it's more complicated than that.

Then there were some more issues that took longer to come up:

* Types feel like second-class citizens. Without knowing the details of the
implementation it feels like the errors that Perl can statically detect is
chosen at random. It's generally useful to have an intuition about what
kinds of errors are detectable at compile time versus runtime so that you
can prefer the former when designing an API to make it harder for users to
hang themselves. There are also instances where it's not clear whether or
not something is part of the type system -- I had an undefined method in a
role that subclasses/roles were meant to override and I had a derived role
that defined it but used different sigils, and a different explicit type on
one of the arguments, and Perl6 gave me no errors. Finally if I want to
implement my own container I haven't been able to find any documentation
explaining how to parameterize my type, e.g. I specifically want
MyContainer[int, float]. Also tying in to the point about object
construction :D did not appear to work on arguments to overrides of new().
Also sometimes when you get a type error at runtime no line number
information is given so where the error occurred is anyone's guess.

* :D is a great idea for function signatures, and is what you probably want
for 99% percent of all your function arguments but surprisingly is not the
default in the otherwise very terse Perl6. Why not?

* set/SetHash are confusing on multiple levels. Set can be parameterized by
a type but SetHash cannot for some reason. If you deliberately choose to
use SetHash and want to do any set operations on it you will get back a
set, not a SetHash. If you try to store two equivalent objects in a set,
you will get a set with two elements instead of one because apparently sets
are hardcoded to use object identity and no obvious API is provided to make
them use something else. I'm not up to writing a balanced binary tree
implementation for my project, so I stopped after this.

Many other aspects of using Perl 6 were a joy, that static types were an
option at all was a welcome improvement, as was the method override
detection by Roles. Omitting parentheses in method and function calls,
regular expressions ignored white space by default, much reduced
boilerplate defining simple classes with the implicitly generated named
argument constructors, are all pretty sweet as well. Macros look pretty
promising although again I had trouble finding good tutorials.

Reply via email to