login  home  contents  what's new  discussion  bug reports help  links  subscribe  changes  refresh  edit

# Edit detail for OverloadProb revision 1 of 1

 1 Editor: Time: 2008/06/21 14:41:26 GMT-7 Note: New page which demonstrates some observations and problems with type conversion and function overloa

changed:
-

*(Found while developing Biquaternion calculus
support function collection)*

D. Cyganski - July 11-13, 2007

developing the biquaternion support function collection. I have extracted the
minimum code set to illustrate each of these herein.

**Implicit and Explicit Type Conversions**

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

The cos function will produce float outcomes for float arguments
\begin{axiom}
cos(1.237)
\end{axiom}
can handle expressions that mix floats and integers
\begin{axiom}
cos(1.237/2)
\end{axiom}
but will respect an integer expression, as we would want it too, by not evaluating
\begin{axiom}
cos(2/3)

\end{axiom}
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 constant in each expression with then results in a
proper implicit selection of which "/" definition to use:
\begin{axiom}
cos(2/3::Float)
cos((2/3)::Float)
cos(2/3$Float) cos((2/3)$Float)
cos(2/3@Float)
cos((2/3)@Float)
\end{axiom}

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
\begin{axiom}
cos(2/3)::Float
\end{axiom}

However, there is a real need for a deep coercion
operator that operates on the inner most atomic constants! Suppose we define:
\begin{axiom}
cosf(x:Expression Integer):Expression Integer == 1+cos(x/2)
\end{axiom}
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
arguments and outcomes because this results in behaviors that
preserve our representation of Integer fractions, rather than forming
approximate decimal expansions, which is perferred 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:
\begin{axiom}
cosf(2/3)
cosf((2/3)::Float)
\end{axiom}
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!
\begin{axiom}
draw(cosf(x),x=0..15)
\end{axiom}
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 = Interger/Float. Like
Maple expressions it would leave Integers as integers and floats as floats,
unmolested and treated as generic constant quantities will 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
\begin{axiom}
cos(2/3)+1.2323
\end{axiom}

In a way, Axiom already has a quantity treated like this - the constant
%pi is treated as a special float which remains unevaluated and does
not force combination of itself with an Integer and simply results
in a new kind of Integer expression of type Pi.
\begin{axiom}
3/4+%pi
\end{axiom}

Define the type Q of Hamiltonian biquaternions
\begin{axiom}
C:=Complex Expression Integer
Q:=Quaternion C
\end{axiom}
While developing the support functions, this definition of biquat division
was introduced to simplify the format of the formulae
\begin{axiom}
((x:Q)/(y:Q)):Q == x*inv(y)
\end{axiom}
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
\begin{axiom}
x:=15/6
\end{axiom}
But though the answer was right, the type is now a biquat.
If we don't notice this, and procede, some things seem still to
act normally, for example, no complaint from axiom with
\begin{axiom}
cos(x)
\end{axiom}
Of course we still get a correct answers with
\begin{axiom}
cos(1.237)
\end{axiom}
But let's try to apply this is a simple mixed float/integer function
\begin{axiom}
cos(15.457/6)
\end{axiom}
Obiously the quaternion version of "/" is being invoked despite mismatches
Well, what if we built a new cosine function that forced the form of
of the arguments into certain types to avoid the mismatch?
\begin{axiom}
c(y:Float):Float==cos(y)
\end{axiom}
At first this seems to work, we can still evaluate a float
\begin{axiom}
c(1.237)
\end{axiom}
and we can even get a float answer when we introduce the integer
coercable biquat variable value generated above!!!
\begin{axiom}
c(x)
\end{axiom}
But that was only misdirection, because this breaks down for reasonable expressions
because of the "/" operation still not being resolved correctly.
\begin{axiom}
c(1.237/2)
\end{axiom}

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 this page. Our results are mixed!
Recall that each of the following worked in the previous case, producing the correct
floating result in each case:
\begin{axiom}
cos(2/3::Float)
cos((2/3)::Float)
cos(2/3$Float) cos((2/3)$Float)
cos(2/3@Float)
cos((2/3)@Float)

\end{axiom}
Try these examples with our type constrained function, which has better luck now
\begin{axiom}
c(2/3::Float)
c((2/3)::Float)
c(2/3$Float) c((2/3)$Float)
c(2/3@Float)
c((2/3)@Float)
\end{axiom}

Could the above problems been avoided by not assigning types to the
function we defined?  Let's repeat the entire above example with this
single change for the function c2
\begin{axiom}
c2(y)==cos(y)
c2(1.237)
c2(x)
\end{axiom}
But that was only misdirection, because this breaks down for reasonable expressions
\begin{axiom}
c2(1.237/2)
\end{axiom}
and various attempts at coercion also fail-compare these results to the
previous ones
\begin{axiom}
c2(2/3::Float)
c2((2/3)::Float)
c2(2/3$Float) c2((2/3)$Float)
c2(2/3@Float)
c2((2/3)@Float)

\end{axiom}
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
\begin{axiom}
draw(c(x),x=0..15)

\end{axiom}
*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!
\begin{axiom}
draw(cos(x),x=0..15)
\end{axiom}



(Found while developing Biquaternion calculus support function collection)

D. Cyganski - July 11-13, 2007

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

Implicit and Explicit Type Conversions

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

The cos function will produce float outcomes for float arguments

fricas
cos(1.237)
 (1)
Type: Float

can handle expressions that mix floats and integers

fricas
cos(1.237/2)
 (2)
Type: Float

but will respect an integer expression, as we would want it too, by not evaluating

fricas
cos(2/3)
 (3)
Type: Expression(Integer)

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 constant in each expression with then results in a proper implicit selection of which "/" definition to use:

fricas
cos(2/3::Float)
 (4)
Type: Float
fricas
cos((2/3)::Float)
 (5)
Type: Float
fricas
cos(2/3$Float)  (6) Type: Float fricas cos((2/3)$Float)
 (7)
Type: Float
fricas
cos(2/3@Float)
 (8)
Type: Float
fricas
cos((2/3)@Float)
 (9)
Type: Float

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

fricas
cos(2/3)::Float
Cannot convert from type Expression(Integer) to Float for value
2
cos(-)
3

However, there is a real need for a deep coercion operator that operates on the inner most atomic constants! Suppose we define:

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

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 arguments and outcomes because this results in behaviors that preserve our representation of Integer fractions, rather than forming approximate decimal expansions, which is perferred 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:

fricas
cosf(2/3)
fricas
Compiling function cosf with type Expression(Integer) -> Expression(
Integer)
 (10)
Type: Expression(Integer)
fricas
cosf((2/3)::Float)
Conversion failed in the compiled user function cosf .
Cannot convert from type Float to Expression(Integer) for value
0.6666666666_6666666667

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!

fricas
draw(cosf(x),x=0..15)
fricas
Compiling function %B with type DoubleFloat -> DoubleFloat
Graph data being transmitted to the viewport manager...
FriCAS2D data being transmitted to the viewport manager...
 (11)
Type: TwoDimensionalViewport?

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 = Interger/Float. Like Maple expressions it would leave Integers as integers and floats as floats, unmolested and treated as generic constant quantities will 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

fricas
cos(2/3)+1.2323
 (12)
Type: Expression(Float)

In a way, Axiom already has a quantity treated like this - the constant %pi is treated as a special float which remains unevaluated and does not force combination of itself with an Integer and simply results in a new kind of Integer expression of type Pi.

fricas
3/4+%pi
 (13)
Type: Pi

Define the type Q of Hamiltonian biquaternions

fricas
C:=Complex Expression Integer
 (14)
Type: Type
fricas
Q:=Quaternion C
 (15)
Type: Type

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

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

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

fricas
x:=15/6
fricas
Compiling function / with type (Quaternion(Complex(Expression(
Integer))),Quaternion(Complex(Expression(Integer)))) ->
Quaternion(Complex(Expression(Integer)))
 (16)
Type: Quaternion(Complex(Expression(Integer)))

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

fricas
cos(x)
 (17)
Type: Expression(Integer)

Of course we still get a correct answers with

fricas
cos(1.237)
 (18)
Type: Float

But let's try to apply this is a simple mixed float/integer function

fricas
cos(15.457/6)
Conversion failed in the compiled user function / .
Cannot convert from type Float to Quaternion(Complex(Expression(
Integer))) for value
15.457

Obiously 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 of the arguments into certain types to avoid the mismatch?

fricas
c(y:Float):Float==cos(y)
Function declaration c : Float -> Float has been added to workspace.
Type: Void

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

fricas
c(1.237)
fricas
Compiling function c with type Float -> Float
 (19)
Type: Float

and we can even get a float answer when we introduce the integer coercable biquat variable value generated above!!!

fricas
c(x)
 (20)
Type: Float

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

fricas
c(1.237/2)
Conversion failed in the compiled user function / .
Cannot convert from type Float to Quaternion(Complex(Expression(
Integer))) for value
1.237

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 this page. Our results are mixed! Recall that each of the following worked in the previous case, producing the correct floating result in each case:

fricas
cos(2/3::Float)
 (21)
Type: Expression(Integer)
fricas
cos((2/3)::Float)
 (22)
Type: Float
fricas
cos(2/3$Float)  (23) Type: Expression(Integer) fricas cos((2/3)$Float)
 (24)
Type: Float
fricas
cos(2/3@Float)
 (25)
Type: Expression(Integer)
fricas
cos((2/3)@Float)
An expression involving @ Float actually evaluated to one of type
Quaternion(Complex(Expression(Integer))) . Perhaps you should use
:: Float .

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

fricas
c(2/3::Float)
 (26)
Type: Float
fricas
c((2/3)::Float)
 (27)
Type: Float
fricas
c(2/3$Float)  (28) Type: Float fricas c((2/3)$Float)
 (29)
Type: Float
fricas
c(2/3@Float)
 (30)
Type: Float
fricas
c((2/3)@Float)
An expression involving @ Float actually evaluated to one of type
Quaternion(Complex(Expression(Integer))) . Perhaps you should use
:: Float .

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

fricas
c2(y)==cos(y)
Type: Void
fricas
c2(1.237)
fricas
Compiling function c2 with type Float -> Float
 (31)
Type: Float
fricas
c2(x)
There are 1 exposed and 7 unexposed library operations named cos
having 1 argument(s) but none was determined to be applicable.
Use HyperDoc Browse, or issue
)display op cos
package-calling the operation or using coercions on the arguments
will allow you to apply the operation.
Cannot find a definition or applicable library operation named cos
with argument type(s)
Quaternion(Complex(Expression(Integer)))
Perhaps you should use "@" to indicate the required return type,
or "$" to specify which version of the function you need. FriCAS will attempt to step through and interpret the code.  (32) Type: Expression(Integer) But that was only misdirection, because this breaks down for reasonable expressions fricas c2(1.237/2) Conversion failed in the compiled user function / . Cannot convert from type Float to Quaternion(Complex(Expression( Integer))) for value 1.237 and various attempts at coercion also fail-compare these results to the previous ones fricas c2(2/3::Float)  (33) Type: Expression(Integer) fricas c2((2/3)::Float)  (34) Type: Float fricas c2(2/3$Float)
 (35)
Type: Expression(Integer)
fricas
c2((2/3)$Float)  (36) Type: Float fricas c2(2/3@Float)  (37) Type: Expression(Integer) fricas c2((2/3)@Float) An expression involving @ Float actually evaluated to one of type Quaternion(Complex(Expression(Integer))) . Perhaps you should use :: Float . 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 fricas draw(c(x),x=0..15) There are 9 exposed and 0 unexposed library operations named draw having 2 argument(s) but none was determined to be applicable. Use HyperDoc Browse, or issue )display op draw to learn more about the available operations. Perhaps package-calling the operation or using coercions on the arguments will allow you to apply the operation. Cannot find a definition or applicable library operation named draw with argument type(s) Float Equation(Segment(Quaternion(Complex(Expression(Integer))))) Perhaps you should use "@" to indicate the required return type, or "$" to specify which version of the function you need.

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!

fricas
draw(cos(x),x=0..15)
There are 9 exposed and 0 unexposed library operations named draw
having 2 argument(s) but none was determined to be applicable.
Use HyperDoc Browse, or issue
)display op draw
or "\$" to specify which version of the function you need.