Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically created class with invocant constraint

Tags:

raku

rakudo

Official docs says that class can be built dynamically like so:

constant A := Metamodel::ClassHOW.new_type( name => 'A' );
A.^add_method('x', my method x(A:D:) { say 42 });
A.^compose;                                                 
     
A.new.x(); # x will be only called on instances

But what if I am building a class and don't assign it to a constant but rather store it in a var (for instance when I need to create a bunch of classes in loop) like so:

my $x = Metamodel::ClassHOW.new_type( name => 'some custom string' );
$x.^add_method('x', my method ($y:) { say $y });
$x.^compose;

But in this case I can call method x both on class ($x.x) and on instance ($x.new.x) though I want it to only be called on instances. I tried to define method like so:

$x.^add_method('x', my method ($y:D:) { say $y });

but that produces an error:

Invalid typename 'D' in parameter declaration.

Of course I can check defindness of the value inside the method but I want some compile-time guarantees (I want to believe that type checking is done in compile time).

I tried to play with signatures and parameters but couldn't find a way to create an invocant parameter but what is more important I am not sure how to assign signature which I have in a variable to some method.

like image 781
hasrthur Avatar asked Jul 22 '26 00:07

hasrthur


1 Answers

Change:

my $x = ...

to:

my constant x = my $ = ...

In full:

my constant x = my $ = Metamodel::ClassHOW.new_type( name => 'some custom string' );
x.^add_method('x', my method (x:D $y:) { say $y });
x.^compose;
x = Metamodel::ClassHOW.new_type( name => 'another custom string' );
...

I want some compile-time guarantees (I want to believe that type checking is done in compile time).

By making the constant's RHS be a variable declaration, you blend static compile-time aspects with dynamic run-time ones.

(BTW, the my before constant is just me being pedantic. A plain constant like you've used is equivalent to our constant which is less strict than my constant.)

I note the error message for a non-instance is different:

Type check failed in binding to parameter '$y';
expected type some custom string cannot be itself

At a guess that's because the usual message comes from Mu or Any and your class isn't inheriting from either of them.

I am not sure how to assign signature which I have in a variable to some method.

I'll leave that part unanswered.

like image 148
raiph Avatar answered Jul 28 '26 17:07

raiph