Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Perl 6's given: switch on steroids (tenesianu.blogspot.com)
109 points by lizmat on June 2, 2019 | hide | past | favorite | 64 comments


They've reinvented OCaml / SML pattern matching. I wonder if they also compile it to efficient machine code? Xavier Leroy's famous ZINC paper goes into how you do that, and it's pretty complicated (page 64 of http://caml.inria.fr/pub/papers/xleroy-zinc.pdf)


Machine code? Lol. They don't even seperate out compile-time branches, like switching on types. If types are known at compile-time, the switch can be collapsed to the rest. Better languages do that and provide proper syntax to match on types or values or both.

Perl6 (and perl5 given/when) is famously over-designed and under-implemented, with both lsh and rhs needed to be evaluated at runtime, and many inconsistent edgecases, eg matching on arrays vs lists. destructuring (matching nested structures) is also confusing.


Not really.

Let’s first consider how this code would be translated to ocaml. One would expect to use variants instead of strings, so e.g. gender should be:

  type t = | Masculine | Feminine | Mixed
And then one can match on them and match on tuples and so on. But what about countries? In this case you could write out all the cases separately (difficult to maintain), or you could use polymorphic variants to achieve the @foo.any behaviour:

  type vosotros = [ `Spain | ... ]
  type dialect = [ vosotros | ... ]
And then do e.g.

  match dialect with
  | #vosotros -> ...
But this has the disadvantages that polymorphic variants usually bring (difficulties with type inference/exhaustiveness checks). So instead one would probably have some function to decide if a dialect Is vosotros, and then match on the result of that, a slightly annoying to read boolean.

And one would also need to match on the (perhaps) nonsense case of singular mixed-gender. One can get around this with types in one of two annoying ways. Either combine gender and number:

  type gender = Masculine | Feminine
  type genders = Masculine | Mixed | Feminine
  type number = | Singular of gender | Plural of genders
Which is not great because it is now hard to extract the gender if that is all one wants (but it is perhaps not grammatically useful); or one can use GADTs:

  type singular = [ `singular ]
  type plural = [ `plural ]
  type 'number gender =
    | Masculine : 'a gender
    | Feminine : 'a gender
    | Mixed : plural gender
  type 'number number =
    | Singular : singular number
    | Plural : plural number
  type t =
    T : { number : 'num number; gender : 'num gender } -> t
But this is also unpleasant.

And how does one do other smart-match predicates? For example * > 0. This could either be:

  match number, ... with
  | num, ... when num > 1 -> ...
Which separates the important part (num > 1) from the unimportant part (giving it the name when you don’t care), and you still need a catch all because of the exhaustiveness checks. So maybe instead you would have a helper function to change the number into a variant like One | Zero | Many.

This also ignores the case when one might want to write some more traditional style Perl and put regular expressions as the predicates of those when blocks. This isn’t really an ocaml/SML thing to do but that doesn’t mean it should be disregarded as something bad/useless.


Other than the ability to put a predicate in the pattern position (which you can do in several languages, including Haskell with ViewPatterns), I still don't see what Perl 6 adds here? Of course it's more difficult to model the problem using sum types, but there's an asymmetry here: whereas given can't do powerful pattern-matching features like exhaustiveness checking, GADTs, auto case-split in an IDE, efficient case trees, etc., the opposite isn't true. Haskell can do everything Perl does here, just by using strings! The other features (multiple variables to split on) are pretty standard these days.

    vosotros = ["Spain", "EquitorialGuinea", "WesternSahara"]
    
    message = case (number, gender, formality, country) of
      (1         , "masculine"                        , "informal", _                     ) -> "¿Cómo estás mi amigo?"    
      (1         , "masculine"                        , "formal"  , _                     ) -> "¿Cómo está el señor?"     
      (1         , "feminine"                         , "informal", _                     ) -> "¿Cómo estás mi amiga?"   
      (1         , "feminine"                         , "formal"  , _                     ) -> "¿Cómo está la señora?"    
      ((> 1) -> T, (`elem` ["mixed","masculine"]) -> T, "informal", (`elem` vosotros) -> T) -> "¿Cómo estáis mis amigos?" 
      ((> 1) -> T, "feminine"                         , "informal", (`elem` vosotros) -> T) -> "¿Cómo estáis mis amigas?" 
      ((> 1) -> T,  _                                 , _         , _                     ) -> "¿Cómo están ustedes?"


Are you arguing about data representation in Perl vs OCaml? Of course there will be differences in data representation, and that would make your pattern matching also look slightly different.

However, the examples in the article do fit very well familiar ML-style (SML, OCaml, Haskell, Rust, etc.) pattern matching.


If you want to pattern match on strings as in the Perl code the OCaml code is almost exactly the same. Now try to recreate the types you just constructed in OCaml and get static checking. That’s just not possible.

You’re comparing apples and screwdrivers.


> They've reinvented OCaml / SML pattern matching.

I don't think so. ML pattern matching is statically machine checkable for exhaustiveness. P6 matching is dynamic.

Aiui what they've done is generalized matching.

This includes features traditionally associated with pattern matching. But also any other match/destructure/bind operation.

A field of a match might build a parse tree or AST.

(Perl 5 did a simple small scale flat assignment approach to this; a statement could assign variables to selected elements of an array of captures extracted from a string by a regex. Perl 6 scales this up to turing complete parsing and AST generation involving huge numbers of nodes.)

One can match an arbitrary predicate. That's what the `* > 1` is. It's not a pattern.

Any value or variable can be matched against any value or variable. (Not just literals.)

Matching is "smart". For example:

  say DateTime.new('2020-01-01T01:01:01Z') ~~ Date.new('2020-01-01')
displays True.

And it can all be destructured (with a fairly sophisticated range of options) and bound as part of the match.


Sigh. ML is such a sweet spot in language design.

OCaml was so far ahead of Java and C# 20 years ago. It's a shame us regular industrial programmers ended up with Java (which I like fine) and PHP, later Python and JS.


This is nice.

In other languages, I would settle for a switch-statement like Go's, which by default breaks instead of falls through. The common switch-statement seems like a prank: If you omit the break, the compiler throws no error, like when you forget a closing brace. Instead the program silently does the opposite of what you meant.

I am less afraid of forgetting one, more of one day accidentally deleting one. Every once in a while in Vim I order my keystrokes wrong and a random line disappears. Usually it catches my eye, but it is unnerving. The risk is eternal.

You would want to leave the switch-statement as is, for backward compatibility, and come up with a new key word to set off the improved version, like Perl did with "given."

With all of the ongoing improvements to JavaScript, I'm surprised this has not been addressed. And in general with most languages I am surprised that their flow control is so stunted.


Falling through sort of makes sense in C, which is underdefined by design to allow pulling whatever dirty tricks needed to get where you're going.

Copying the idea to higher level languages makes little sense to me. Blindly copying any feature into a language design is a bad idea from my experience.


Honestly I'd rather use goto than have fallthrough by default in C. Or even better, a Fallthrough keyword as in GO.


Perl6 has a fallthrough keyword named `proceed`. It also has a keyword named `succeed` which is the default for `when` blocks.

    given 1 {
      when Int { say 'integer'; proceed }
      if 0 ≤ $_ ≤ 9 { say 'digit'; succeed }
      when 1 { say 'one'; proceed }
    }
The above will print two lines `integer` and `digit`. It will not get a chance to run the second `when` block because of the `succeed` that gets run before it.

If you want the `given` block to return a value, `succeed` can be given a value.

    my $result = do given $example {
      when 1 { 'one' }
      when 2 { succeed 'two' } # succeed is redundant here
      if $_ == 3 { succeed 'three' } # acts like a `when` block and returns "three"
      …
    }
---

Perl6 is “supposed” to have a `goto` keyword, but nobody has implemented it. Mainly because of a lack of need.

One of the few good uses of `goto` in a higher level language is to have a portion of a function always run at the function exit. Perl6 has `LEAVE`, `KEEP`, and `UNDO` which handles this nicely.

    sub foo (){
      my $fh = open 'example.txt', :r;
      LEAVE $fh.close; # close $fh at scope exit

      … # use the opened file handle
    }
Technically it would probably be better to have the `.close` be conditional on whether the $fh was successfully opened.

    sub foo (){
      my $fh = open 'example.txt', :r;
      LEAVE with $fh {.close}

      without $fh {.throw}; # throw the error in `$fh`
      # (This isn't necessary, as it will get thrown as soon as you use it.)

      … # use the opened file handle
    }


Wow, had no idea about fallthrough in Go and I've written plenty. Thanks.

That's a seriously ugly solution, but I guess that could be considered a good thing.


Nowadays GCC warns about implicit fall-through.

If you want to have a fall-through, you have to annotate it with, e.g /* fall-through */

This is of course not ideal, suddenly comments have to be considered by the compiler. But I guess it's the only way to fix this in a backwards compatible way.


C++17 includes the [[fallthrough]] attribute built into the language to disable the warning [1].

[1] https://en.cppreference.com/w/cpp/language/attributes/fallth...


Shouldn’t we optimize for the common case?

The language should do want we want most of the time.


We should not optimize for the common case at the expense of making the uncommon case impossible.

With C style switch, you can fall through or break. In languages that don't provide fall through (say Erlang's case expression), if you have something that fits fall through, you need to either duplicate the inner code, or have a more verbose construction with multiple phases of matching.


So, 99% of the time to need to be more verbose to handle the 1% case? I’d rather wrap the duplicate code in a function and call it in each instance.


You're thinking about C's switch statement the wrong way.

You are thinking about where a value is used to determine which block of code to run, like a ramped up conditional or an if-else-if chain.

C's switch is a more a complex goto statement. All the case statements are labels and the switch does a goto label for the correct value. Those labels just need to be inside the switch block. This is why you can switch into the the middle of a looping construct or if-statement. In this way, break is kind of the oddity and sugar for goto past end of the switch block. This allows for some complex control flow that is kind of useful in a language without much else to offer in that regard (besides the ugly setjump hackiness).


Of course if you'd use Lisp in the first place you could make a new syntax to input those things in the visually safest manner without waiting for a language revision.

Compile-time computing is precisely about this, e.g. https://medium.com/@MartinCracauer/a-gentle-introduction-to-...


Perl 6 includes the ability to modify the grammar and parser on the fly in a way which is much more convenient than reader macros in Common Lisp (and different to macros in CL). Saying “new syntax” is also slightly disingenuous because the only convenient new syntax available is made of parens.

That said, this isn’t really an article about syntax but how several language features fit together.

Making something slightly similar in CL could be something like:

  (defmacro with (it &body body)
    `(let ((it ,it)) (block nil ,@body)))
  (defmacro having (condition &body body)
    `(if (smart-match ,condition it)
         (return-from nil (progn ,@body))
         (values)))
  (defgeneric smart-match (matcher thing))
  ...
But this makes the behaviour of `having` a bit weird.

I feel like this article is much more about how certain perl6 features compose nicely together (in particular smart matching, $_, expressions returning values) in a way that the existing features of given and when compose to give a useful switch mechanism for free.


And of course, your code base will end up riddled with those untested, undocumented customizations. People getting into it will hate you for it, and you will look at them with a smug face, stating how they don't get the power of a true language.

There is a reason Lisp based languages are not more popular: most people don't want to learn a new language every time they work on a new project.


There is no specific difference between compile-time and run-time (regular) computing when it comes to testing and documenting it.

As for learning something new, perl6 is a new language, this construct isn't in perl5, so they are in for a learning. In Lisp no language modification was required to enable this functionality in the first place, and so you do not have to learn any new language or language construct.

Yes, you have to learn the library that you or somebody else writes to enable this "enter the data in the safest way possible". But that is learning a library, not a new language, or language evolution.

It goes back to object-oriented programming. How badly did they hack up C compilers to implement either C++ or Objective-C? In Lisp the OO system used to this day was implemented as a compile-time library. A library still used today, too.

You don't have to wait for anybody to hack up the compiler, and test it, and document it, when compile-time computing is part of the language in the first place.

ETA: Another thing you can do with compile-time computing, without waiting for somebody to hack up the compiler: https://medium.com/@MartinCracauer/static-type-checking-in-t...


Actually this feature is in Perl5, you just have to ask the compiler for a recent enough version.

Though it has been marked as experimental because the Perl6 design for this didn't fit into Perl5 as well as was hoped for. That is it had edge-cases that need to be worked through before it is recommended for general use.

    use v5.10;
    no warnings qw(experimental);

    given (1) {
      when (1) { say 'one' } # only prints this line
      when (1) { say 1 }
    }


This is FUD and rarely happens in the real world. (It happens with about the same frequency people abuse language features in other languages, like monkeypatching Python classes in an uncontrolled way, which is just as bad.)

Not once in my career have I heard someone either inspect or begin to learn Lisp and said “ya know what, all these new languages, not for me.” People usually don’t learn (Common) Lisp because it’s an old language, people don’t recognize benefits it has vis a vis other langs like Python/Go/Rust, it doesn’t look like anything they learned before, it more-or-less bolts you down to Emacs, it has no major corporate backer promoting the language, etc.


perl6 also has syntax macros (sort of, I think rakudo does not implement the full perl6 macro stuff).


Perl6 is “supposed” to have syntax macros.

Rakudo has a macro feature, but the current design was deemed not good enough to be part of the Perl6 specification testsuite yet.

There has been design work in this area in the 007 project. https://github.com/masak/007


Do you mind explaining how is it related to the article? I'm genuinely interested.


The article reasons that you should use the syntax that makes it safest to enter and later change that table you need.


> you could make a new syntax

Thanks, but I'd rather not.


Why not? Do you prefer to manage multiple languages in your stack, or cobble together half-baked “DSL”s with method dot-notation, decorators, etc.?

New syntax doesn’t have to mean new lexemes or characters. New syntax can be making something that wasn’t semantically meaningful before now meaningful.

In Lisp notation, if I just have a bare (F 5), I’ll get an error: F is undefined. If I define F, in some sense, I’m adding new syntax. I can now write something down that is meaningful.

Now, it’s not strictly true that it’s new syntax. But if you agree to that, then maybe you’ll agree that

    (match X (P1 R1) (P2 R2) ...)
isn’t new syntax either. (Lisp programmers, however, call it “new syntax”.) That chunk of code could represent pattern matching X against the patterns Pi, and a successful match will return Ri.

Visually, lexically, and structurally, this isn’t actually “new” in a lot of ways. Still has parentheses. Looks like CASE. Doesn’t introduce any foreign evaluation semantics.

So why wouldn’t you want to be able to write things like this? What makes functions/classes/methods/variables—which we define day in and day out—more privileged than syntax like this?


The `when` block seems to exhibit a different behavior when used as a block vs as a statement modifier. The latter lets things falls through until it matches the most general case. For instance, given

    class Audience {
        has $.number;
        has $.gender;
        has $.formality;
        has $.country;
    }
    
    my @vosotros = <Spain EquitorialGuinea WesternSahara>;
    
    my $audience = Audience.new:
     :number(100), :gender('feminine'),
     :formality('informal'), :country('Spain')
    ;
Contrast:

    my $message = do given (.number, .gender, .formality, .country given $audience) {
      when     1, 'masculine', 'informal', *              { '¿Cómo estás mi amigo?'    }
      when     1, 'masculine',   'formal', *              { '¿Cómo está el señor?'     }
      when     1, 'feminine',  'informal', *              { '¿Cómo estás mi amiga?'    }
      when     1, 'feminine',    'formal', *              { '¿Cómo está la señora?'    }
      when * > 1, 'feminine',  'informal', @vosotros.any  { '¿Cómo estáis mis amigas?' }
      when * > 1,  *,          'informal', @vosotros.any  { '¿Cómo estáis mis amigos?' }
      when * > 1,  *,                  * , *              { '¿Cómo están ustedes?'     }
    }

    say $message; #=> «¿Cómo estáis mis amigas?␤»
with this:

    my $message = do given (.number, .gender, .formality, .country given $audience) {
      '¿Cómo estás mi amigo?'     when     1, 'masculine', 'informal', *;
      '¿Cómo está el señor?'      when     1, 'masculine',   'formal', *;
      '¿Cómo estás mi amiga?'     when     1, 'feminine',  'informal', *;
      '¿Cómo está la señora?'     when     1, 'feminine',    'formal', *;
      '¿Cómo estáis mis amigas?'  when * > 1, 'feminine',  'informal', @vosotros.any;
      '¿Cómo estáis mis amigos?'  when * > 1,  *,          'informal', @vosotros.any;
      '¿Cómo están ustedes?'      when * > 1,  *,                  * , *;
    }
    
    say $message; #=> «¿Cómo están ustedes?␤»


Yes, that's deliberate.

If you use an ordinary `when` (with its statement(s) on the right) then P6 assumes it should succeed with the value of the last statement of the matched `when`. To succeed means to leave the block and return that last value if the block's value is being kept (eg via a `do`). If you wish instead to proceed to the next statement rather than succeed, you must write `proceed`.

Conversely, if you use a modifier `when` (with its statement(s) on the left) then P6 assumes it should proceed as explained above after matching. If you wish instead to succeed as explained above you must write `succeed` (with a value unless you wish to succeed with a value of `Nil`).

This is great bit of language design work. Thank you Larry.


Fortunately, the second example does throw warnings for each line of the block but the last:

    Useless use of constant string "¿Cómo estás mi amigo?" in sink context


Whoa


Every time I see something about Perl 6 I think this is awesome. Shame that a younger generation of programmers will never use it, because it’s not the new cool.

If they renamed Perl 6 into something cool like “Liquid” or some think you find in the kitchen, like Chilli. Then hide away it’s origins a bit, they’d have a language kids would be raving about.

I know that’s not the point but I can’t think of any programmer I know today that doesn’t talk about Perl with a certain contempt. “It’s Perrrrl” eyes up


There's a concept in programming language design called "weirdness budget". There's only a finite amount of idiosyncratic syntax and semantics your language is allowed to have before it starts to turn off potential adapters because it looks too unfamiliar, too unintuitive, or too opinionated compared to what they already know.

Perl has never cared what the mainstream programmer community thinks. It is willfully and deliberately weird; when it adopts or reinvents concepts from other languages it does it in a way that seems purposively quirky; it invents bespoke vocabulary for things that already have well-established names. The Perl community appears cultish, lacking a certain self-awareness and cognizance of the programming world at large. It's like an alternate timeline where everything seems eerily off in some way.

Perl blew its weirdness budget a long time ago and never cared. And given its well-deserved reputation as a write-only language, it's no wonder at all that people don't take it entirely seriously.


I don't think this is correct. If you come from Unix programming, perl should not at all be unfamiliar. It was an intentional amalgamation of shell, sed, awk, etc. And there was a time when that was the "mainstream" programmer community.


I think the key word is "was". Yes, in the beginning it was a pretty straightforward amalgamation of a bunch of standard Unix tools. (Although it should be noted that those were even then in a separate category from languages meant for application programming!) But that's where the Perl timeline started to diverge from the mainstream, in which production-ready programming languages have mostly grown to agree on basic concepts and terminology, and to emphasize design principles like clarity over cleverness and readability over writability.


Not sure if I agree. Ruby is a language founded on quirkyness and bespoke vocabulary. They've certainly blown their "weirdness budget" too, but it has a large following.


Ruby is an interesting data point. I only know the basics, but I've never thought of it being particularly weird, except maybe for its emphasis on runtime reflection and "monkey-patching", and yes, the vocabulary, which I believe partially stems from its creator being Japanese. It's still a fairly niche language, and I believe Ruby on Rails has had a lot to do with whatever popularity it has garnered in the West.


If you want to make Perl 6 'cool' just create an alternate syntax that maps to Perl 6.

cough Elixir cough


To be fair, elixir mostly inherited pattern matching case from erlang


If you think merely rebranding something will make it more acceptable, then perhaps you've found the real reason people don't like Perl: it is a language that appears to be built around the superficial. Like someone who takes 30 mins crafting their bed hair in an effort to prove they don't care about appearances.


> then perhaps you've found the real reason people don't like Perl: it is a language that appears to be built around the superficial

How so? That's an odd statement without citation or clarification. If anything the opposite is true. It's become a trend in the industry to let superficial attitudes shape popular opinion. You're not "cool" if you use languages like Perl and PHP. You're supposed to criticize Perl even if you never used it or even understand it. The idea that Perl 6 should be called something else isn't because of the superficiality of Perl but of popular misconceptions and misguided opinions erroneously excepted as truisms in the tech community. Perl 6 is not a the next "version" of Perl 5. It's a completely different language but because it's still called "Perl" people tend to dismiss it out of hand. That and it's confusing to call it "Perl 6" when it isn't related to Perl 5 and doesn't even share a codebase with Perl 5.


>It's become a trend in the industry to let superficial attitudes shape popular opinion.

Well, yeah. Popular opinion is always a trend, and it always follows superficial attitudes. That's basically a tautology. The question is why do you care? Why complain about being unpopular if you don't want to follow trends? If Perl were popular, it would be just as trendy to praise it. And just as counter-trendy to denounce it as over-sold.

People have perfectly rational reasons to use languages that are popular. If Perl is not popular, it has to offer something else. Is it as fast as C? As portable as JavaScript? As flexible as C++? As well-funded as Java? As easy to use as Python?

These 'popular' languages are also heavily criticized. JavaScript could be the worst language in the world, and it would survive all that criticism because browser compatibility is important. What does Perl offer? Look at the landing page at https://www.perl.org/ "It's old and does stuff! That's why we love it!" Who cares about that? The language basically bills itself with no more than "This is a programming language, but with different syntax!"


It only appears superficial because you have only looked at the surface of it.

Perl6 brings together features from many languages, but makes them feel as if they have always belonged together.

Imagine writing Haskell and C code in the same line. If Perl6 had just copied the syntax of the originators of those features verbatim, it would feel very disjointed. It instead feels very natural and fluid.

    gather loop ( my Int $i = 0 ; ; $i += 2 ) { take $i }
The above line is a generator for an infinite sequence of even numbers, but uses the C-style `for` loop to do it.

---

When major features get brought into Perl6 they are rarely copied exactly. That applies both to the syntax and the functionality of the feature. If the feature doesn't compose with other language features, or doesn't mesh syntactically, it will be redesigned until it does. (We don't want non-Perl6-ish features.)

When I was new to Perl6 I would often try to combine features together to try and break the syntax/compiler/runtime. Eventually I got tired of that because it almost always worked the first time exactly how I would expect it to. (A wizard will eventually see magical things as being mundane because he sees them day-in and day-out.)


I can say as a part of the younger generation of programmers that I don't have any problem with Perl and that it has its uses but I don't think Perl should necessarily be used as much as it was in the past.


This looks a lot like Rust's match blocks (which were inspired by pattern matching in ML languages). It's nice to see pattern matching constructs come to more languages.


But, this has really not a lot to do with pattern matching. Please see my comment at https://www.reddit.com/r/perl6/comments/bvhzwh/perl_6s_given...


Surely it has everything to do with pattern matching? A C-style switch statement is an extremely primitive version of pattern matching, and in the article the flattened equivalent of the nested switch structure is just tuple destructuring and matching, just like in Rust I could write

  match (foo, bar, baz) {
    (1, 2, 3) => something(),
    (3, 2, 1) => somethingelse()
  }


From that explanation, it sounds very similar to pattern matching in general, and Erlang's case statement in particular. Would you care to elaborate?


the condition tree flattening reminds me of pattern matching compilation though


Rust's match blocks appear to be less powerful than the smart-match feature in Perl6.

Rust doesn't appear to allow arbitrary code in the condition.

---

    given 1 {
      when (0 ≤ * ≤ 9) { 'digit' }
    }
Expanding out the definition of the `when` above:

    given 1 {
      {
        my $initial-result = (0 ≤ * ≤ 9); # get the result of the expression
        my $result = $initial-result.ACCEPTS($_); # ask it if it accepts the topic
        if $result {
          succeed 'digit'
        }
      }
    }
The condition part a `when` is just like the right side of the `smart-match` feature, and the `where` clause.

It does double code execution.

First as just a statement. (In this case the result is a lambda that will compare against `0` and `9`.)

Then it asks the result of the statement if it `ACCEPTS` the current topic value. (In this case it runs the lambda with topic as its argument.)

If the second level result is truish then `when` runs its block and calls `succeed` with its last value.

`succeed` throws a `CX::Succeed` control exception which the `given` catches.

---

This double code execution allows for a lot of flexibility. Also since smart-match asks the initial result if it `ACCEPTS` the topic, it gets to decide how it matches.

    class Match-Always {
      method ACCEPTS ( $ --> True ){}
    }
    class Match-Never {
      method ACCEPTS ( $ --> False ){}
    }

    # match 50% of the time arbitrarily
    class Match-Half {
      method ACCEPTS ( $ --> Bool ){ Bool.pick }
    }

    given 1 {
      when Match-Half { … }

      when ( $_ == 1 ?? Match-Always !! Match-Never ) { … }
    }
(Note that `True` works like `Match-Always` and `False` like `Match-Never`, so there is not a good reason to add those two types like I did.)


I find it odd that no language seems to have a syntax short-cut (like operators) for something as common as switches; the closest thing might be a shell script!

This is a very common thing to write. Why couldn’t a switch avoid all keywords and look more like a list...such as:

    ?(value):
    - 0: { doThing(); }
    - 1: { otherThing(); }
    - *: { doDefault(); }


Haskell's syntax is pretty minimal:

  f 0 = doThing
  f 1 = otherThing
  f _ = doDefault


given/when is also available in Perl 5 from 5.10.1 onward[1]. There are times when it is very helpful.

[1] https://perldoc.perl.org/perlsyn.html#Switch-Statements


Don't use it in Perl 5. You have to first read the whole documentation on what when does[1] and then the whole documentation on what smartmatch does[2] and then you probably still won't know what will happen if you compare two values that might or might not be numbers, because Perl does not make this distinction for you, so smartmatch guesses. There is a reason every other operator has explicit stringy and numeric comparison versions, and optional new stringy bitwise operators were added because they had the same ambiguity[3].

[1] https://perldoc.pl/perlsyn#Experimental-Details-on-given-and...

[2] https://perldoc.pl/perlop#Smartmatch-Operator

[3] https://perldoc.pl/feature#The-'bitwise'-feature


A more explicit switch statement for only strings or numbers is available from CPAN: https://metacpan.org/pod/Switch::Plain


I feel like you can approach most of this with Ruby’s `case`. Not sure about the `when @ary.any` but it wouldn’t be hard to monkeypatch a fix (not that it would be a good idea).


I'm usually looking for two kinds of switching, most implementations support one of them. Switching on a list of conditions in priority order like CL's COND, and switching on a value.

Simply making the value optional and injecting it in specified conditions if present would allow using the same construct for both.

Note that this may well be possible in P6, most things are; but I have yet to come across and example of COND-behavior, they're all switching on values from what I can see.


Behold:

    switch (true) {
        case a > b: ...
        case isFullMoon(): ...
    }


Thanks, I have yet to come across anything that P6 doesn't have a feature for. The languages [0] I've designed so far don't even come close in complexity, and I'm still balancing the edge of my abilities to keep track of everything. If they manage to make that monster run reasonably correct and fast, I'm seriously impressed.

[0] https://github.com/codr7/g-fu/tree/master/v1


Well, that's not specifically Perl above―it should work in most languages with `switch`. It's also highly questionable to my taste, as I don't see why `if` wouldn't do. I've chastised a dude many a time for its use, but that was only one of his dubious choices in life, so...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: