Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign an empty set to a record using overloaded operators

I'm using a record to encapsulate two dissimular sets.
I've put in operators to allow the assignment of either set to the record. Doing so will clear the other set.
However I cannot assign an empty set.

See the following example code:

Program test;

{$Apptype console}
type
  TSomeThing = (a,b,c);
  TOtherThing = (x,y,z);
  TSomeThings = set of TSomething;
  TOtherThings = set of TOtherThing;

  TSomeRecord = record
  strict private
    Fa: TSomeThings;
    Fb: TOtherThings;
  public
    class operator Implicit(a: TSomeThings): TSomeRecord;
    class operator Implicit(a: TOtherThings): TSomeRecord;
  end;

implementation

class operator TSomeRecord.Implicit(a: TSomeThings): TSomeRecord;
begin
  Result.Fa:= a;
  Result.Fb:= [];
end;

class operator TSomeRecord.Implicit(a: TOtherThings): TSomeRecord;
begin
  Result.Fa:= [];
  Result.Fb:= a;
end;

var
  SomeRec: TSomeRecord;

begin
  SomeRec:= [];
end.

[dcc64 Error] InstructionList.pas(512): E2010 Incompatible types: 'TSomeRecord' and 'Set'

How do I make it so I can assign the empty set to my record?
I can misuse the implicit operator to allow SomeRec:= nil;, but that looks very ugly.

like image 916
Johan Avatar asked Dec 05 '25 02:12

Johan


1 Answers

The compiler cannot tell whether you mean an empty set of TSomeThing or an empty set of TOtherThing. You can declare typed constants to allow the compiler to resolve the overload:

const
  EmptySomeThings: TSomeThings = [];
  EmptyOtherThings: TOtherThings = [];

Then the following assignments compile and resolve as you would expect:

SomeRec:= EmptySomeThings;
SomeRec:= EmptyOtherThings;

Of course, you know that either one of these has the same effect, because the implementation of the Implicit operators sets one field, and clears the other. But the compiler cannot know this.

If you wish to clear both members of the record you can always use:

SomeRec:= Default(TSomeRecord);

I personally might wrap that up in a static class method like this:

class function Default: TSomeRecord; static;
....
class function TSomeRecord.Default: TSomeRecord;
begin
  Result := Default(TSomeRecord);
end;

Then you can write:

SomeRec:= TSomeRecord.Default;

In an ideal world you'd be able to declare a constant in the type, but the language designers did not think of that and it is sadly not possible.

Update

Rudy correctly points out in a comment, that constants can be added to a record type by way of a record helper. This was news to me as I mistakenly believed that helpers could only add methods. This is what I love about Stack Overflow. Even when you think you know something pretty well, there's always scope for more knowledge to be acquired. Thanks Rudy.

So you might write:

type
  TSomeRecordHelper = record helper for TSomeRecord
  public
    const
      Default: TSomeRecord = ();
  end;
like image 99
David Heffernan Avatar answered Dec 06 '25 15:12

David Heffernan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!