Should it be possible to add a definedness constraint on parameterized roles? The following attempt:
role R[::T] { }
class C {
method m ( R[Str]:D $a ) { }
}
results in:
Invalid typename 'D' in parameter declaration.
at ... scratch.raku:4
------> method m ( R[Str]:D⏏ $a ) { }
and declaring a variable:
role R[::T] { }
class S does R[Str] { }
my R[Str]:D $r = S.new;
results in:
Malformed my
at ... scratch.raku:8
------> my R[Str]⏏:D $r = S.new;
TL;DR @wamba's answer assumes the "definiteness" interpretation of your question (which seems likely to be what you actually meant) and provides a nice succinct solution for that. This answer explains why your question is ambiguous, and provides a solution for both interpretations. Neither of my solutions are @wamba's, so this answer serves as a complement to theirs.
Your question is ambiguous
Here's what you wrote at the start:
Here instead is the implicit question:
I'll address them in reverse order, given that it's near certain you meant definite, not defined.
Definite
Definiteness corresponds to the
:Dtype constraint or.DEFINITEcompiler macro.This is what the code in your question is about.
The fact that
R[Str]:Dis invalid syntax may be due to an oversight, or lack of tuits, or lack of consensus, or a deliberate decision. I have not researched that. Someone may have filed an issue about it.¹ Again, I have not researched that.Here's a way to add an equivalent definiteness constraint that works for your example:
Defined
Definedness corresponds to the
.definedmethod call, as tested by features such aswithand infix//.This is what your question's title and opening sentence refer to, taken literally.
Here's one way:
Note how the result is the same as for
.DEFINITE(and would have been ifType[Type]:Dwas valid syntax).But they aren't always the same for all objects, which reflects the fact that a definiteness constraint is not exactly the same as a definedness constraint --
:Dand.DEFINITEcorrespond to definiteness whereas.definedcorresponds to definedness.Definite vs Defined
The similarity between definiteness and definedness is deliberate. If a given object has not got a
.definedmethod (and almost none do) it will inheritMu's. And that.definedmethod just returnsself.DEFINITE.But while the
DEFINITEmethod cannot be overridden², the.definedone can be:Users may override
.definedfor their classes/objects. This makes it easy for someone writing a foreign language adaptor to allow Raku interop with another PL which has a different notion of definedness than Raku's. (This is pretty much the only use case. It is generally ill-advised for ordinary Raku code to override.defined.)The built in
Failureclass overrides.defined. It returnsFalsefor both the type object (as normal) and instances. Thus:displays:
The last line, which corresponds to
Failure.new, hasTruein the first column (its.DEFINITEisTrue) butFalsein the second column (its.definedisFalse).Footnotes
¹ I don't think an issue should be filed for making
Type[Type]:Dwork. Similarly, if an issue has been filed, then I would anticipate it being ignored for the foreseeable future unless a non-core-dev creates a suitable PR for it (which may still be rejected).² Definiteness is fundamental to the static typing foundation of Raku's gradual type system and its notion that an "object" is something that can be either a type object or an object instance. To allow the compiler to rely on this simple either/or boolean at compile time, the behavior of "definiteness", and thus the
.DEFINITEmacro, cannot be overridden by user code -- unlike the.definedmethod.