this new question is a follow up to my previous that has emerged as I flesh things out. Please note that I have also done some research and I am consciously skirting the Scalar Mixins bug mentioned here. So I am mixing the role in to the Object and not to the Scalar container.
Big picture is to do math operations that also perform simple error calculations.
Here is a concise version of my failing code:
1 role Error {
2 has $.abs-error
3 }
4
5 multi prefix:<-> ( Error:D $x ) is default {
6 # - $x; # fails - enters an infinite loop
7 # - $x.Real; # fails - does not drop the Error mixin
8 ( 0 - $x ) does Error($x.abs-error) # works - but relies on the infix:<-> form
9 }
10
11 my $dog = 12.5 does Error(0.5);
12
13 #what i have...
14 say $dog; #12.5
15 say $dog.WHAT; #(Rat+{Error})
16 say $dog.abs-error; #0.5
17
18 #what i want...
19 say (-$dog); #-12.5
20 say (-$dog).WHAT; #(Rat+{Error})
21 say (-$dog).abs-error; #0.5
The heart of my question is:
I have tried (desperately?) a few things:
Thanks for all advice!!
The direct answer to the question posed: no, there's no operation to undo a mixin. You can do some tricks to reach the functionality of the original type, however:
$obj-with-mixin.OriginalType::method-name()
form to call methods that have been overridden.multi
sub (such as the operators), you could do &prefix:<->.cando(\(1.5)).head
to resolve, but not call, the implementation of -
on Rat
, and then call it directly.Looking at this question and your previous one, however, it seems you're fighting the language every step of the way; is default
is really a last resort, and even if you can get it to work using the mixin approach, you'll find the result is terribly slow, in no small part because mixins trigger deoptimization (falling out of specialized and JIT-compiled code back to the interpreter).
Perhaps explore a design using composition instead:
# An object holding the value and the error.
class Error does Real {
has Real $.value;
has Real $.abs-error;
multi method Real(Error:D:) { $!value }
multi method gist(Error:D:) { "$!value±$!abs-error" }
}
# A cute constructor of this type, just for fun.
multi infix:<±>(Real $value, Real $abs-error) {
Error.new(:$value, :$abs-error)
}
# Negation; no `is default` or other tricks required!
multi prefix:<->(Error $e --> Error) {
Error.new(value => -$e.value, abs-error => $e.abs-error)
}
# It works!
my $x = 4.5 ± 0.1;
say $x;
say -$x;
Coming off @raiphs comment, I have figured out a quick and dirty fix that uses the fact that I know the .say method works to produce the unadorned value of the Object...
... OO programming purists, please look away now.
1 role Error {
2 has $.abs-error;
3
4 method negate {
5 my $val = +"{self}"; #extract unadorned value of $x
6 (- $val) does Error( $!abs-error );
7 }
8 }
9
10 multi prefix:<-> ( Error:D $x ) is default { $x.negate }
11
12 my $dog = 12.5 does Error(0.5);
13
14 #what i get...
15 say (-$dog); #-12.5
16 say (-$dog).WHAT; #(Rat+{Error})
17 say (-$dog).abs-error; #0.5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With