Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test module 'isa-ok' with Buf

Tags:

testing

raku

Using the Perl6 Test module to test an object's type with Buf:

use Test;
isa-ok Buf.new, Buf;
isa-ok Buf.new, Blob;
isa-ok Buf.new, 'Buf';
isa-ok Buf.new, 'Blob';
ok Buf.new ~~ Buf;
ok Buf.new ~~ Blob;
does-ok Buf.new, Buf;
does-ok Buf.new, Blob;

Here's the output:

not ok 1 - The object is-a 'Buf'
# Failed test 'The object is-a 'Buf''
# at buftest line 3
# Actual type: Buf
not ok 2 - The object is-a 'Blob'
# Failed test 'The object is-a 'Blob''
# at buftest line 5
# Actual type: Buf
ok 3 - The object is-a '"Buf"'
not ok 4 - The object is-a '"Blob"'
# Failed test 'The object is-a '"Blob"''
# at buftest line 9
# Actual type: Buf
ok 5 - 
ok 6 - 
ok 7 - The object does role 'Buf'
ok 8 - The object does role 'Blob'

How does isa-ok really work? How does that differ from just ~~? What is the difference between testing an object against Buf vs. 'Buf'? Why isn't a Buf considered to be isa a Buf or Blob? (while it isa a 'Buf' but still not a 'Blob'?

In general, does isa-ok understand roles or must does-ok be used for them?

like image 967
Curt Tilmes Avatar asked Mar 16 '19 12:03

Curt Tilmes


1 Answers

See isa-ok does not work with parametrized types. (I think the issue title is misleading because aiui it's really about classes vs roles not parameterized vs unparamaterized types. One can write Array[Int] after all and that's arguably a parameterized type.)

I found this by searching the Rakudo Github repo for 'isa-ok' and clicking on Issues.

Mu.pm6 defines isa:

proto method isa(|) {*}

multi method isa(Mu \SELF: Mu $type --> Bool:D) {
    nqp::hllbool(SELF.^isa($type.WHAT))
}

multi method isa(Mu \SELF: Str:D $name --> Bool:D) {
    return True if .^name eq $name for SELF.^mro;
    False
}

The first multi only works if the type is a class. In P6 the word "isa" has a technical meaning that A isa B iff both A and B are classes and A is, or inherits from, B.

(More concretely, the isa of a class that does Perl6::Metamodel::MROBasedTypeChecking resolves to a method in the corresponding role that checks for a match based on going through the class's method resolution order.)

A type like Buf is a role. (Roles can be easily "punned" into corresponding anonymous classes/instances by, eg. Buf.new, but that doesn't stop Buf itself being a role.)

A type like Array works because Array is a class.

So:

put Array.HOW.^name; # Perl6::Metamodel::ClassHOW+{<anon>}
say Array.^mro;      # ((Array) (List) (Cool) (Any) (Mu))
isa-ok Array, List;  # ok
put Buf.HOW.^name;   # Perl6::Metamodel::ParametricRoleGroupHOW
say Buf.^mro;        # No such method 'mro' for invocant of type
                     # 'Perl6::Metamodel::ParametricRoleGroupHOW'

The string version of isa-ok applies only if you pass a string version of the type's name. For good or ill it allows for a sloppier way of thinking about types and will accept an exact match.

~~ is "smart matching". It's up to the type on the right to decide if the thing on the left is to be considered a match.

In general, does isa-ok understand roles or must does-ok be used for them?

No it doesn't. You should use does-ok.

like image 101
raiph Avatar answered Oct 21 '22 11:10

raiph