Question

How to forward declare a role to be used for an enum?

Running this piece of code

use v6.d;

role DrawSurface { ... };

enum Surface does DrawSurface <Fire>;

role DrawSurface {
    method draw () {
        given self {
            when Surface::Fire { "f" }
        }
    }
}

Produces this error:

===SORRY!=== Error while compiling /tmp/me.raku
No appropriate parametric role variant available for 'DrawSurface':
    Cannot resolve caller (Surface:U); Routine does not have any candidates.  Is only the proto defined?
at /tmp/me.raku:5

How do I write that so that I can do this: Surface::Fire.draw?

 4  39  4
1 Jan 1970

Solution

 4

Enums are compile time constructs, so all logic to create the enum must exist when the enum is declared.

The closest solution is to do like this

use v6.d;

enum Surface <Fire>;

role DrawSurface {
    method draw ($surface) {
        given $surface {
            when Surface::Fire { "f" }
        }
    }
}

say DrawSurface.draw(Fire);

or like this

use v6.d;

enum Surface <Fire>;

class SurfaceC {
    has Surface $.surface;

    method draw {
        given $!surface {
            when Surface::Fire { "f" }
        }
    }
}

say SurfaceC.new(surface => Fire).draw;
2024-07-25
Dmitry Matveyev

Solution

 3

Direct solution using multidispatch.

module DrawSurface {
    enum Surface is export <Fire>;

    proto draw (Surface $ ) is export {*}
    multi draw (Fire) {'f'}
}

import DrawSurface;

say draw Fire;
f

Combination with role.

role DrawSurface {
    method draw () {drawp self}
}

enum Surface does DrawSurface <Fire>;

multi drawp(Fire) { 'f' }

say Fire.draw;
f
2024-07-25
wamba