Hacker News new | ask | show | jobs
by rs86 2745 days ago
Perl 6 feels a bit "ad hoc" to me... It looks like it has very interesting features but it lacks the uniformity present in most languages...
2 comments

Instead of "ad hoc", think of it as a multi-paradigm language.

From that viewpoint, I think there is a fair bit of beauty in being able to pick and choose your approach based on the problem at hand without worrying if that is an idiomatic choice dictated by language designers. P6 goes to great lengths to give you all the expressiveness you could hope for, regardless if you are doing functional, OOP, or dealing with concurrency etc...

Perl has never been about uniformity.

Perl is a great experiment in language design, or, rather, a battery of experiments. It's the opposite of a cleanly designed language.

No, it's designed. It's just not designed the way everyone expects a computer language to be designed. It was designed by a linguist. He produced a language with some of the flexibility (and messiness) of human languages, which is completely foreign as a goal to other languages.

One of the places this shows up to me is being able to say "it" (in essence). That is, we humans, when talking to each other, we say things like "Read in a line of input. If it looks like an XML tag, pass it to the XML handler function". But you can't talk to a computer that way. The computer says, in effect, "Read in a line of input from where? And put it where? And what do you mean 'if it ends in a newline'? If what ends in a newline?"

But in Perl, you can write it just like the humans say it, and Perl says, "Well, you didn't say where to read the input from, so I assume I should read it from the standard place (which is perfectly well defined in Perl). You didn't say where to put the line of input, so I'll put it in the default variable. You didn't say what to check to see if it looks like an XML tag, so I will check the default variable." The default variable, essentially, plays the role of "it" in human language.

And the whole language is like that. There are shortcuts that work most of the time, and precise ways of saying things that work when the shortcut isn't what you want. And what the shortcut does is well defined (in the docs; it can be very opaque in code).

None of this makes Perl an ideal language. But it has a perspective on language that is (as far as I can tell) unique among programming languages. It is only fair to judge the coherence of the design within the framework of what Perl is trying to be.

Except the resulting code will look nothing like “the humans say it”, and instead will be a cryptic charade requiring a ton of knowledge to decipher - ending up being neither natural language nor machine code.
The linguistic target Larry Wall aims at has little to do with uttering the line of code out loud..

The attempt to mirror human language is in the flexibility of the constructs. This is the much maligned There Is More Than One Way To Do It (TMTOWTDI) principle.

The language is designed to allow the programmer to express themselves in they way that makes the point best for their brains.

Now, this is almost a classical debate in programming at this point but it was really in high gear during the late 90s as Python's One Way approach quickly proved more useful for larger codebases, in contrast to the personalized anarchy of styles often found in a large Perl project.

Perl 6 changes the landscape of "personalizable programming language" considerably, making it less complex in some ways and more complex in others.

Whether or not TMTOWTDI is a boon or a bane to you is your choice. I find that having a language that is designed for personal expression is precisely the thing I want when I am reaching for scripting glue.

Hmm, interesting. TMTOWTDI is great for a small (one person) script, and One Way is better for a large (multi person) code base? That seems very plausible.
I think it is rather more related to team size than codebase size, really.

Think of how much can be done with a small group of people who all speak the same dialect / lingo. If everyone is on the same page WRT code style, then TMTOWTDI is just the magic that allowed you all to arrive on the same stylistic page.

Perl 6 is much better than Perl 5 in this because some of the styles that ossified in the Perl 5 dinosaur brains are truly grotesque to behold when deployed in the 21st century.

The downside of TIMTOWTDI is that the next person that comes along might not be as familiar with the alternate way you chose to implement something, which impedes understanding. That's never really an issue for a single person program, since they had to understand that feature it to initially write it, meaning they should understand it when they encounter it later (the vast majority of time at least. Forgetting skills from long ago happens).
> Except the resulting code will look nothing like “the humans say it”,

Actually, I find it maps rather directly to how a lot of people explain things. For example, "Examine each number, and as long as it's greater than 10 and odd, then pass it to the the work function."

    for my $number ( @numbers ) {
        next unless $number > 10;
        next unless $number % 2;
        work($number);
    }
Perl generally allows you to structure your code as you would explain how to accomplish something to another person. This can be beneficial or detrimental depending on how deep you go with this concept. A lot of becoming a good Perl programmer is learning where a sane line is for this, but each language usually has a similar feature which the user needs to decide where the sane point to stop is before taking it to an extreme that is detrimental.

There are definitely aspects of Perl that I think are better left untouched, and thankfully the community has pretty much come to consensus about the most problematic missteps the language allows.

One can write pretty much the same code in python/c++11/whatnot and it also feels quite natural to read:

   for number in numbers:
       if number <= 10: continue
       work(number)
Do you have a better example where the Perl syntax would shine?
You have clearly been able to read and translate the GP's code and confidently assert you've written "pretty much the same code".

> Do you have a better example where the Perl syntax would shine?

Unless you have "a ton of knowledge about Perl" your reply shows that it was a perfect example in response to the GGP.

Note: This is all in the context of Perl 5. You can assume the following works with little or no changes in Perl 6, along with probably 3+ other new ways to do it (which is actually one of my peeves about Perl 6).

There's a few things. Full word but lower precedence boolean operators (and, or, not) which allows for combining statements in a way that &&, || and ! doesn't always facilitate, but really shine in making boolean statements more readable. e.g.

    die "some problem" unless defined $some_var and not $some_var eq "foo";
But I think you somewhat missed my point. What you've done in your example, is easy to read, but you've either unconsciously or consciously switched the order of some statements so they are valid in the context of Python. This is trivial and easy with simple conditionals, but if they are complex it can hide the point of the statement, which is that this is a shortcut to the next loop iteration. I find putting the "verb" first can make for much easier understanding of what's going on when it gets more complex. A comparison of that might be something like the following:

    for my $item ( @items ) {
        # Standard barrage of tests
        next if test1($item) or test2($item) or test3($item)
            or test4($item) or test5($item);
        # If it's a special item, do a couple more tests
        next if test_guard($item) and ( subtest1($item) or subtest2($item) );
        # If it's an end marker, skip the rest
        last if is_last_processable($item);

        ...
    }
Even though the actions are condensed, I quickly know what the point of each one is, and what it does. Condensing them also allows me to comment each without feeling I'm cluttering the logic and making it more verbose than needed (too verbose, and you raise the likelihood related code will be off-screen or not as easily visually associated, which hampers comprehension), but event without the comments having the defining action start the line helps clarify intent. I imagine in Python, the continue statement would either be far to the right from larger conditionals, or moved to a more traditional scope underneath taking up an extra line, or split into multiple if statements. This is also a good example in Perl of where the community has come to a fairly good consensus that while you can make very complex postconditional statements, don't, as it defeats the purpose (just split it into multiple simple ones or use a traditional precontitional if formatted to be more readable, or some other technique such as computing portions of the condition separately and comparing them later).

Also, regarding if pre or post positioning, I feel that Perl allows the statements to be expressed as you might say them or think of them. That's the point of postconditionals in Perl. Also, like how you would express them verbally to someone, a postconditional only works on a single statement (it does not support blocks through braces). You wouldn't normally say "do X, do Y, do Z if A is true" and expect it to apply unambiguously to tasks X, Y and Z. On the flip side, a preconditional not only supports braces, it reqiures them, since the simple one statement case is easily handled through the postconditional. e.g.

    # Valid
    if ( $A ) {
        do_something();
    }
    if ( $A ) { do_something(); }
    do_something() if $A;
    
    # Invalid
    if ( $A ) do_something();
    { do_something(); } if $A;
This is an example of one of the places Perl not only allows you to use natural expressions to express yourself, but guides you away from odd or problematic ways of doing so (i.e. ambiguous speech patterns).

As for sigils, some people really dislike them, but I find the useful. I see them a little signifiers of the nouns in any statement (and the type of noun, of which there are only a few).

Finally, there's "context", which has a specific meaning in Perl, and is probably the most interesting and unique thing about the language. It can be very useful, but the complexities can sometimes cause interesting behavior that was unintended or non-obvious initially. That said, its also what makes a lot of the "magic" (really just the rules put into action) of the array and hash data types work, so it's not something that could feasibly be removed (and nor would I want it to be). Instead, knowledge of the problematic spots is acknowledged by the community, so we try to avoid those problems, and for the most part they are old problems (this is usually a function that may produce multiple values being using within the definition of a hash or array in list context, exemplified by decades old projects based on CGI.pm which has been deprecated).

In Perl 6 this could almost look the same:

    for @numbers -> $number {
        next unless $number > 10;
        next unless $number % 2;
        work($number);
    }
Although personally, I wouldn't write it like that: I would probably write it as:

    for @numbers.grep( { $_ > 10 && $_ % 2 } ) -> $number {
        work($number)
    }
or use the postfix notation:

    work($_) for @numbers.grep( { $_ > 10 && $_ % 2 } );
If you want to spread this out over multiple CPUs and you don't care about the order in which the work is done, you only need to add the `.race` method:

    for @numbers.grep( { $_ > 10 && $_ % 2 } ).race -> $number {
        work($number)
    }
More info: https://docs.perl6.org/routine/race
That ought to be a oneliner in any sane language today:

    numbers.into_iter().filter(|n| n>10 && n%2!=0).for_each(work);

    map work . filter ((/=0) . (`mod` 2)) . filter (>10) $ numbers
Insert tirade about how for-loops are free to do so much that they are slower-to-comprehend than specific-purpose iterator/list functions, here.
The language is happy to accommodate any style you like best, including oneliners.

    sub work($n) { say $n }
    my @numbers = 1..100;

    # rubyish
    @numbers.grep(* > 10 && * %% 2).map(&work);

    # lol turbo haskal
    map &work <== grep * %% 2 <== grep * > 10 <== @numbers;

    # same, but in proper reading direction
    @numbers ==> grep * > 10 ==> grep * %% 2 ==> map &work;
The traditional function composition operator exists, see https://docs.perl6.org/routine/%E2%88%98
Here is a slight modification that takes advantage of the hyper operator >> (»):

  @numbers.grep(* > 10 && * % 2)>>.&work;
https://docs.perl6.org/language/operators#index-entry-hyper_...
This would be one way to write in Perl 6:

    for @numbers -> $number {
        next unless $number > 10;
        next if $number %% 2;
        work($number);
    }
A lot of that "cryptic charade" comes straight out of the UNIX environment. To those familiar with this, it was/is hardly "cryptic".
Just like the Old Testament is “hardly cryptic” for someone studying it since the 70s. Doesn’t tell you anything about it’s validity or relevance today.
Why would Perl repeat the same mistake as others, of trying to treat a programming language too much like a natural language? It's optimized to be read as a programming language, not anything else.

Also, "cryptic charade" could be a good name for what all non-Perl 6 languages call "regular expressions". It would make an even better name for a prog rock band.

Perl (5 or 6) doesn't try to treat a programming language as a natural language. Instead it tries to allow the structure in which the author's brain defines the problem to be able to match the structure in which the code of the program defines the solution. It is linguistic in the sense that it tries to follow the normal flow of human language as a form of communication, allowing skills learned for human communication to be re-used for communicating via source code--not in a natural, human language (still in a computer language) but without necessarily having to pivot the problem in to something more natural for computers first.

Source code is instructions for two audiences: A human, and a computer. The computer doesn't care what the syntax is, but the human does. It is an ongoing challenge to write code in a manner which effectively and concisely communicates to other humans, including your future self. This is a thing at which Perl5 and Perl6 both excel, Perl6 more so IMO (although there is not yet enough history to prove it).

It is true that one can easily write unmaintainable spaghetti in Perl5. One can write unmaintainable spaghetti in any language, but Perl5 makes it somewhat easier to do it by mistake--this is an aspect of the same versatility which gives it its expressive power, which in turn is what makes it possible to communicate things using Perl more effectively (in the same space) than with many other computer languages. You have to employ some discipline not to sound like a gibbering lunatic. This is not much different from human languages: if you have ever read English 101 papers you will find some of them sadly similar to Perl5 scripts written by similarly undisciplined authors.

In contrast to Perl5, Perl6 makes it far easier to avoid accidental spaghetti and does so without sacrificing any of the linguistic expressiveness that makes Perl generally so useful.

> It is true that one can easily write unmaintainable spaghetti in Perl5.

This was something that surprised me when I first learned about Perl 5 in college. Most people in the internet would parrot it as a "write-only" language and yet I've always being capable of getting the whole picture of a code snippet posted on Perl Monks, Reddit, Stack Overflow, etc. Granted I've always steered away from golf code which obviously has its place but shouldn't be mistaken as being the "de facto way" of writing Perl 5 or Perl 6 for that matter.

>In contrast to Perl5, Perl6 makes it far easier to avoid accidental spaghetti and does so without sacrificing any of the linguistic expressiveness that makes Perl generally so useful.

Can you give some examples of that point, w.r.t. Perl6?

I'm not sure your definition of 'it' (that is, a default) matches how 'it' is actually used. 'It' is a locally scoped name binding to a previously mentioned symbol. In English, the referent of 'it' is sometimes ambiguous, requiring contextual intelligence that computers lack, so programming languages with 'it' need to be more precise.

Here's 'it' in lisp: https://en.wikipedia.org/wiki/Anaphoric_macro

The official name for "it" in Perl 6 is "the topic variable":

https://docs.perl6.org/language/variables#index-entry-topic_...

This makes so much sense, in its own way. Is there anywhere I can read more about this perspective?
Try the "state of the onion" series of speeches.
I do agree that Perl (6) is not a cleanly designed language.
Would you care to elaborate on the non-clean parts in your opinion?
Things like this seem like odd design choices:

  my @menu = <hamburger fries milkshake>;
  say @menu.contains('hamburger');            # True 
  say @menu.contains('hot dog');              # False 
  say @menu.contains('milk');                 # True! 
  say @menu.contains('er fr');                # True! 
  say @menu.contains(<es mi>);                # True!
From https://docs.perl6.org/routine/contains, `contains` coerces its invocant to a string and searches for a substring starting from a certain position (index 0 by default):

    # Let's drop `<>` (quote-words constructor) and 
    # use a more familiar array of strings:
      
    my @menu = 'hamburger', 'fries', 'milkshake';
      
    # Let's look at the definition of the `Str` method in 
    # the `List` class from which the `Array` class inherits:
    
    #`{
      method Str(List:D: --> Str:D)
      Stringifies the elements of the list and joins
      them with spaces (same as .join(' ')).
    }

    # Thus, after being stringfied, @menu is treated as 
    # the string 'hamburger fries milkshake'
    
    # With this is in hand, we can gauge the possible
    # result of the following statements:
    
    say @menu.contains('hamburger');            # True 
    say @menu.contains('hot dog');              # False 
    say @menu.contains('milk');                 # True
    say @menu.contains('er fr');                # True 
    say @menu.contains(<es mi>);                # True


If you'd like instead to search the array for words as elements, we could use Perl 6's set functions. However, I don't know if they're as performant as regular string searches:

    say 'hamburger' (<=) @menu;  # True 
    say 'fries' (<=) @menu;      # True 
    say 'hot dog' ∈ @menu;       # False 
    say 'milk' ∈ @menu;          # False 
    say 'er fr' ∈ @menu;         # False 
`∈` is the unicode equivalent of `(<=)`.

---

I'm not sure if I'm missing something in the "odd design choices" in this specific case so it'd be great if you could elaborate a little bit further here.

The ASCII equivalent of `∈` is `(elem)`.
English contains ambiguous words. What does "contains" mean in the previous sentence? In P6 it means searching a string for a substring. Your code asks P6 to treat @menu as a string. If you want to treat it as a list and grep that list then use grep:

    my @menu = <hamburger fries milkshake>;
    say so @menu.grep('hamburger');            # True 
    say so @menu.grep('hot dog');              # False 
    say so @menu.grep('milk');                 # False 
    say so @menu.grep('er fr');                # False 
    say so @menu.grep(<es mi>);                # False
You are sort-of right.

It should have used a different word.

A similar example would be the word `length`.

There is no `length` in Perl 6 because it is ambiguous. Instead there is `.elems` and `.chars`.

It is perhaps even a worse because there are other languages which use `contains` to see if the container has a given element.