Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2021-06

Option type

13 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

denisgolovan

Hi all

I am trying to implement Option<T> type in FPC.

type
  generic TOption<T> = record
    case IsSome:boolean of
    true: ( some: T );
    false: ();
  end;

However fpc just emits errors:
Error: Type parameters may require initialization/finalization - cannot be used in variant records

Could anybody suggest some sane workaround for the problem?

-- Regards,
Denis Golovan

Ryan Joseph
to denisgolovan
Show quoted text 12 lines
On Jun 1, 2021, at 12:20 PM, denisgolovan via fpc-pascal wrote: Hi all I am trying to implement Option<T> type in FPC. type generic TOption<T> = record case IsSome:boolean of true: ( some: T ); false: (); end;

You need to use a constraint like:

type
 generic TOption<T: TObject> = record
   case IsSome:boolean of
   true: ( some: T );
   false: ();
 end;

Not sure why though.

Regards,
Ryan Joseph

denisgolovan
to Ryan Joseph
Show quoted text 13 lines
You need to use a constraint like: type generic TOption<T: TObject> = record case IsSome:boolean of true: ( some: T ); false: (); end; Not sure why though. Regards, Ryan Joseph

That would limit supported types to class instances. I'll like to avoid that.
Ideally TOption type should allow any type (primitives, strings, objects, class instances, etc).

-- Regards,
Denis Golovan

Ryan Joseph
to denisgolovan
Show quoted text 5 lines
On Jun 1, 2021, at 12:56 PM, denisgolovan wrote: That would limit supported types to class instances. I'll like to avoid that. Ideally TOption type should allow any type (primitives, strings, objects, class instances, etc).

What are you trying to make that requires a variant record? I don't know what "TOption" is.

Regards,
Ryan Joseph

Виктор Матузенко
to denisgolovan: Hi all I am trying to implement Option<T> type in FPC. type generic TOption<T> = record…

Why `case`? You can make the same with a plain record:

type
  generic TOption<T> = record
    IsSome: boolean;
    some: T;
  end;

вт, 1 июн. 2021 г. в 21:26, denisgolovan via fpc-pascal <

Show quoted text 25 lines
: Hi all I am trying to implement Option<T> type in FPC. type generic TOption<T> = record case IsSome:boolean of true: ( some: T ); false: (); end; However fpc just emits errors: Error: Type parameters may require initialization/finalization - cannot be used in variant records Could anybody suggest some sane workaround for the problem? -- Regards, Denis Golovan _______________________________________________ fpc-pascal maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Victor Matuzenko (Виктор Матузенко)
Sven Barth
to denisgolovan: Hi all I am trying to implement Option<T> type in FPC. type generic TOption<T> = record…
denisgolovan wrote 13 lines
Hi all I am trying to implement Option<T> type in FPC. type generic TOption<T> = record case IsSome:boolean of true: ( some: T ); false: (); end; However fpc just emits errors: Error: Type parameters may require initialization/finalization - cannot be used in variant records

You simply can't use managed types in a variant clause and as T could be a managed type the compiler does not allow it.

Could anybody suggest some sane workaround for the problem?

Use Nullable.TNullable<T>.

Regards,
Sven

Henry Vermaak
to Ryan Joseph: What are you trying to make that requires a variant record? I don't know what "TOption"…

On Tue, 1 Jun 2021, 23:39 Ryan Joseph via fpc-pascal, <

Show quoted text 14 lines
wrote: > On Jun 1, 2021, at 12:56 PM, denisgolovan wrote: > > That would limit supported types to class instances. > I'll like to avoid that. > Ideally TOption type should allow any type (primitives, strings, objects, class instances, etc). What are you trying to make that requires a variant record? I don't know what "TOption" is.

https://en.wikipedia.org/wiki/Option_type

Henry

denisgolovan
to Sven Barth: You simply can't use managed types in a variant clause and as T could be a managed type…
You simply can't use managed types in a variant clause and as T could be a managed type the compiler does not allow it.

Well. I thought it should be precisely the case for variant clause to properly handle. Compiler knows IsSome field is used to determine if some contains initialized value.

On drop/free it would insert check:
if IsSome then finalize(some);
Use Nullable.TNullable<T>.

Thanks. It's something close to what I need.

-- Regards,
Denis Golovan

Sven Barth
to denisgolovan
denisgolovan wrote 8 lines
> You simply can't use managed types in a variant clause and as T could be > a managed type the compiler does not allow it. Well. I thought it should be precisely the case for variant clause to properly handle. Compiler knows IsSome field is used to determine if some contains initialized value. On drop/free it would insert check: if IsSome then finalize(some);

No, because to use a field is not a requirement, it can be without a name as well. Also the RTL would need to do checks each time the record is assigned to another as there could be multiple managed entries.

It's not allowed for good reason.

Regards,
Sven

Martin Frb
to Sven Barth: You simply can't use managed types in a variant clause and as T could be a managed type…
Sven Barth wrote 10 lines
Am 01.06.2021 um 20:20 schrieb denisgolovan via fpc-pascal: > > I am trying to implement Option<T> type in FPC. > > type >    generic TOption<T> = record >      case IsSome:boolean of >      true: ( some: T ); >      false: (); >    end;

Well as already discovered type like strings can not go into a "record case"

But... The above record is anyway of constant size. I.e. the memory for the field is always included, even if it is not used.

Since the "false" block is empty, you can do

type
    generic TOption<T> = record
      IsSome:boolean;
      some: T;
    end;

It is not as expressive to the reader of the code. But it leads to the same data in memory.

There is only a diff, if the other blocks of the record (the false block) also has/have data.
With case the memory will overlap.

denisgolovan
to Martin Frb
Show quoted text 15 lines
Well as already discovered type like strings can not go into a "record case" But... The above record is anyway of constant size. I.e. the memory for the field is always included, even if it is not used. Since the "false" block is empty, you can do type generic TOption<T> = record IsSome:boolean; some: T; end; It is not as expressive to the reader of the code. But it leads to the same data in memory.

Yes.
Except that "some" is still initialized with something (some default) and dropped and copied and assigned despite conceptually being empty.

-- Regards,
Denis Golovan

Sven Barth
to denisgolovan

denisgolovan via fpc-pascal schrieb am
Mi., 2. Juni 2021, 13:28:

Show quoted text 23 lines
> Well as already discovered type like strings can not go into a "record case" > > But... The above record is anyway of constant size. I.e. the memory for > the field is always included, even if it is not used. > > Since the "false" block is empty, you can do > > type > generic TOption<T> = record > IsSome:boolean; > some: T; > end; > > It is not as expressive to the reader of the code. But it leads to the > same data in memory. Yes. Except that "some" is still initialized with something (some default) and dropped and copied and assigned despite conceptually being empty.

That would have to be the case otherwise as well. And even worse: the RTL would need to decide at runtime if it would need to manage that entry. With the suggested solution (which is essentially what TNullable provides as well) this will be rather cheap if the element is Nil (aka empty) anyway.

Regards,
Sven