Adding methods to an existing namespace

As I’m porting an existing project to Oxygene, I’m using the DelphiRTL project to avoid reinventing the wheel.
I totally understand that it’s still a work in progress, which means it lacks a few methods that my code uses, such as these:

if not System.Math.IsNaN(DoubleValue) then
  Result := System.Ln(DoubleValue);

I know how to implement IsNaN and Ln using regular CLR functions, but what I’m faced with is the way I should declare those functions so that I don’t have to change the code above.
I created a file called System.pas and placed this code inside it:

namespace System;

interface

function Ln(const X: Double): Double;

implementation

function Ln(const X: Double): Double;
begin
  result := System.Math.Log(X);
end;

end.

This made the error about missing System.Ln go away. So I went on and created a System.Math.pas file and placed this inside it

namespace System.Math;

interface

function IsNaN(d: Double): Boolean;

implementation

function IsNaN(d: Double): Boolean;
begin
  Result := Double.IsNaN(d);
end;

end.

But this did not help, I still get the following error on the if line above:

Error (E43) No static member "IsNaN" on type "Math"	

And this despite having made sure System.Math is in the uses section.

What am I missing?

The problem is that Math is a type, not a namespace. You will want to add an extension for the Math class (https://docs.elementscompiler.com/Oxygene/Types/Extensions/).

On an unrelated, I highly discourage putting anything into the System namespace as that’s reserved for, well, the system. For extending Delphi RTL, you’ll want stuff in RemObjects.Elements.RTL.Delphi and sub namespaces.

On a second unrelated note, and just FTR:

in Oxygene, filenames have no relevance for the namespace. you don’t have to name them to match (in fact I recommend against it and for all but trivial code use a one-class-per-file approach Oxygene doesn’t have any of Delphi’s limitations where stuff has to be in the same files to avoid circular referencing and the like.

Ah, that’s it! Done it, it works just fine:

namespace RemObjects.Elements.RTL.Delphi;

interface

type 
  MathExtension = public extension class (System.Math)
  public
    class method IsNaN(d: Double): Boolean; static;
  end;

implementation

class method MathExtension.IsNaN(d: Double): Boolean;
begin
  Result := Double.IsNaN(d);
end;

Ok, noted, but in the first case, because of the System prefix, I had no other choice.

As to the filenames, I speculated that it was the case, but it helps me figure out where things are.

Thanks for your help.

1 Like