Skip to content

Instantly share code, notes, and snippets.

@JJ

JJ/advent.md Secret

Last active Dec 16, 2020
Embed
What would you like to do?

The Story Of Elfs, and Roles, And Santas' Enterprise.

Let's be serious. After all, we're grown up people and know the full truth about Santa: he is a showman, and he is a top manager of Santa's family business. No one knows his exact position, because we must not forget about Mrs.Santa whose share in running the company is at least equal. The position is not relevant to our story anyway. What is important though is that running such a huge venture requires a lot of skills. Not to mention that the venture itself is also a tremendous show on its own, as one can find out from documentaries like The Santa Clause and many other filmed over the last several decades of human history.

What would be the hardest part of running The North Pole Inc.? Logistics? Yeah, but with all the magic of the sleds, and the reindeers, and the Christmas night this task is not that hard to be done. Manufacturing? This task has been delegated to small outsourcing companies like Lego, Nintendo, and dozens others across the globe.

What else remains? The employees. Elves. And, gosh!, have you ever tried to organize them? Don't even think of trying unless you have a backup in form of a padded room served by polite personnel with reliable supply of pills where you'd be spending your scarce vacation days. It's an inhumane task because when one puts together thousands, if not millions, as some estimations tell, of ambitious stage stars (no elf would ever consider himself as a second-plane actor!), each charged with energy amount more appropriate to a small nuclear reactor... You know...

How do Santas manage? Sure, they're open-hearted, all-forgiving beyond an average human understanding. But that's certainly not enough to build a successful business! So, there must be a secret ingredient, something common to both commercial structures and shows. And I think it's well done role assignment which turns the brownian motion of elf personalities into a self-organized structure.

In this article I won't be telling how Raku helps Santas sort things out or ease certain tasks. Instead I'll try to describe some events happening within The North Pole company with help of the Raku language and specifically its OO capabilities.

Elves

Basically, an elf is:

class Elf is FairyCreature {...}

For some reason, many of them don't like this definition; but who are we to judge them as long, as many humans still don't consider themselves as a kind of apes? Similarly, some elves consider fairy to be archaic and outdated and not related to them, modern beings.

But I digress...

The above definition is highly oversimplified. Because if we start traversing the subtree of the FairyCreature class we gonna find such diverse species in it like unicorns, goblins, gremlins, etc., etc., etc. Apparently, there must be something else, defining the difference. Something what would provide properties sufficiently specific to each particular kind of creature. If we expand the definition of the Elf class we gonna see lines like these:

class Elf is FairyCreature {
    also does OneHead;
	  also does UpperLimbs[2];
    also does LowerLimbs[2];
    also does Magic;
    ...
}

I must make a confession here: I wasn't allowed to see the full sources. When requested for access to the fairy repository the answer was: "Hey, if we reveal everything it's not gonna look like magic anymore!" So, some code here is real, and some has been guessed out. I won't tell you which is which; after all, let's keep it magic!

Each line is a role defining a property, or a feature, or a behavior intrinsic to a generic elf (don't mess it up with the spherical cow). So, when we see a line like that we say that: Elf does Magic ; or, in other words: class Elf consumes role Magic.

I apologize for not explaining in details to Raku newcomers what a role is; hopefully the link will be helpful here. For those who knows Java (I'm a dinosaur, I don't), a role is somewhat similar to interfaces but better. It can define attributes and methods to be injected into a consuming class; it can require certain methods to be defined; and it can specify what other roles the class will consume, and other classes it will inherit from.

As a matter of fact, because of complexity of elf species, the number of roles they do is too high to mention all of them here. Normally, when a class consumes only few of them, it's OK to write the code in another way:

class DisgustingCreature is FairyCreature does Slimy does Tentacles[13] { ... }

But numerous roles are better be put into class body with the prefix also.

When Santas Hire An Elf

This would probably be incorrect to say that elves are hired by Santas. In fact, as we know it, all of them do work for The North Pole Inc. exclusively. Yet, my thinking is such that at some point in the history the hiring did take place. Let's try to imagine how it could have happen.

One way or another, there is a special role:

role Employee {...}

And there is a problem too: our class Elf is already composed and immutable. Moreover, each elf is an object of that class! Or, saying the same in Raku language: $pepper-minstix.defined && $pepper-minstix ~~ Elf. Ok, what's the problem? If one tries to $pepper-minstix.hire(:position("security officer"), :company("The North Pole Inc."), ...) a big boom! will happen because of no such method 'hire' for invocant of type 'Elf'. Surely, the boom! is expected because long, long time ago elves and work were as compatible as Christmas and summer! But then there was Santas. And what they did is called mixing a role into an object:

$pepper-minstix does Employee;

From the outside the operation does adds content of Employee role to the object on its left hand side, making all role attributes and methods available on the objet. Internally it creates a new class for which the original $pepper-minstix.WHAT is the only parent class; and which consumes the role Employee. Eventually, after the does operator, say $pepper-minstix.WHAT will output something like (Elf+{Employee}). This is now the new class of the object held by $pepper-minstix variable.

Such a cardinal change in life made elves much happier! Being joyful creatures anyway, they now got a great chance to be also useful by sharing their joy with all the children, and sometimes not only children. The only thing worried them though. You know, it's really impossible to find two identical people; the more so there're no two identical elves. But work? Wouldn't it level them all down in a way? Santas wouldn't be the Santas if they didn't share these worries with their new friends. To understand their solution let's see what Employee role does for us. Of the most interest to us are the following lines:

has $.productivity;
has $.creativity;
has $.laziness;
has $.position;
has $.speciality;
has $.department;
has $.company;

For simplicity, I don't use typed attributes in the snippet, though they're there in the real original code. For example, $.lazyness attribute is a coefficient among other things used in a formula calculating how much time is spent for coffee or eggnog breaks. The core of the formula is something like:

method todays-cofee-breaks-length {
    $.company.work-hours * $.laziness * (1 + 0.2.rand)
}

Because they felt their responsibility for the children, elves agreed to limit their maximum laziness level. Therefore the full definition of the attribute is something like:

has Num:D $.laziness where * < 0.3;

If anybody thinks that the maximum is too high then they don't have the Christmas spirit in their hearts! Santa Claus was happy about it, why wouldn't we? I personally sure his satisfaction is well understood because his own maximum is somewhere closer to 0.5, but – shh! - let's keep it a secret!

Having all these characteristics in place, Santas wanted to find a way to set them to as diverse combinations, as possible. And here is what they came up with something similar to this:

role Employee {
    ...
    method my-productivity {...}
    method my-creativity {...}
    method my-laziness {...}
    submethod TWEAK {
        $!productivity //= self.my-productivity;
        $!creativity //= self.my-creativity;
        $!laziness //= self.my-laziness;
    }
}

Now it was up to an elf to define their own methods to set the corresponding characteristics. But most of them were OK with a proposed special role for this purpose:

role RandomizedEmployee {
    method my-productivity { 1 - 0.3.rand }
    method my-creativity { 1 - 0.5.rand }
    method my-laziness { 1 - 0.3.rand }
}

The hiring process took the following form now:

$pepper-minstix does Employee, RandomizedEmployee;

But, wait! We have three more attributes left behind! Yes, because these were left up to Santas to fill in. They knew what kind of workers and where they needed most. Therefore the final version of the hiring code was more like:

$pepper-minstix does Employee(
        :company($santas-company),
        :department($santas-company.department("Security")),
        :position(HeadOfDepartment),
        :speciality(GuardianOfTheSecrets),
        ...
    ), 
    RandomizedEmployee;

With this line the Raku's mixin protocol does the following:

  1. creates a new mixin
  2. sets attributes defined with named parameters
  3. invoke role's constructor TWEAK
  4. returns a new employee object

Because everybody knew that the whole thing is going to be a one-time venture as elves would never leave their new boss alone, the code was a kind of trade-off between efficiency and speed of coding. Still, there were some interesting tricks used, but discussing them is beyond this story mainline. I think many readers can find their own solutions to the problems mentioned here.

Me, in turn, moves on to a story which took place not long ago...

When Time Is Too Scarce

It was one of those craziest December days, when Mrs.Santa left for an urgent business trip. Already busy with mails and phone calls Mr.Santa got additional duties in the logistics and the packing departments which are usually handled by his wife. There were no way he could skip those or otherwise risks of something going wrong on the Christmas night would be too high. The only way to get everywhere on time was to cut on the phone calls. It meant to tell the elf-receptionist to answer with the "Santa is not available" message.

Santa sighed. He could almost see and hear the elf staring at him with deep regret and asking: "Nicholas, are you asking me to lie?" Oh, no! Of course he wouldn't ask, but...

But? but! After all, even if the time/space magic of the Christmas is not available on other days of year, Santa can still do other kind of tricks! So, here is what he did:

role FirewallishReceptionist {
    has Bool $.santa-is-in-the-office;
    has Str $.not-available-message;
    method answer-a-call {
        if $.santa-is-in-the-office {
            self.transfer-call: $.santas-number;
        }
        else {
            self.reply-call: $.not-available-message, 
                                :record-reply,
                                :with-marry-christmas;
        }
    }
}

my $strict-receptionist = 
    $receptionist but FirewallishReceptionist(
        :!santa-is-in-the-office, 
        :not-available-message(
            "Unfortunately, Santa is not available at the moment."
            ~ ... #`{ the actual message is longer than this }
        )
    );

$company.give-a-day-off: $receptionist;
$company.santa-office-frontdesk.assign: :receptionist($strict-receptionist);

The operator but is similar to does, but instead of altering its left hand side operand its clone is created and then mixes in the right hand side role into the clone.

Just imagine the amazement of the receptionist when he saw his own copy taking his place at his desk! But a day off is a day off, he wasn't really much against applying his laziness coefficient to the rest of that day...

As to Santa himself... He has never been really proud of what he done that day. Even though it was needed in the name of saving the Christmas. Besides, the existence of a clone created a few awkward situations later, especially when both elves were trying to do the same work while still sharing some data structures. But that's a separate story on its own...

When New Magic Helps

Have you seen the elves this season? They're always very strict in sticking to the latest tendencies of Christmas fashion: rich colors, spangles, all fun and joy! Yet this year is really something special!

It all started at the end of the spring. Santa was sitting in his chair, having well-deserved rest of the last Christmas he served. The business did not demand as much attention as it usually does at the end of the autumn. So, he was sitting by the fireplace, drinking chocolate, and reading the news. Though the news was far from being the best part of Santa's respite (no word about 2020!). Eventually, Santa put away his tablet, made a deep sip from his giant mug, and said aloud: "Time to change their caps!" No idea what pushed him to this conclusion, but from this moment on elves knew that a new fashion is coming!

The idea Santa wanted to implement was to add WiFi connection and LEDs to elvish caps, and to make the LEDs twinkle with patterns available from a local server of The North Pole Inc. Here is what he started with:

role WiFiConnect {
    has $.wifi-name is required;
    has $.wifi-user is required;
    has $.wifi-password is required;
    submethod TWEAK { 
        self.connect-wifi( $!wifi-name, $!wifi-user, $!wifi-password );
    }
}

role ShinyLEDs {
    submethod TWEAK { 
        if self.test-cirquits {
            self.LED( :on );
        }
        if self ~~ WiFiConnect {
            self.set-LED-pattern: self.fetch( :config-key<LED-pattern> );
        }
    }
}

class ElfCap2020 is ElfCap does WiFiConnect does ShinyLEDs {...}

Note, please, that I don't include the body of the class here for it's too big for this article.

But the attempt to compile the code resulted in:

Method 'TWEAK' must be resolved by class ElfCap2020 because it exists in multiple roles (ShinyLEDs, WiFiConnect)

"Oh, sure thing!" – Santa grumbled to himself. And added a TWEAK submethod to the class:

    submethod TWEAK {
        self.R1::TWEAK;
        self.R2::TWEAK;
    }

This made the compiler happy. and ElfCap2020.new came up with a new and astonishingly fun cap instance! "Ho-ho-ho!" – Santa couldn't help laughing of joy. It was the time to start producing the new caps for all company employees; and this was the moment when it became clear that mass production of the new cap will require coordinated efforts of so many third-party vendors and manufacturers that there were no way to equip everybody with the new toy by the time the Christmas comes.

Does Santa give up? No, he never does! What if we try to modernize the old caps? It would only require so many LEDs and controllers and should be feasible to handle on time!

Suit the action to the world! With a good design it should be no harder than to:

$old-cap does (WiFiConnect(:$wifi-name, :$wifi-user, :$wifi-password), ShinyLEDs);

And... Boom! Method 'TWEAK' must be resolved by class ElfCap+{WiFiConnect,ShinyLEDs} because it exists in multiple roles (ShinyLEDs, WiFiConnect)

Santa sighed. No doubt, this was expected. Because does creates an implicit empty class the two submethods from both roles clash when compiler tries to install them into the class. A deadend? No way! Happy endings is what Santa loves! And he knows what to do. He knows that there is a new version of the Raku language is in development. It is not released yet, but is available for testing with Rakudo compiler if requested with use v6.e.PREVIEW at the very start of a compilation unit which is normally is a file.

Also, Santa knows that one of the changes the new language version brings in is that it keeps submethods where they were declared, no matter what. It means that where previously a submethod was copied over from a role into the class consuming it, it will now remain be the sole property of the role. And the language itself now takes care of walking over all elements of a class inheritance hierarchy, including roles, and invoking their constructor and/or destructor submethods if there're any.

Not sure what it means? Check out the following example:

use v6.e.PREVIEW;
role R1 {
    submethod TWEAK { say ::?ROLE.^name, "::TWEAK" }
}
role R2 {
    submethod TWEAK { say ::?ROLE.^name, "::TWEAK" }
}
class C { };
my $obj = C.new;
$obj does (R1, R2);
# R1::TWEAK
# R2::TWEAK

Apparently, adding use v6.e.PREVIEW at the beginning of the modernization script makes the $old-cap does (WiFiConnection, ShinyLEDs); line work as expected!

Moreover, switching to Raku 6.e also makes submethod TWEAK unnecessary for ElfCap2020 class too if its only function is to dispatch to role TWEAKs. Though, to be frank, Santa kept it anyway as he needed a few adjustments to be done at the construction time. But the good thing is that it wasn't necessary for him to worry that much about minor details of combining all the class components together.

And so the task was solved. At the first stage all the old caps were modernized and made ready before the season started and Christmas preparations took all remaining spare time of The North Pole Inc. company. The new caps will now be produced without extra fuss and be ready by the 2021 season. The time spared Santa used to adapt WiFiConnection and ShinyLEDs to use them with his sleds too. When told by The Security Department that additional illumination makes sled's camouflaging much harder if ever possible Santa only shrugged and replied: "You'll manage, I have my trust in you!" And they did, but that'd be one more story...

Happy End

When it comes to The North Pole it's always hard to tell the truth from fairy tales, and to separate magic from the science. But, after all, a law of nature tells it that any sufficiently advanced technology is indistinguishable from magic. With Raku we try to bring a little bit of good magic into this life. It is so astonishing to know that Raku is supported by nobody else but the Santa family themselves!

Merry Christmas and Happy New Year!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment