Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are enums augmentable?

In Raku, HOWs must expose a list of archetypes through an archetypes method, which is used to determine what broader features of types a type implements, e.g. parametricity or composability. I noticed Metamodel::EnumHOW (the HOW used with enums) has the augmentable archetype, which is given to types that can be extended after composition with the augment keyword when the MONKEY-TYPING pragma is enabled.

My first guess at why enums would be augmentable would be to allow enum values to be added, so I tried writing this:

use v6;
use MONKEY-TYPING;

enum Foo <foo bar baz>;
augment enum Foo <qux>;
say qux;

But this throws:

bastille% raku test.raku
===SORRY!=== Error while compiling /home/morfent/test.raku
Redeclaration of symbol 'Foo'.
at /home/morfent/test.raku:5
------> augment enum Foo⏏ <qux>;

So they're probably not intended to be augmented in this way.

My next guess was that they're intended to be augmentable with regards to the enum values, not the enum type itself. augment, interestingly, doesn't take into account what HOW a type actually has when you tell it what kind of type you're augmenting, so I tried augmenting an enum like you would a class:

use v6;
use MONKEY-TYPING;

enum Foo <foo bar baz>;

augment class Foo {
    proto method is-foo(::?CLASS:D: --> Bool:D) {*}
    multi method is-foo(foo: --> True)          { }
    multi method is-foo(::?CLASS:D: --> False)  { }
}

say foo.is-foo;

Which works:

bastille% raku test.raku
True

But this doesn't feel like how you're intended to augment enums to me. This usage of augment is rather weird, and there isn't any implication that this should be possible to do from its documentation. How are you intended to augment enums?

FAQ

  • Foo.is-foo doesn't appear to have any code? What is it doing?

is-foo is rather heavy-handed with how it uses features of signatures and parameters. It depends on the following:

  • Constant values may be used like types in signatures. This includes enum values, which are dealt with at compile-time.
  • A routine can be made to always return a constant value by making one its signature's return value's type.
  • Variables for any given parameter in a signature are optional.
  • When a colon is placed after the first parameter like this, that first parameter is the signature's invocant. In the case of methods, this allows you to type self however you want.
  • ::?CLASS is an alias for the class whose scope a method is declared in. This exists in class and role bodies, so despite Foo not really being a class, that is what the symbol is referring to.
  • :D is a type smiley denoting that a type should only typecheck against its own instances, not type objects that typecheck like it.

Since foo is a more specific type than ::?CLASS:D (an alias for Foo:D), when invoking this method on foo, the foo multi will be selected and True will get returned, but in any other case, the ::?CLASS:D multi will be selected and False will be returned.

like image 978
Kaiepi Avatar asked Sep 17 '20 16:09

Kaiepi


1 Answers

In Java you can add almost arbitrary attributes and functions to enums. So I do think augment in the way you describe could make sense. For example:

use MONKEY-TYPING;

enum Days(Monday => 1, Tuesday => 2, Wednesday => 3, Thursday => 4, Friday => 5, Saturday => 6, Sunday => 7); 

augment class Days {
    proto method is-weekend(::?CLASS:D: --> Bool:D) {*} 
    multi method is-weekend(Saturday: --> True)          { } 
    multi method is-weekend(Sunday: --> True) {}
    multi method is-weekend(::?CLASS:D: --> False)  { } 

    proto method days-til-weekend(::?CLASS:D: --> Int:D) {*}
    # there is probably a better way to express this, but
    # hopefully the concept is clear
    multi method days-til-weekend(Monday: --> 4) {}
    ...
}

say Monday.is-weekend;
say Wednesday.days-til-weekend;
say Saturday.is-weekend;
like image 114
bobthecimmerian Avatar answered Nov 18 '22 08:11

bobthecimmerian