I’m finally spending the time to learn Oxygene and I’m running into what is probably a failure of my expectations to match reality.
So, I want a Complex number type that would be, in memory, pretty much what it would be if I wrote it in straight pascal or C. However, I want to leverage generics to vary the storage and precision (there is a library for Quads that I might want to leverage later on). I thought it would be simple to pass either Single or Double and then do some operator overloads for the appropriate math.
However, what I’m finding is that the type does not seem to be resolved enough for the add method to compile. I did write a bit of test code which declared a few TComplex<Double>.
I tried to work it up in Delphi with similar results. Now, everyone in the Delphi discord said ‘Of course you can’t do that because it doesn’t know what the type is’ in reference to the inability for the &add overload to compile. My counter is that since I did have something that fully specified what I wanted TComplex<Double> then the compiler does have enough information. If I don’t do anything with TComplex then it should be optimized out.
I tried using a where clause, yet that seems to AND single and double rather than OR. I guess what I’m trying to do is similar to Rust’s Sum (Enum) Type.
Am I just going down a rabbit hole?
BR
namespace fail.complex;
interface
uses
RemObjects.Oxygene.System;
type
TComplex<T> = record
re: T;
im: T;
public
constructor Create;
class operator assign(var dest, src: TComplex<T>);
class operator &add(const l, r: TComplex<T>): TComplex<T>;
end;
implementation
{ TComplex<T> }
constructor TComplex<T>;
begin
re := 0; // Yeah, was wondering if it it would be fixed by bringing in a constructor....
im := 0;
end;
class operator TComplex<T>.&add(const l, r: TComplex<T>): TComplex<T>;
begin
Result.re := l.re + r.re; // Nu-uhhhh...
Result.im := l.im + r.im; // ditto
end;
class operator TComplex<T>.assign(var dest, src: TComplex<T>);
begin
dest.re := src.re;
dest.im := src.im;
end;
end.
Yeah, I’m afraid that wont work like this; the errors aer all “correct”. as rthe compiler doesnt know if T which could be anything can be assigned “0”, nt if T has a + operator.
What would happen if you declare var x: TComplex<Button>, for example?
In general, generic constraints are the rr to limit T to specific restrictions (such as implementing a specific interface). Alas, there exists noconstrait that wood help you there, as clstracints can only require to
have a actor
be a class or a record
*implement an interface
and none of those can provide the ability to assign 0 or to have a + operator.
That’s what I figured. I haven’t delved deep enough into Oxygene to determine if there is perhaps an Interface that is shared between real types exclusively. Even then its still not ideal because I cannot foresee a need for a complex number representing currency? (Maybe there is; beyond a passing familiarity with Black-Scholes, I am unfamiliar with Quantitative Finance).
My desire was to have it exist in memory as a simple structure with two fields of the same data-type. A generic record seemed perfect.
I’ve returned to finish this up. My thought was that the following would fix the issue
type
TComplex<T> = record
where T is System.Numerics.IFloatingPoint;
re: T;
im: T;
public
class operator assign(var dest, src: TComplex<T>);
class operator &add(const l, r: TComplex<T>): TComplex<T>;
end;
I know I must be looking for the snake that should have bitten me but for the life of me I’m not able to import System.Numerics.
So, taking a look at the documentation on MS learn site, it makes its first appearance in .Net 7. I assume that’s still .Net Core . The .Net Framework does not have that particular interface. I’m unsure if it has an appropriate one.