Search code examples
delphipropertiesdefault-valuevariant

Can a Variant property have default value?


I've written a component who has a Variant property for which I would like to set a default value.

TMyComponent = class(TComponent)
private
  FVariantValue : Variant;
published
  property VariantValue : Variant read FVariantValue write FVariantValue default False;
end;

On compilation, I get the following error on the VariantValue property line:

E2026 Constant expression expected

Doing the same thing with a Boolean property doesn't cause any kind of error.

I read a little bit of documentation but I didn't find nothing about Variant properties default values.


Solution

  • Be careful here. The default directive does not do anything to set the value of the property itself. It only affects whether or not the value is explicitly saved in the .dfm file. If you specify a default value for a property you still have to ensure that the constructor initializes the backing field to that value.

    Properties : Storage Specifiers

    When saving a component's state, the storage specifiers of the component's published properties are checked. If a property's current value is different from its default value (or if there is no default value) and the stored specifier is True, then the property's value is saved. Otherwise, the property's value is not saved.

    Note: Property values are not automatically initialized to the default value. That is, the default directive controls only when property values are saved to the form file, but not the initial value of the property on a newly created instance.

    This is just a hint to the component streaming system that it doesn't need to store this value explicitly in the .dfm - your part of the contract is to ensure that you actually initialize the backing field to that value. The appropriate place to do this type of initialization is in the component's constructor:

    constructor TMyComponent.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FVariantValue := False;
    end;
    

    That said, False is a boolean, not a variant, so it cannot be used as a constant expression of Variant type. Since a variant is a complex type it cannot be expressed as a single constant and, therefore, cannot have a default property.

    Per Remy, if you want to ensure that the variant is not saved in the .dfm file when the backing variant is False, you can use the stored directive with a parameterless method which returns False when the variant evaluates to a boolean False. For example :

     property VariantValue : Variant read FVariantValue write FVariantValue stored IsVariantValueStored;
    

    where

    function TMyComponent.IsVariantValueStored : Boolean;
    begin
      Result := not VarIsType(FVariantValue, varBoolean);
      if not Result then
        Result := FVariantValue;
    end;