Today, we continue our initial exploration of the Real role, that was started a couple of days ago.
Together with its methods, the role contains a number of subroutines (placed outside the role) that define the infix operators with the objects of the Real type. The list is not that long, so let me copy it here:
multi sub infix:<+>(Real \a, Real \b) { a.Bridge + b.Bridge } multi sub infix:<->(Real \a, Real \b) { a.Bridge - b.Bridge } multi sub infix:<*>(Real \a, Real \b) { a.Bridge * b.Bridge } multi sub infix:</>(Real \a, Real \b) { a.Bridge / b.Bridge } multi sub infix:<%>(Real \a, Real \b) { a.Bridge % b.Bridge } multi sub infix:<**>(Real \a, Real \b) { a.Bridge ** b.Bridge } multi sub infix:«<=>»(Real \a, Real \b) { a.Bridge <=> b.Bridge } multi sub infix:<==>(Real \a, Real \b) { a.Bridge == b.Bridge } multi sub infix:«<»(Real \a, Real \b) { a.Bridge < b.Bridge } multi sub infix:«<=»(Real \a, Real \b) { a.Bridge <= b.Bridge } multi sub infix:«≤» (Real \a, Real \b) { a.Bridge ≤ b.Bridge } multi sub infix:«>»(Real \a, Real \b) { a.Bridge > b.Bridge } multi sub infix:«>=»(Real \a, Real \b) { a.Bridge >= b.Bridge } multi sub infix:«≥» (Real \a, Real \b) { a.Bridge ≥ b.Bridge } proto sub infix:<mod>($, $) is pure {*} multi sub infix:<mod>(Real $a, Real $b) { $a - ($a div $b) * $b; }
As you see, most of the operators are using the Bridge method, which allows using the same code in derived classes that may redefine the bridge.
There’s also one prefix operation for negation:
multi sub prefix:<->(Real:D \a) { -a.Bridge }
The cis function works as a type converter returning a complex number:
roto sub cis($) {*} multi sub cis(Real $a) { $a.cis }
Try it out:
> cis(pi) -1+1.22464679914735e-16i > cis(pi).WHAT (Complex)
A bit outstanding, there is a function for atan2:
proto sub atan2($, $?) {*} multi sub atan2(Real \a, Real \b = 1e0) { a.Bridge.atan2(b.Bridge) } # should really be (Cool, Cool), and then (Cool, Real) and (Real, Cool) # candidates, but since Int both conforms to Cool and Real, we'd get lots # of ambiguous dispatches. So just go with (Any, Any) for now. multi sub atan2( \a, \b = 1e0) { a.Numeric.atan2(b.Numeric) }
It is a bit strange as it does not follow the manner in which other trigonometric functions are implemented. The atan2 routine is also defined as a method:
proto method atan2(|) {*} multi method atan2(Real $x = 1e0) { self.Bridge.atan2($x.Bridge) } multi method atan2(Cool $x = 1e0) { self.Bridge.atan2($x.Numeric.Bridge) }
All other trigonometric functions only exist as Real methods. The rest is defined inside the src/core/Numeric.pm file as self-standing subroutines, for example:
proto sub cos($) is pure {*} multi sub cos(Numeric \x) { x.cos } multi sub cos(Cool \x) { x.Numeric.cos } . . . proto sub atan($) is pure {*} multi sub atan(Numeric \x) { x.atan } multi sub atan(Cool \x) { x.Numeric.atan }
There are a few more routines but let us skip them, as they are quite straightforward and clear.
In the next part, we will explore the two methods of the Real role: polymod and base. Stay tuned!
2 thoughts on “🔬59. Examining the Real role of Perl 6, part 2”