HN user

b2gills

191 karma
Posts0
Comments210
View on HN
No posts found.

I didn't downvote, but this is by far not the first time something like that was stated (Raku being similar to Roku).

I know I'm tired of seeing it, I'm sure others are as well.

I'm sure that there has been more changes from Perl 5.8 to Perl 5.40 than there is between Python 2.0 to Python 3.x (Whatever version it is up to at the moment.)

What's more is that every change from Python 2 to Python 3 that I've heard of, resembles a change that Perl5 has had to do over the years. Only Perl did it without breaking everything. (And thus didn't need a major version bump.)

I've often thought of Raku as being a lot like the English language. It borrows heavily from other languages.

Of course since Raku has the benefit of an actual designer, it is more cohesive than English.

I've heard that the best way to solve a hard problem is to create a language in which solving that problem would be easy.

Basically creating a Domain Specific Language.

Raku isn't necessarily that language. What it is, is a language which you can modify into being a DSL for solving your hard problem.

Raku is designed so that easy things are easy and hard things are possible. Of course it goes even farther, as some "hard" things are actually easy. (Hard from the perspective of trying to do it in some other language.)

Lets say you want a sequence of Primes. At first you think sieve of Eratosthenes.

Since I am fluent in Raku, I just write this instead:

  ( 2..∞ ).grep( *.is-prime )
This has the benefit that it doesn't generate any values until you ask for them. Also If you don't do anything to cache the values, they will be garbage collected as you go.

This has nothing to do with the halting problem. And I have no idea why you think there would be 'terrible consequences'.

  2, 4, 8 ... *
The `...` operator only deduces arithmetic, or geometric changes for up-to the previous 3 values.

Basically the above becomes

  2, 4, 8, * × 2 ... *
Since each value is just double the previous one, it can figure that out.

If ... can't deduce the sequence, it will error out.

  2, 4, 9 ... *

  Unable to deduce arithmetic or geometric sequence from: 2, 4, 9
  Did you really mean '..'?
  in block at ./example.raku line 1
So I really don't understand how you would be horrified.

That's nothing, use it to calculate the sum of range of values

  say [+] 1..10000000000000000000000000000000000000000000
Which will result in you getting this back in a fraction of a second

50000000000000000000000000000000000000000005000000000000000000000000000000000000000000

(It actually cheats because that particular operator gets substituted for `sum` which knows how to calculate the sum of a Range object.)

I once heard of a merger between a company that used Java, and another one that used Perl.

After that merger, both teams were required to make a similar change.

If I remember right, the Perl team was done before the Java team finished the design phase. Or something like that.

The best aspect of Java is that it is difficult to write extremely terrible code. The worst aspect is that it is difficult to write extremely awesome code. (If not impossible.)

Many of the features that make Perl harder to write cleanly have been improved in Raku.

Frankly I would absolutely love to maintain a Raku codebase.

I would also like to update a Perl codebase into being more maintainable. I'm not sure how much I would like to actually maintain a Perl codebase because I have been spoiled by Raku. So I also wouldn't like to maintain one in Java, Python, C/C++, D, Rust, Go, etc.

Imagine learning how to use both of your arms as if they were your dominant arm, and doing so simultaneously. Then imagine going back to only using one arm for most tasks. That's about how I feel about using languages other than Raku.

Java inspired the Design Patterns book.

Every Design Pattern is a workaround for a missing feature. What that missing feature is, isn't always obvious.

For example the Singleton Design Pattern is a workaround for missing globals or dynamic variables. (A dynamic variable is sort of like a global where you get to have your own dynamic version of it.)

If Raku has a missing feature, you can add it by creating a module that modifies the compiler to support that feature. In many cases you don't even need to go that far.

Of course there are far fewer missing features in Raku than Java.

If you ever needed a Singleton in Raku (which you won't) you can do something like this:

  role Singleton {
    method new (|) {
      once callsame
    }
  }

  class Foo does Singleton {
    has $.n is required
  }

  say Foo.new( n => 1 ).n;
  say Foo.new( n => 2 ).n;
That prints `1` twice.

The way it works is that the `new` method in Singleton always gets called because it is very generic as it has a signature of `:(|)`. It then calls the `new` method in the base class above `Foo` (`callsame` "calls" the next candidate using the "same" arguments). The result then gets cached by the `once` statement.

There are actually a few limitations to doing it this way. For one, you can't create a `new` method in the actual class, or any subclasses. (Not that you need to anyway.) It also may not interact properly with other roles. There are a variety of other esoteric limitations. Of course none of that really matters because you would never actually need, or want to use it anyway.

Note that `once` basically stores its value in the next outer frame. If that outer frame gets re-entered it will run again. (It won't in this example as the block associated with Foo only gets entered into once.) Some people expect `once` to run only once ever. If it did that you wouldn't be able to reuse `Singleton` in any other class.

What I find funny is that while Java needs this Design Pattern, it is easier to make in Raku, and Raku doesn't need it anyway.

"Actual parsers" aren't powerful enough to be used to parse Raku.

Raku regular expressions combined with grammars are far more powerful, and if written well, easier to understand than any "actual parser". In order to parse Raku with an "actual parser" it would have to allow you to add and remove things from it as it is parsing. Raku's "parser" does this by subclassing the current grammar adding or removing them in the subclass, and then reverting back to the previous grammar at the end of the current lexical scope.

In Raku, a regular expression is another syntax for writing code. It just has a slightly different default syntax and behavior. It can have both parameters and variables. If the regular expression syntax isn't a good fit for what you are trying to do, you can embed regular Raku syntax to do whatever you need to do and return right back to regular expression syntax.

It also has a much better syntax for doing advanced things, as it was completely redesigned from first principles.

The following is an example of how to match at least one `A` followed by exactly that number of `B`s and exactly that number of `C`s.

(Note that bare square brackets [] are for grouping, not for character classes.)

  my $string = 'AAABBBCCC';

  say $string ~~ /
    ^

    # match at least one A
    # store the result in a named sub-entry
    $<A> = [ A+ ]

    {} # update result object

    # create a lexical var named $repetition
    :my $repetition = $<A>.chars(); # <- embedded Raku syntax

    # match B and then C exactly $repetition times
    $<B> = [ B ** {$repetition} ]
    $<C> = [ C ** {$repetition} ]
  
    $
  /;
Result:
  「AAABBBCCC」
  A => 「AAA」
  B => 「BBB」
  C => 「CCC」
The result is actually a very extensive object that has many ways to interrogate it. What you see above is just a built-in human readable view of it.

In most regular expression syntaxes to match equal amounts of `A`s and `B`s you would need to recurse in-between `A` and `B`. That of course wouldn't allow you to also do that for `C`. That also wouldn't be anywhere as easy to follow as the above. The above should run fairly fast because it never has to backtrack, or recurse.

When you combine them into a grammar, you will get a full parse-tree. (Actually you can do that without a grammar, it is just easier with one.)

To see an actual parser I often recommend people look at JSON::TINY::Grammar https://github.com/moritz/json/blob/master/lib/JSON/Tiny/Gra...

Frankly from my perspective much of the design of "actual parsers" are a byproduct of limited RAM on early computers. The reason there is a separate tokenization stage was to reduce the amount of RAM used for the source code so that further stages had enough RAM to do any of the semantic analysis, and eventual compiling of the code. It doesn't really do that much to simplify any of the further stages in my view.

The JSON::Tiny module from above creates the native Raku data structure using an actions class, as the grammar is parsing. Meaning it is parsing and compiling as it goes.

> magic functions—which behave differently on lists-of-scalars vs. lists-of-lists by special default logic ...

That is completely the wrong way to think about it. Before the Great List Refactor those were dealt with the same by most operations (as you apparently want it). And that was the absolute biggest problem that needed to be changed at the time. There were things that just weren't possible to do no matter how I tried. The way you want it to work DID NOT WORK! It was terrible. Making scalars work as single elements was absolutely necessary to make the language usable. At the time of the GLR that was the single biggest obstacle preventing me from using Raku for anything.

It also isn't some arbitrary default logic. It is not arbitrary, and calling it "default" is wrong because that insinuates that it is possible to turn it off. To get it to do something else with a scalar, you have to specifically unscalarify that item in some manner. (While you did not specifically say 'arbitrary', it certainly seems like that is your position.)

Let's say you have a list of families, and you want to treat each family as a group, not as individuals. You have to scalarize each family so that they are treated as a single item. If you didn't do that most operations will interact with individuals inside of families, which you didn't want.

In Raku a single item is also treated as a list with only one item in it depending on how you use it. (Calling `.head` on a list returns the first item, calling it on an item returns the item as if it had been the first item in a list.) Being able to do the reverse and have a list act as single item is just as important in Raku.

While you may not understand why it works the way it works, you are wrong if you think that it should treat lists-of-scalars the same as lists-of-lists.

> This attempt to fuse higher-order functional programming with magic special behaviors from Perl comes off to me as quixotic.

It is wrong to call it an attempt, as it is quite successful at it. There is a saying in Raku circles that Raku is strangely consistent. Rather than having a special feature for this and another special feature for that, there is one generic feature that works for both.

In Python there is a special syntax inside of a array indexing operation. Which (as far as I am aware) is the only place that syntax works, and it is not really like anything else in the language. There is also a special syntax in Raku designed for array indexing operations, but it is just another slightly more concise way to create a lambda/closure. You can use that syntax anywhere you want a lambda/closure. Conversely if you wanted to use one of the other lambda/closure syntaxes in an array indexing operation you could.

The reason that we say that Raku is strangely consistent, is that basically no other high level language is anywhere near as consistent. There is almost no 'magic special behaviors'. There is only the behavior, and that behavior is consistent regardless of what you give it. There are features in Perl that are magic special behaviors. Those special behaviors were specifically not copied into Raku unless there was a really good reason. (In fact I can't really think of any at the moment that were copied.)

Any sufficiently advanced technology is indistinguishable from magic. So you saying that it is magic is only really saying that you don't understand it. It could be magic, or it could be advanced technology, either way it would appear to be magic.

In my early days of playing with Raku I would regularly try to break it by using one random feature with another. I often expected it to break. Only it almost never did. The features just worked. It also generally worked the way I thought it should.

The reason you see it as quixotic is that you see a someone tilting at a windmill and assuming they are insane. The problem is that it maybe it isn't actually a windmill, and maybe you are just looking at it from the wrong perspective.

I don't think Perl is really that hard to learn. It does have a few traps for people new to the language though.

Raku on the other hand is easy to learn. Of course it is so easy to learn that knowing another language, any other language, can make it more difficult to fully grasp. That is because Raku is strangely consistent.

Most languages have a set of syntaxes for different actions. Raku has a set of features, and the syntax mostly just falls out from that.

When someone who knows another language tries to learn Raku they naturally translate what they already know to Raku features. That will only get you a surface level understanding of the language. No other language is really comparable.

Raku also has a new view of regexes. In Raku a regex is just a DSL for matching text. So rather than bolt on feature after feature like other languages have done it allows you to embed regular Raku code for situations where that is easier. You can also combine them using grammars (a type of class) to get a full parser out of several parts.

In fact the grammar feature in Raku is the only one that is powerful enough to parse Raku easily. Part of that has to do with the ability to mutate the language.

It has been said that the best way to solve a programming problem is to create a language in which solving the problem is easy. Raku, using that ability, allows you to do that easily.

The `but` keyword takes an instance and something to mix into it.

So you can say something like this:

    0 but True
---

Since `True` is a `Bool` it automatically creates a role that has a method `Bool` that returns `True`.

    my $role = role { method Bool { True }}
You can do that manually if you want.
    0 but role { method Bool { True }}
---

It creates a new subclass of Int and mixes in the role.

So:

    0 but True
Is roughly equivalent to:
    do {
      my constant but-true = anon role { method Bool { True }}
      my $class = anon class :: is Int does but-true {}

      $class.new( 0 )
    }

It was originally for helping to organize Perl events. It acted as an entity that could enter into contracts for insurance and rental purposes.

It was extended to have grants among other things.

Larry Wall has historically only really been influential on the design of the language. So it was not taken away, he just has rarely done anything outside of that.

I think it matters who your audience is.

If your audience is mostly programmers then just use `*`

If your audience is physicists or mathematicians then `×` or `·` may be a better fit.

When turning a math expression into code, it is often handy if the code looks a lot like the expression. Even better if you can just copy and paste it. It's hard to translate an expression wrong if you aren't translating it at all.

It would be easy to just make `·` an alias. Then that code would work.

  my &infix:< · > = &infix:< × >;
(After all `×` itself is just an alias of `*` in the source for Rakudo.)

If you need more control you can write it out

  sub infix:< · > (+@vals)
    is equiv(&[×])       # uses the same precedence level etc.
    is assoc<chaining>   # may not be necessary given previous line
  {
    [×] @vals            # reduction using infix operator
  }
I made it chaining for the same reason `+` and `×` are chaining.

---

I don't know enough about the topic to know how to properly write `∧`.

It looks like it may be useful to write it using multis.

  # I don't know what precedence level it is supposed to be
  proto infix:< ∧ > (|) is tighter(&[×]) {*}

  multi infix:< ∧ > (
    Numeric $l,
    Numeric $r,
  ) {
    $l × $r
  }

  multi infix:< ∧ > (
    Vector $l, # need to define this somewhere, or use List/Array
    Vector $r,
  ) {
    …
  }
If it was as simple as just a normal cross product, that would have been easy.
  [[1,2,3],[4,5,6]] »×« [[10,20,30],[40,50,60]]
  # [[10,40,90],[160,250,360]]

  # generate a synthetic `»×«` operator, and give it an alias
  my &infix:< ∧ > = &infix:< »×« >;

  [[1,2,3],[4,5,6]] ∧ [[10,20,30],[40,50,60]]
  # [[10,40,90],[160,250,360]]
Of course, I'm fairly confident that is wrong.

I remember reading an article that the width of railway track was set by the width of chariots.

I don't remember much about the article except it ended with some quip about the width of a car was determined by a couple of horses asses.

In Raku you can also use × (U+D7) for multiplication

    # this assumes that ϕ, ψ, and θ have already been set

    my \cϕ = ϕ.cos; my \sϕ = ϕ.sin;
    my \cψ = ψ.cos; my \sψ = ψ.sin;
    my \cθ = θ.cos; my \sθ = θ.sin;

    my \alpha = [ cψ×cϕ−cθ×sϕ×sψ,   cψ×sϕ+cθ×cϕ×sψ,   sψ×sθ;
               −sψ×cϕ−cθ×sϕ×cψ,  −sψ×sϕ+cθ×cϕ×cψ,   cψ×sθ;
                sθ×sϕ,           −sθ×cϕ,            cθ];
I'm not sure if using × helps or hurts in this case since I'm not really experienced in this area.

These all work because Unicode defines ϕψθ as "Letter lowercase"

    say "ϕψθ".uniprops;
    # (Ll Ll Ll)
---

I would like to note that I used the Unicode "Minus Sign" "−" U+2212 so that it wouldn't complain about not being able to find a routine named "cϕ-cθ". (A space next to the "-" would have also sufficed.)

Technically it is MoarVM that handles graphemes as synthetic codepoints.

We call it NFG for Normalized Form Grapheme.

The JVM and JavaScript backends currently use the built-in string handling features. Which means that they are just as broken as the rest of the code running on them.

---

Of further note, you can use ignorecase in regexes to match "baffle".

    "baffle" ~~ /:ignorecase  BAFfLE  /;

It certainly does. (Or rather Rakudo the compiler for Raku does.)

There are some for people coming from Perl.

    say $^V;

    ===SORRY!=== Error while compiling:
    Unsupported use of $^V variable; in Raku please use
    $*RAKU.version or $*RAKU.compiler.version
    ------> say $^V⏏<EOL>
Some for simple typos.
    my $morning = DateTime.now.truncated-to('day').later( :9hours );
    say $moroning;

    ===SORRY!=== Error while compiling:
    Variable '$moroning' is not declared.  Did you mean '$morning'?
    ------> say ⏏$moroning;


There are some errors that it can't find until it runs your code.
    say $var.length;

    No such method 'length' for invocant of type '...'.  Did you mean
    any of these: 'elems', 'chars', 'codes'?
(I omitted the type because it doesn't really matter.)

The reason Raku doesn't use `length` is because of the common Perl error of calling `length` on an array.

In Perl `length` is a string operation. It would turn your array into a number representing the number of elements, and get the count of characters in that. So it would give you a number representing the order of magnitude of an arrays length.

In order to catch this error, and to reduce the number of times it happens, `chars`, `codes`, and `elems` were chosen instead. (Functions in Raku are intended to do a single operation on a single type. If the argument isn't that type it often coerces into that type. `elems` for example is a list operation, so something like `Str.elems()` always returns `1`.)

Most exceptions are in https://github.com/rakudo/rakudo/blob/master/src/core.c/Exce...

Try APL 5 years ago

Actually once you setup a compose key it can become second nature.

I program in Raku, which can be written using only ASCII, but it can be clearer if you mix in a bit of Unicode.

For example, a raw quote can be written like this using only ASCII

    Q[C:\Windows\]
Or you can write it like this
    「C:\Windows\」
To get those two characters I have added these two sequences
    Compose [ [
    Compose ] ]
I use them so often that it was worth making them a double press of the same key. The other options would have probably been `Q[` and `Q]`.

Another example is

    * * *
That is a lambda that takes two arguments and multiplies them together. It is also much clearer as
    * × *
I didn't even have to add this
    Compose x x
There is also
    1, 2, 3 <<+>> 40, 50, 60
    1, 2, 3  «+»  40, 50, 60

    @array>>.is-prime
    @array».is-prime
These were also already there
    Compose < <
    Compose > >
Most of the compose sequences I have added match the ASCII equivalent. Which makes it very easy to remember them, even though I may not use them often.
    π   pi
    τ   tau
    ∪   (|)
    ⊎   (+)
    ∩   (&)
    ≡   (==)
    ≢   !(==)
(That is I type `Compose p i` for `π`, and it is equivalent to `pi`.)

or are at least similar

    Unicode
        Compose
                #   Actual ASCII

    ∅   set     #   set()
(That is I type `Compose s e t` and it is equivalent to `set()`.)

Though some of the ASCII operators are apparently too long to do that with.

    ∈   (el)    #   (elem)
    ∉   !(el)   #   !(elem)
    ∋   (co)    #   (cont)
    ∌   !(co)   #   !(cont)
I would like to point out that I actually had to read my .XCompose to remember how to type this last four. I don't use them as often as `「」`, and they don't match the ASCII like `≡`.

There are also some that I had to make the compose sequence longer.

    ∘   &o      #   o
---

There are some codes that I just remember for some reason like `U2424` is `␤`. (That's not even an operator in Raku, though it is useful for messaging the camelia eval-bot on irc.)

Try APL 5 years ago

I also wonder how many people understand that linenoise meant noise on a data cable of some description.

i.e. the difference between `d` and `$` is a single bit. If your cable happened to glitch during that first `1` bit, you would get a `$` instead of the `d` you should have.

The thing is that doesn't happen anymore. Or at least when it does happen it gets caught and retransmitted.

---

Which means that some of the first people to say it might not have been making a value judgement, but a statement of fact. (I doubt there was very many in that camp.)

Note that I say that as a person who's second favorite language is Perl. (First favorite is Raku, formally known as Perl6.)

It is too bad that most of coolest features have come to Perl after I switched to Raku.

Try APL 5 years ago

So does Raku

    say 3×(1÷3)
    # 1
It works because `1÷3` is a rational number.
    my \rat = 1÷3;

    say rat.numerator;   # 1
    say rat.denominator; # 3
If you multiply it by 3, you get another rational number which represents 1.
    my \result = 3×rat;

    say result; # 1

    say result.numerator;   # 1
    say result.denominator; # 1
---

Now that this may be slower than using floating point numbers, but it isn't that much slower. You only have two integers that you have to manage.

Actually on many older processors there wasn't built in support for floating point numbers, so it might actually have been faster to use rationals like this.

(I'm not sure if this is how APL handled it.)

---

APL happens to be one of the languages Raku copied ideas from

    ×/⍳10
Translated to Raku
    [×] 1..10
That is rather than `×/…` it is written `[×] …`. Partly because `/` is the ASCII version of the division operator.

We could go further towards replicating it.

    {
      sub prefix:<⍳> (UInt \n){ 1..n }
      sub infix:</> (&f, +list){
        [[&f]] list
      }
      constant term:<×> = &infix:<×>;

      say ×/⍳10;
      # 3628800
    }
Try APL 5 years ago

I'm not sure of the need to do that. Not for parsing anyway.

A well designed regex system is enough without tokenization.

The parser for the Raku language, for example, is a collection of regexes composed into grammars. (A grammar is a type of class where the methods are regexes.)

We could probably do the token thing with multi functions, if we had to.

    multi parse ( 'if',  $ where /\s+/, …, '{', *@_ ) {…}
    multi parse ( 'for', $ where /\s+/, …, '{', *@_ ) {…}
    …
Or something like that anyway.

(Note that `if` and `for` etc are keywords only when they are followed immediately by whitespace.)

I'm not sure how well that would work in practice; as hypothetically Raku doesn't start with any keywords or operators. They are supposed to seem like they are added the same way keywords and operators are added by module authors. (In order to bootstrap it we of course need to actually have keywords and operators there to build upon.)

Since modules can add new things, we would need to update the list of known tokens as we are parsing. Which means that even if Raku did the tokenization thing, it would have to happen at the same time as the other steps.

Tokenization seems like an antiquated way to create compilers. It was needed as there wasn't enough memory to have all of the stages loaded at the same time.

---

Here is an example parser for JSON files using regexes in a grammar to show the simplicity and power of parsing things this way.

    grammar JSON::Parser::Example {

        token TOP       { \s* <value> \s* }

        rule object     { '{' ~ '}' <pairlist>  }
        rule pairlist   { <pair> * % ','        }
        rule pair       { <string> ':' <value>  }

        rule array      { '[' ~ ']' <arraylist> }
        rule arraylist  {  <value> * % ','      }

        proto token value {*}

        token value:sym<number> {
            '-'?                          # optional negation
            [ 0 | <[1..9]> <[0..9]>* ]    # no leading 0 allowed
            [ '.' <[0..9]>+ ]?            # optional decimal point
            [ <[eE]> <[+-]>? <[0..9]>+ ]? # optional exponent
        }

        token value:sym<true>    { <sym>    }
        token value:sym<false>   { <sym>    }
        token value:sym<null>    { <sym>    }

        token value:sym<object>  { <object> }
        token value:sym<array>   { <array>  }
        token value:sym<string>  { <string> }

        token string {
            「"」 ~ 「"」 [ <str> | 「\」 <str=.str_escape> ]*
        }

        token str { <-["\\\t\x[0A]]>+ }
        token str_escape { <["\\/bfnrt]> }
    }
A `token` is a `regex` with `:ratchet` mode enabled (no backtracking). A `rule` is a `token` with `:sigspace` also enabled (whitespace becomes the same as a call to `<.ws>`).

The only one of those that really looks anything like traditional regexes is the `value:sym<number>` token. (Raku replaced non capturing grouping `(?:…)` with `[…]`, and character classes `[eE]` with `<[eE]>`)

This code was copied from https://github.com/moritz/json/blob/master/lib/JSON/Tiny/Gra... but some parts were simplified to be slightly easier to understand. Mainly I removed the Unicode handling capabilities.

It will generate a tree based structure when you use it.

    my $json = Q:to/END/;
    {
      "foo": ["bar", "baz"],
      "ultimate-answer": 42
    }
    END
    my $result = JSON::Parser::Example.parse($json);
    say $result;
The above will display the resultant tree structure like this:
    「{
      "foo": ["bar", "baz"],
      "ultimate-answer": 42
    }
    」
     value => 「{
      "foo": ["bar", "baz"],
      "ultimate-answer": 42
    }
    」
      object => 「{
      "foo": ["bar", "baz"],
      "ultimate-answer": 42
    }
    」
       pairlist => 「"foo": ["bar", "baz"],
      "ultimate-answer": 42
    」
        pair => 「"foo": ["bar", "baz"]」
         string => 「"foo"」
          str => 「foo」
         value => 「["bar", "baz"]」
          array => 「["bar", "baz"]」
           arraylist => 「"bar", "baz"」
            value => 「"bar"」
             string => 「"bar"」
              str => 「bar」
            value => 「"baz"」
             string => 「"baz"」
              str => 「baz」
        pair => 「"ultimate-answer": 42
    」
         string => 「"ultimate-answer"」
          str => 「ultimate-answer」
         value => 「42」
You can access parts of the data using array and hash accesses.
    my @pairs = $result<value><object><pairlist><pair>;

    my @keys = @pairs.map( *.<string>.substr(1,*-1) );
    my @values = @pairs.map( *.<value> );

    say @pairs.first( *.<string><str> eq 'ultimate-answer' )<value>;
    # 「42」
You can also pass in an actions class to do your processing at the same time. It is also a lot less fragile.

See https://github.com/moritz/json/blob/master/lib/JSON/Tiny/Act... for an example of an actions class.

---

Note that things which you would historically talk about as a token such as `true`, `false`, and `null` are written using `token`. This is a useful association as it will naturally cause you to write shorter, more composable regexes.

Since they are composable, we could do things like extend the grammar to add the ability to have non string keys. Or perhaps add `Inf`, `-Inf`, and `NaN` as values.

    grammar Extended::JSON::Example is JSON::Parser::Example {
        rule pair { <key=.value> ':' <value>  } # replaces existing rule

        # adds to the existing set of value tokens.
        token value:sym<Inf>    { <sym> }
        token value:sym<-Inf>   { <sym> }
        token value:sym<NaN>    { <sym> }
    }
This is basically how Raku handles adding new keywords and operators under the hood.

One of the things that `use strict` does is enable `use strict "vars"`.

    use strict;

    no strict qw(vars);
    $foo = $bar;
That's part of the reason `use strict` is recommended.

---

The other major reason is `"refs"`, which disable symbolic refs. Honestly this is *THE* main reason I recommend `use strict`.

Symbolic refs are how you did arrays of arrays prior to Perl5. (Among other uses.)

    use 4.0;

    @a = 'b','c';
    @b = (1, 2);
    @c = (3, 4);

    print $a[1]->[1], "\n"; # 4
That can be a security risk if an attacker can insert or change strings in `@a`.

It isn't (generally) needed anymore of course.

    use 5.0;
    my @a = ( \[1,2], \[3,4] );

    print $a[1]->[1], "\n"; # 4
(The only reason `@b` and `@c` existed was to symbolically reference them.)

You might be right about why Unicode was slow.

In which case I was right.

So much so that to properly support Rakudo on Parrot would require a rewrite of [the middleware].

Which also means that most of the work you would have done to Parrot would needed to be reworked again afterwards.

There was `ifdefs` all over the NQP and Rakudo codebases to work around Parrot's differences. Which was annoying and error-prone.

The `ifdefs` are now mostly in NQP. And even those tend to be constrained a bit.

---

Rakudo's parser was (maybe still is) slow because it can't optimize anything, even the <ws> token.

That is factually incorrect. There are several known optimizations that have not been implemented yet. One of which was even in STD.

Also since Raku treats regexes as code, optimizations to regular code paths can also apply to regexes. That includes optimizations to calling methods like using the <ws> token.

The main reason that they haven't been many is that the people that are competent enough and confident enough to do that work have been busy doing other things. Both their dayjobs and other optimizations or design work.

Really as far as I know, there have been next to no attempts to optimize specifically regexes and grammars since they first got to the current feature set. Certainly not in the several years where I was looking over every commit to Rakudo.

The thing that P6 really needed was a new object system.

There were two options.

1. Create a new object system for Parrot. 2. Create a new object system and a VM around it.

Considering the object system needed is almost nothing like the one that was in Parrot, creating a new VM was probably considerably less work.

Then there is also the problem that some of the major contributors to Parrot didn't care about P6. They have said so publically. I don't think they would have taken too kindly to a completely new object system dumped on their doorsteps. (That's how they might feel about it anyway.)

---

Honestly thinking about it now, I think that if option 1 had been taken there would have been a fork of Parrot. I can almost guarantee it. And I'm not just talking about a fork of the codebase. There would have been a fork of the people behind it as well. It wouldn't have been a peaceful fork either.

I see all of the anger that you have towards what happened. I can only see it as being significantly worse and bigger if they had created a new object system for Parrot instead.

Creating a new object system, and a new VM to support it, was the correct move.

Especially considering that a number of the fundamental design decisions of Parrot which were completely unnecessary or plainly wrong.

I can only imagine the hell it would be to remove or replace any of the features.

---

You seem to be the only one still angry, still here, and still talking about it. Most of the other people who would have been angry regardless of which of those two decisions were made have either gone, or are quiet.

If the Parrot object system was replaced instead, a number of those people would still be angry, and still be here, and be loud. They would just be angry for different reasons.

Instead what happened is they got angry, but mostly drifted away with Parrot.

Come to think about it; things seemed to have gotten quieter after that event. Even though progress started going faster.

---

I would have preferred if they (you) didn't get angry about it. I would have very much preferred if there wasn't a reason to get angry.

The thing is that there would be some number of people would have gotten angry regardless. It's only a matter of who, and for what.

In the reality where Parrot got the new object system instead, I strongly suspect that one of the people who got angry would include jnthn. Since he is responsible for a lot of the progress in recent years, I think I prefer this reality.

I mean I miss the people from back then, but I think problems were piling up, and it was coming to a head at some point.