$SPAD/src/input overload.input

David Cyganski December 3, 2016

Abstract

Type conversion and overload problems

Contents

2

— * —

)set break resume
)spool overload.output
)set message test on
)set message auto off
)clear all

———-

1 Type Conversion and Overload problems

Several non-intuitive problems with overloading and type conversions arose while developing the biquaternion (see biquat.input) support function collection. I have extracted the minimum code set to illustrate each of these problems.

2 Implicit and Explicit Type Conversions

We begin by illustrating function calling with variously typed arguments and conversion which we will break in various ways, some understandable, some not(?), below.

The cos function will produce float outcomes for float arguments — * —

--S 1 of 51
cos(1.237)
--R
--R
--R   (1)  0.3276321705 9891498386
--R                                                                  Type: Float
--E 1

———-

can handle expressions that mix floats and integers — * —

--S 2 of 51
cos(1.237/2)
--R
--R
--R   (2)  0.8147490934 6341557739
--R                                                                  Type: Float
--E 2

———-

but will respect an integer expression, as we would want it to, by not evaluating — * —

--S 3 of 51
cos(2/3)
--R
--R
--R            2
--R   (3)  cos(-)
--R            3
--R                                                    Type: Expression(Integer)
--E 3

———-

We can coerce the evaluation as a float by forcing the floating point evaluation of the division and typing of the outcome in a variety of ways. Each of the following forms is effective in some appropriate and understandable way. Some act explicitly on the “/” operator to force a polymorphic choice, others convert the type of the second constand in each expression which results in a proper implicit selection of which “/” definitition to use.

— * —

--S 4 of 51
cos(2/3::Float)
--R
--R
--R   (4)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 4
--S 5 of 51
cos((2/3)::Float)
--R
--R
--R   (5)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 5
--S 6 of 51
cos(2/3$Float)
--R
--R
--R   (6)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 6
--S 7 of 51

cos((2/3)$Float)
--R
--R
--R   (7)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 7
--S 8 of 51
cos(2/3@Float)
--R
--R
--R   (8)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 8
--S 9 of 51
cos((2/3)@Float)
--R
--R
--R   (9)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 9

———-

But, as we would expect, it is too late to attempt coercion after the fact. Coercion operates “on the surface and not deeply” as illustrated here.

— * —

--S 10 of 51
cos(2/3)::Float
--R
--R
--RDaly Bug
--R   Cannot convert from type Expression(Integer) to Float for value
--R       2
--R   cos(-)
--R       3
--R
--E 10

———-

However, there is a real need for a deep coercion operator that operates on the innermost atomic constants. Suppose we define

— * —

--S 11 of 51

cosf(x:Expression Integer):Expression Integer == 1+cos(x/2)
--R
--R   Function declaration cosf : Expression(Integer) -> Expression(
--R      Integer) has been added to workspace.
--R                                                                   Type: Void
--E 11

———-

which is an example of a simple function that might be defined in the course of typical work. We wish to declare functions as having integer based fractions, rather than forming approximate decimal expansions, which is preferred for purposes of analytic examination and simplification for both the human and the Axiom system. The Axiom book and online resources are full of examples in which this choice has been made by the authors thanks to the power of this form of expression – even though it amounts to lying to Axiom in many cases as to the ultimate destiny of the function being defined. But woe to us if we wish later to evaluate it in a more general way because it is a tangled web we weave when we practice to decieve.

— * —

--S 12 of 51
cosf(2/3)
--R
--R   Compiling function cosf with type Expression(Integer) -> Expression(
--R      Integer)
--R
--R             1
--R   (11)  cos(-) + 1
--R             3
--R                                                    Type: Expression(Integer)
--E 12
--S 13 of 51
cosf((2/3)::Float)
--R
--R   Conversion failed in the compiled user function cosf .
--R
--RDaly Bug
--R   Cannot convert from type Float to Expression(Integer) for value
--R   0.6666666666 6666666667
--R
--E 13

———-

Thus in effect once we wrap a function around an integer base definition, we are stuck and unable to evaluate it as a float later, unlike the core basic functions that can be used either way. This forces us to choose the Float type throughout at a loss of comprehensibility and analyzability, unless we seek to more than double our development type by supplying an overloaded integer base and Float base version of every step of a sequential development of a formula.

Bizarrely, the draw function seems to have the power to override the type problem as shown here

— * —

--S 14 of 51
--draw(cosf(x),x=0..15)
--E 14

———-

Why can’t we grant this deep coercion power to some new form of floating point conversion operation which can be applied at will? If draw has this power, why not put it in the hands of the user?

Alternatively, it would be best to have a mixed type – mixed = Integer/Float. Like Maple expressions it would leave integers as integers and floats as floats, unmolested and treated as generic constant quantities with distinguishable parts until an evalf like function that would force them entirely into the Float type. For example, in Maple “cos(2/3)+1.2323” remains as is, while in Axiom we get

— * —

--S 15 of 51
cos(2/3)+1.2323
--R
--R
--R   (12)  2.0181872607 769480007
--R                                                      Type: Expression(Float)
--E 15

———-

In a way, Axiom already has a quantity treated like this – the constant force combination of itself with an Integer. It simply results in a new kind of Integer evaluation of type Pi

— * —

--S 16 of 51
3/4+%pi
--R
--R
--R         4%pi + 3
--R   (13)  --------
--R             4
--R                                                                     Type: Pi
--E 16

———-

3 Overloading problems

Now let’s examine properties and problems with overloading.

Define the type Q of Hamiltonian biquaternions — * —

--S 17 of 51
C:=Complex Expression Integer
--R
--R
--R   (14)  Complex(Expression(Integer))
--R                                                                 Type: Domain
--E 17
--S 18 of 51
Q:=Quaternion C
--R
--R
--R   (15)  Quaternion(Complex(Expression(Integer)))
--R                                                                 Type: Domain
--E 18

———-

While developing the support functions, this definition of biquat division was introduced to simplify the format of the formulae

— * —

--S 19 of 51
((x:Q)/(y:Q)):Q == x*inv(y)
--R
--R   Function declaration ?/? : (Quaternion(Complex(Expression(Integer)))
--R      ,Quaternion(Complex(Expression(Integer)))) -> Quaternion(Complex(
--R      Expression(Integer))) has been added to workspace.
--R                                                                   Type: Void
--E 19

———-

But is this typed function in any way actually restricted to quaternions? On the face, it would appear all is normal, here’s an example of integer division

— * —

--S 20 of 51
x:=15/6
--R
--R   Compiling function / with type (Quaternion(Complex(Expression(
--R      Integer))),Quaternion(Complex(Expression(Integer)))) ->

--R      Quaternion(Complex(Expression(Integer)))
--R
--R         5
--R   (17)  -
--R         2
--R                               Type: Quaternion(Complex(Expression(Integer)))
--E 20

———-

But though the answer was right, the type is now a biquat. If we don’t notice this, and proceed, some things seem still to act normally, for example, no complaint from Axiom with

— * —

--S 21 of 51
cos(x)
--R
--R
--R             5
--R   (18)  cos(-)
--R             2
--R                                                    Type: Expression(Integer)
--E 21

———-

Of course, we still get a correct answer with — * —

--S 22 of 51
cos(1.237)
--R
--R
--R   (19)  0.3276321705 9891498386
--R                                                                  Type: Float
--E 22

———-

But let’s try to apply this as a simple mixed float/integer function — * —

--S 23 of 51
cos(15.457/6)
--R
--R   Conversion failed in the compiled user function / .
--R
--RDaly Bug

--R   Cannot convert from type Float to Quaternion(Complex(Expression(
--R      Integer))) for value
--R   15.457
--R
--E 23

———-

Obviously the quaternion version of “/” is being invoked despite mismatches of the arguments and the supposed overloading in effect. Well, what if we built a new cosine function that forced the form of the arguments into certain types to avoid mismatch?

— * —

--S 24 of 51
c(y:Float):Float == cos(y)
--R
--R   Function declaration c : Float -> Float has been added to workspace.
--R                                                                   Type: Void
--E 24

———-

At first this seems to work, we can still evaluate a float — * —

--S 25 of 51
c(1.237)
--R
--R   Compiling function c with type Float -> Float
--R
--R   (21)  0.3276321705 9891498386
--R                                                                  Type: Float
--E 25

———-

and we can even get a float answer when we introduce the integer coercible biquat variable value generated from the above.

— * —

--S 26 of 51
c(x)
--R
--R
--R   (22)  - 0.8011436155 4693371483
--R                                                                  Type: Float
--E 26

———-

But that was only misdirection, because this breaks down for reasonable expressions because of the “/” operation still not being resolved correctly.

— * —

--S 27 of 51
c(1.237/2)
--R
--R   Conversion failed in the compiled user function / .
--R
--RDaly Bug
--R   Cannot convert from type Float to Quaternion(Complex(Expression(
--R      Integer))) for value
--R   1.237
--R
--E 27

———-

Rather than complaining about it, what if we tried the various coercions that served to solve the similar type conversion problem we had when just dealing with Integer Fraction versus Floats at the top of the page. Our results are mixed. Recall that each of the following worked in the previous case, producing the correct floating result in each case.

— * —

--S 28 of 51
cos(2/3::Float)
--R
--R
--R             2
--R   (23)  cos(-)
--R             3
--R                                                    Type: Expression(Integer)
--E 28
--S 29 of 51
cos((2/3)::Float)
--R
--R
--R   (24)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 29
--S 30 of 51
cos(2/3$Float)
--R
--R
--R             2

--R   (25)  cos(-)
--R             3
--R                                                    Type: Expression(Integer)
--E 30
--S 31 of 51
cos((2/3)$Float)
--R
--R
--R   (26)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 31
--S 32 of 51
cos(2/3@Float)
--R
--R
--R             2
--R   (27)  cos(-)
--R             3
--R                                                    Type: Expression(Integer)
--E 32
--S 33 of 51
cos((2/3)@Float)
--R
--R
--RDaly Bug
--R   An expression involving @ Float actually evaluated to one of type
--R      Quaternion(Complex(Expression(Integer))) . Perhaps you should use
--R      :: Float .
--E 33

———-

Try these examples with our type constrained function, which has better luck now — * —

--S 34 of 51
c(2/3::Float)
--R
--R
--R   (28)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 34
--S 35 of 51
c((2/3)::Float)
--R

--R
--R   (29)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 35
--S 36 of 51
c(2/3$Float)
--R
--R
--R   (30)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 36
--S 37 of 51
c((2/3)$Float)
--R
--R
--R   (31)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 37
--S 38 of 51
c(2/3@Float)
--R
--R
--R   (32)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 38
--S 39 of 51
c((2/3)@Float)
--R
--R
--RDaly Bug
--R   An expression involving @ Float actually evaluated to one of type
--R      Quaternion(Complex(Expression(Integer))) . Perhaps you should use
--R      :: Float .
--E 39

———-

Could the above problems have been avoided by not assigning types to the function we defined? Let’s repeat the entire example with this single change for the function c2

— * —

--S 40 of 51
c2(y) == cos(y)
--R
--R                                                                   Type: Void

--E 40
--S 41 of 51
c2(1.237)
--R
--R   Compiling function c2 with type Float -> Float
--R
--R   (34)  0.3276321705 9891498386
--R                                                                  Type: Float
--E 41
--S 42 of 51
c2(x)
--R
--R   There are 2 exposed and 6 unexposed library operations named cos
--R      having 1 argument(s) but none was determined to be applicable.
--R      Use HyperDoc Browse, or issue
--R                               )display op cos
--R      to learn more about the available operations. Perhaps
--R      package-calling the operation or using coercions on the arguments
--R      will allow you to apply the operation.
--R   Cannot find a definition or applicable library operation named cos
--R      with argument type(s)
--R                  Quaternion(Complex(Expression(Integer)))
--R
--R      Perhaps you should use "@" to indicate the required return type,
--R      or "$" to specify which version of the function you need.
--R   AXIOM will attempt to step through and interpret the code.
--R
--R             5
--R   (35)  cos(-)
--R             2
--R                                                    Type: Expression(Integer)
--E 42

———-

But that was only misdirection, because this breaks down for reasonable expressions — * —

--S 43 of 51
c2(1.237/2)
--R
--R   Conversion failed in the compiled user function / .
--R
--RDaly Bug
--R   Cannot convert from type Float to Quaternion(Complex(Expression(
--R      Integer))) for value
--R   1.237

--R
--E 43

———-

and various attempts at coercion also fail – compare these results to the previous ones — * —

--S 44 of 51
c2(2/3::Float)
--R
--R
--R             2
--R   (36)  cos(-)
--R             3
--R                                                    Type: Expression(Integer)
--E 44
--S 45 of 51
c2((2/3)::Float)
--R
--R
--R   (37)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 45
--S 46 of 51
c2(2/3$Float)
--R
--R
--R             2
--R   (38)  cos(-)
--R             3
--R                                                    Type: Expression(Integer)
--E 46
--S 47 of 51
c2((2/3)$Float)
--R
--R
--R   (39)  0.7858872607 7694800072
--R                                                                  Type: Float
--E 47
--S 48 of 51
c2(2/3@Float)
--R
--R
--R             2

--R   (40)  cos(-)
--R             3
--R                                                    Type: Expression(Integer)
--E 48
--S 49 of 51
c2((2/3)@Float)
--R
--R
--RDaly Bug
--R   An expression involving @ Float actually evaluated to one of type
--R      Quaternion(Complex(Expression(Integer))) . Perhaps you should use
--R      :: Float .
--E 49

———-

Lastly, we cannot now use the graph function, draw, on such a function since the wrong “/” function is used, contrary to the bypassing of internal types we saw take place with draw in the example prior to the introduction of operator overloading.

— * —

--S 50 of 51
--draw(c(x),x=0..15)
--E 50

———-

Not safe at any speed. Most oddly, the ordinary cos() function which exposes no “/” division Now fails to work with draw despite the fact that we just saw it above still working with Integer and Float arguments applied directly.

— * —

--S 51 of 51
--draw(cos(x),x=0..15)
--E 51
)spool
)lisp (bye)

———-

References^{[1] nothing}

17