Implicit operators: how do you define them so two record types can implicitly convert between each other?

Implicit operators: how do you define them so two record types can implicitly convert between each other?

I have two record types, which each store a value in a different unit (measurement unit, not Pascal unit.) The unit needs to be "carried" with the value, but the unit can be converted changing the numerical value as it changes unit, and I'd like that conversion to be carried out on assignment of one to the other, or when one is passed into a method parameter taking the other, etc. (I could have one type which knows which unit it is, but two types is elegant especially when needing strong typing - including the unit! - for methods that expect a value in one unit or other. For the sake of this question and the problem I've got, let's assume two types.)

The problem is that you can't forward-declare records, and so I can't see how to write an implicit operator in one that knows about the second.

type
  TB = record; // illegal
  TA = record
    class operator Implicit(B : TB) : TA;
  end;
  TB = record
    class operator Implicit(A : TA) : TB; 
  end;

The closest I've got is a forward declaration of  a pointer type, eg,
type
  PB = ^TB;
  TA = record
    class operator Implicit(B : PB) : TA;
  end;
and that allows code only like so:
  B := A;
  A :=@B;// argh
whereas what I really want is
  B := A;
  A := B;

I tried defining the operators in record helpers, but that isn't supported - a real pity since that would be the perfect place to put them, and the helpers can be defined after both types are fully defined.

Any ideas?

Finally, since the value is ultimately numerical and I want to do math on it, I also want the records to convert to Double. I can't see a way to do this apart from to define the various math operators (+, -, *...) and have the operator return a Double. That doesn't help with something like Power(A, 2) though.

Comments

  1. Can't foward declare records.. I've wanted that for a long time.

    ReplyDelete
  2. Vincent Parrett I would have thought that adding support for forward references would have been a part of making them into lightweight classes.

    ReplyDelete
  3. I want aggregating records - ie light weight classes

    type
      RHeader = packed record
        Signature: Integer;
        Version: Integer;
        CRC: Cardinal;
        Size: Cardinal;
        procedure CalculateCRC;
        procedure CalculateSize; virtual;
      end;

      PBlock = ^RBlock;
      RBlock = packed record (RHeader)
         function Next:PBlock;
      end;

      PStream = ^RStream;
      RStream = packed record (RHeader)
         Count: Integer;
         Blocks : RBlock;
         function First:PBlock;
         procedure CalculateSize; override;
      end;

    and so forth...

    ReplyDelete

Post a Comment