On Sat, 25 Jan 2020, ToddAndMargo via perl6-users wrote:
> Hi All,
> 
> Anyone have a workaround to my stolen uint's?
> 
> > constant DWORD := uint32;
> (uint32)
> 
> > subset StrOrDword where Str | DWORD;
> (StrOrDword)
> 
> > sub x( StrOrDword $item ) {
> *       say "$item is a " ~ $item.^name;
> *   }
> &x
> 
> > x( "abc" );
> abc is a Str
> 
> > x( 3 );
> Constraint type check failed in binding to parameter '$item'; expected
> StrOrDword but got Int (3)
>   in sub x at <unknown file> line 1
>   in block <unit> at <unknown file> line 1
> 
> > x( 3.UInt );
> Constraint type check failed in binding to parameter '$item'; expected
> StrOrDword but got Int (3)
>   in sub x at <unknown file> line 1
>   in block <unit> at <unknown file> line 1
> 

Raku allows you to use native datatypes and to constrain variables to
refuse anything but some kind of native data. But an uint32 is just
32 bits, no class and no methods attached.

If nevertheless you call methods on native values, they will be boxed
into objects that actually support methods to be called on themselves.
Native integers, signed or not, are boxed into Int.

With that in mind, re-read the documentation section about native
dispatch [1]. Your sub x has no candidate that statically accepts
a native integer. Since you use a subset type, the typecheck is
deferred until runtime, but StrOrDword.ACCEPTS has no native integer
candidate either, and at that point you lost already, as

  x(my uint32 $ = 3)

would result in the 3 being auto-boxed to be able to check it against
`Str | uint32` and because of the boxing, its type is now Int and the
check fails. Consider:

  sub x(uint32 $item) { say "$item is a " ~ $item.^name }

  x(3);                # works, `only` subs auto-unbox the Int literal
  x(my uint32 $ = 3);  # works, a native integer is provided

In both cases, "3 is a Int" will be printed, because the class name
is obtained by calling a (meta-)method on $x, which triggers boxing
to Int. There is no room for a class name in a 32 bits native integer.

Now, if you change the signature to something subsetty/dynamic like

  sub x($item where uint32)

both calls fail to dispatch, as explained above. On the other hand,
this works because there is an explicit native integer candidate for
the dynamic typecheck, so you don't get boxed:

  sub x($item where -> uint32 { True })

By the way, this has nothing to do with unsigned or signed integers,
your signs are not stolen, your values are boxed. The uint32 type is
simply not suitable to be typechecked against, as this quintessentially
paradoxical line of code tells you:

  say (my uint32 $ = 3) ~~ uint32;  # False

Native data is second-class data in a language where everything
is an object.

If you want a workaround, eschew the subset and provide two candidates
for your sub x: one for Str and one for uint32. How do you expect to
handle something that may either be a Raku string object or a native
integer in a single candidate anyway? Or drop the native integer
altogether and use Int until you really need the native thing.

Regards,
Tobias

[1] https://docs.raku.org/language/numerics#Native_dispatch

-- 
"There's an old saying: Don't change anything... ever!" -- Mr. Monk

Reply via email to