Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-25 Thread Ondrej Pokorny via fpc-pascal

Am 23.12.2022 um 15:50 schrieb Andrew Haines via fpc-pascal:

Error: Ordinal expression expected

[TEnumAttr(['YES', 'NO', 'COULD_BE'])]


There is another (and cleaner) approach that uses an abstract attribute 
class. See attachment.


The advantage is that the compiler warns you with an error when you add 
a new value to the enum and you don't declare a string value for it.


Ondrej
program EnumAttrTest;

{$mode objfpc}{$H+}
{$modeswitch prefixedattributes}

uses
  SysUtils, TypInfo;

type
  EnumValues = class(TCustomAttribute)
  public
function OrdToStr(const aValue: Integer): string; virtual; abstract;
constructor Create;
  end;

  MyEnumValues = class(EnumValues)
  public
function OrdToStr(const aValue: Integer): string; override;
  end;

  [MyEnumValues]
  TMyEnum = (meYes, meNo, meCouldBe);

{ EnumValues }

constructor EnumValues.Create;
begin
end;

{ MyEnumValues }

function MyEnumValues.OrdToStr(const aValue: Integer): string;
const
  cValues: array[TMyEnum] of string = ('YES', 'NO', 'COULD_BE');
begin
  Result := cValues[TMyEnum(aValue)];
end;

procedure WriteAllValues(const aTypInfo: PTypeInfo);
var
  xAttrs: PAttributeTable;
  xAttr: TCustomAttribute;
  I, V: Integer;
begin
  xAttrs := GetAttributeTable(aTypInfo);
  for I := 0 to xAttrs^.AttributeCount-1 do
  begin
xAttr := GetAttribute(xAttrs, I);
try
  if xAttr is EnumValues then
  begin
for V := 0 to GetTypeData(aTypInfo)^.MaxValue do
  Writeln(EnumValues(xAttr).OrdToStr(V));
  end;
finally
  xAttr.Free;
end;
  end;
end;

begin
  WriteAllValues(PTypeInfo(TypeInfo(TMyEnum)));
  ReadLn;
end.

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Ondrej Pokorny via fpc-pascal

On 23.12.2022 15:50, Andrew Haines via fpc-pascal wrote:

On 12/23/22 5:24 AM, Ondrej Pokorny via fpc-pascal wrote:

This may be simpler:

[TEnumAttr(['YES', 'NO', 'COULD_BE'])]
  TMyEnum = (meYes, meNo, meCouldBe);

TEnumAttr = class(TCustomAttribute)
  protected
    FValues: TStringArray;
    FTypeName: String;
  public
    class function FromType(ATypeInfo: PTypeInfo): TEnumAttr;
    constructor Create(Values: array of string);

I tried that first but the compiler gave an error on the "["

Error: Ordinal expression expected

[TEnumAttr(['YES', 'NO', 'COULD_BE'])]


Indeed. I would say that is a bug and therefore I reported it:
https://gitlab.com/freepascal.org/fpc/source/-/issues/40058

I usually use the scoped enums but in case the enum values are not valid 
identifiers this is the perfect way to handle them. Therefore thanks for 
the idea :) I use attributes for various things but didn't realize this 
possibility.


Ondrej

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Michael Van Canneyt via fpc-pascal




On Fri, 23 Dec 2022, Sven Barth wrote:


Michael Van Canneyt via fpc-pascal 
schrieb am Fr., 23. Dez. 2022, 10:48:




On Fri, 23 Dec 2022, Sven Barth via fpc-pascal wrote:


Michael Van Canneyt via fpc-pascal 
schrieb am Fr., 23. Dez. 2022, 08:18:




On Thu, 22 Dec 2022, Andrew Haines via fpc-pascal wrote:


Hi what I want to do is similar to this question here:




https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/


I am going to create multiple type helpers for enums and I would like

to

look

up the helper and use common methods AsString AsOrdinal to get/set the
values. I am recieving them as json that I dont have control over. I am

using

typeinfo to fill in all the properties but I would like to convert the
strings I am receiving to the enum values semi-automatically.

LString := 'STATUS';

LHelper := GetHelper(LPropInfo^.PropType); // enum proptype


Since there can be multiple type helpers for a type, this will never be
possible. At best you would get a list.

But I don't think there is even a list of type helpers per type.
Sven will need to confirm.



As the active helper(s) for a type change(s) depending on the current

scope

(e.g. in unit A it might be a different helper than in unit B) this is

not

possible. Also helpers are not in any way usable on their own except to
retrieve their RTTI information.


But theoretically it should be possible to generate and get a list of all
defined type helpers, whether they are in scope or not ?



No, because the compiler doesn't keep track of that. It's only interested
in what is in scope *right now*.


I understand such a list is not kept now. 
That's why I said "theoretically" as in "it is possible to add to the compiler"


To be clear:
I don't think you should add such a list, I'm simply interested in the possibility 
of such a thing.


Michael.
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Andrew Haines via fpc-pascal


On 12/23/22 5:24 AM, Ondrej Pokorny via fpc-pascal wrote:

This may be simpler:

[TEnumAttr(['YES', 'NO', 'COULD_BE'])]
  TMyEnum = (meYes, meNo, meCouldBe);

TEnumAttr = class(TCustomAttribute)
  protected
    FValues: TStringArray;
    FTypeName: String;
  public
    class function FromType(ATypeInfo: PTypeInfo): TEnumAttr;
    constructor Create(Values: array of string);

---



I tried that first but the compiler gave an error on the "["

Error: Ordinal expression expected

[TEnumAttr(['YES', 'NO', 'COULD_BE'])]



Or, if the enum values are valid identifiers, you can simple use 
scoped enums:


{$SCOPEDENUMS ON}
  TMyEnum = (YES, NO, COULD_BE);

and the usual TypeInfo methods.

Ondrej



I didn't know about those, that could also be a good solution, thanks!

Andrew

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Sven Barth via fpc-pascal
Michael Van Canneyt via fpc-pascal 
schrieb am Fr., 23. Dez. 2022, 10:48:

>
>
> On Fri, 23 Dec 2022, Sven Barth via fpc-pascal wrote:
>
> > Michael Van Canneyt via fpc-pascal 
> > schrieb am Fr., 23. Dez. 2022, 08:18:
> >
> >>
> >>
> >> On Thu, 22 Dec 2022, Andrew Haines via fpc-pascal wrote:
> >>
> >>> Hi what I want to do is similar to this question here:
> >>>
> >>
> https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/
> >>>
> >>> I am going to create multiple type helpers for enums and I would like
> to
> >> look
> >>> up the helper and use common methods AsString AsOrdinal to get/set the
> >>> values. I am recieving them as json that I dont have control over. I am
> >> using
> >>> typeinfo to fill in all the properties but I would like to convert the
> >>> strings I am receiving to the enum values semi-automatically.
> >>>
> >>> LString := 'STATUS';
> >>>
> >>> LHelper := GetHelper(LPropInfo^.PropType); // enum proptype
> >>
> >> Since there can be multiple type helpers for a type, this will never be
> >> possible. At best you would get a list.
> >>
> >> But I don't think there is even a list of type helpers per type.
> >> Sven will need to confirm.
> >>
> >
> > As the active helper(s) for a type change(s) depending on the current
> scope
> > (e.g. in unit A it might be a different helper than in unit B) this is
> not
> > possible. Also helpers are not in any way usable on their own except to
> > retrieve their RTTI information.
>
> But theoretically it should be possible to generate and get a list of all
> defined type helpers, whether they are in scope or not ?
>

No, because the compiler doesn't keep track of that. It's only interested
in what is in scope *right now*.


> If their RTTI could include a function that returns an interface, you could
> retrieve that and do as the OP suggests..
>

Don't make helpers to something that they're simply not there for.

Regards,
Sven
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Ondrej Pokorny via fpc-pascal

This may be simpler:

[TEnumAttr(['YES', 'NO', 'COULD_BE'])]
  TMyEnum = (meYes, meNo, meCouldBe);

TEnumAttr = class(TCustomAttribute)
  protected
    FValues: TStringArray;
    FTypeName: String;
  public
    class function FromType(ATypeInfo: PTypeInfo): TEnumAttr;
    constructor Create(Values: array of string);

---

Or, if the enum values are valid identifiers, you can simple use scoped 
enums:


{$SCOPEDENUMS ON}
  TMyEnum = (YES, NO, COULD_BE);

and the usual TypeInfo methods.

Ondrej


On 23.12.2022 06:35, Andrew Haines via fpc-pascal wrote:

So, I came up with a solution using Custom Attributes.

I can declare this:

[TEnumAttr('YES', 'NO', 'COULD_BE')]
  TMyEnum = (meYes, meNo, meCouldBe);

and at runtime look for the TEnumAttr attribute and use that.


TEnumAttr = class(TCustomAttribute)
  protected
    FValues: TStringArray;
    FTypeName: String;
  public
    class function FromType(ATypeInfo: PTypeInfo): TEnumAttr;
    constructor Create(Val1: String);
    constructor Create(Val1, Val2: String);

etc

Maybe this can help someone else with a similar use case.


Regards,

Andrew Haines

On 12/22/22 8:40 PM, Andrew Haines via fpc-pascal wrote:
Hi what I want to do is similar to this question here: 
https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/


I am going to create multiple type helpers for enums and I would like 
to look up the helper and use common methods AsString AsOrdinal to 
get/set the values. I am recieving them as json that I dont have 
control over. I am using typeinfo to fill in all the properties but I 
would like to convert the strings I am receiving to the enum values 
semi-automatically.


LString := 'STATUS';

LHelper := GetHelper(LPropInfo^.PropType); // enum proptype

LToStringInterface := LHelper as IToStringInterface;

SetOrdProp(LObject, 'propname', LToStringInterface.OrdValue(LString);


Something like that. I'm not sure if it's even possible to find the 
helper type with typeinfo.


Thanks for your suggestions :)

Regards,

Andrew

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Michael Van Canneyt via fpc-pascal




On Fri, 23 Dec 2022, Sven Barth via fpc-pascal wrote:


Michael Van Canneyt via fpc-pascal 
schrieb am Fr., 23. Dez. 2022, 08:18:




On Thu, 22 Dec 2022, Andrew Haines via fpc-pascal wrote:


Hi what I want to do is similar to this question here:


https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/


I am going to create multiple type helpers for enums and I would like to

look

up the helper and use common methods AsString AsOrdinal to get/set the
values. I am recieving them as json that I dont have control over. I am

using

typeinfo to fill in all the properties but I would like to convert the
strings I am receiving to the enum values semi-automatically.

LString := 'STATUS';

LHelper := GetHelper(LPropInfo^.PropType); // enum proptype


Since there can be multiple type helpers for a type, this will never be
possible. At best you would get a list.

But I don't think there is even a list of type helpers per type.
Sven will need to confirm.



As the active helper(s) for a type change(s) depending on the current scope
(e.g. in unit A it might be a different helper than in unit B) this is not
possible. Also helpers are not in any way usable on their own except to
retrieve their RTTI information.


But theoretically it should be possible to generate and get a list of all 
defined type helpers, whether they are in scope or not ?


If their RTTI could include a function that returns an interface, you could
retrieve that and do as the OP suggests...

I think the OP's solution with attributes is the same as the one TMS Software's
Aurelius ORM uses.

Michael.
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-23 Thread Sven Barth via fpc-pascal
Michael Van Canneyt via fpc-pascal 
schrieb am Fr., 23. Dez. 2022, 08:18:

>
>
> On Thu, 22 Dec 2022, Andrew Haines via fpc-pascal wrote:
>
> > Hi what I want to do is similar to this question here:
> >
> https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/
> >
> > I am going to create multiple type helpers for enums and I would like to
> look
> > up the helper and use common methods AsString AsOrdinal to get/set the
> > values. I am recieving them as json that I dont have control over. I am
> using
> > typeinfo to fill in all the properties but I would like to convert the
> > strings I am receiving to the enum values semi-automatically.
> >
> > LString := 'STATUS';
> >
> > LHelper := GetHelper(LPropInfo^.PropType); // enum proptype
>
> Since there can be multiple type helpers for a type, this will never be
> possible. At best you would get a list.
>
> But I don't think there is even a list of type helpers per type.
> Sven will need to confirm.
>

As the active helper(s) for a type change(s) depending on the current scope
(e.g. in unit A it might be a different helper than in unit B) this is not
possible. Also helpers are not in any way usable on their own except to
retrieve their RTTI information.

Regards,
Sven
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-22 Thread Michael Van Canneyt via fpc-pascal




On Thu, 22 Dec 2022, Andrew Haines via fpc-pascal wrote:

Hi what I want to do is similar to this question here: 
https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/


I am going to create multiple type helpers for enums and I would like to look 
up the helper and use common methods AsString AsOrdinal to get/set the 
values. I am recieving them as json that I dont have control over. I am using 
typeinfo to fill in all the properties but I would like to convert the 
strings I am receiving to the enum values semi-automatically.


LString := 'STATUS';

LHelper := GetHelper(LPropInfo^.PropType); // enum proptype


Since there can be multiple type helpers for a type, this will never be
possible. At best you would get a list.

But I don't think there is even a list of type helpers per type.
Sven will need to confirm.

In your case, I would simply register a function that does this for each
known enum type.

Michael.

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-22 Thread Andrew Haines via fpc-pascal

So, I came up with a solution using Custom Attributes.

I can declare this:

[TEnumAttr('YES', 'NO', 'COULD_BE')]
  TMyEnum = (meYes, meNo, meCouldBe);

and at runtime look for the TEnumAttr attribute and use that.


TEnumAttr = class(TCustomAttribute)
  protected
    FValues: TStringArray;
    FTypeName: String;
  public
    class function FromType(ATypeInfo: PTypeInfo): TEnumAttr;
    constructor Create(Val1: String);
    constructor Create(Val1, Val2: String);

etc

Maybe this can help someone else with a similar use case.


Regards,

Andrew Haines

On 12/22/22 8:40 PM, Andrew Haines via fpc-pascal wrote:
Hi what I want to do is similar to this question here: 
https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/


I am going to create multiple type helpers for enums and I would like 
to look up the helper and use common methods AsString AsOrdinal to 
get/set the values. I am recieving them as json that I dont have 
control over. I am using typeinfo to fill in all the properties but I 
would like to convert the strings I am receiving to the enum values 
semi-automatically.


LString := 'STATUS';

LHelper := GetHelper(LPropInfo^.PropType); // enum proptype

LToStringInterface := LHelper as IToStringInterface;

SetOrdProp(LObject, 'propname', LToStringInterface.OrdValue(LString);


Something like that. I'm not sure if it's even possible to find the 
helper type with typeinfo.


Thanks for your suggestions :)

Regards,

Andrew

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


[fpc-pascal] Unrelated type helpers with the same members? Implement an interface with a type helper?

2022-12-22 Thread Andrew Haines via fpc-pascal
Hi what I want to do is similar to this question here: 
https://en.delphipraxis.net/topic/423-rtti-determine-record-helper-type-for-a-base-type/


I am going to create multiple type helpers for enums and I would like to 
look up the helper and use common methods AsString AsOrdinal to get/set 
the values. I am recieving them as json that I dont have control over. I 
am using typeinfo to fill in all the properties but I would like to 
convert the strings I am receiving to the enum values semi-automatically.


LString := 'STATUS';

LHelper := GetHelper(LPropInfo^.PropType); // enum proptype

LToStringInterface := LHelper as IToStringInterface;

SetOrdProp(LObject, 'propname', LToStringInterface.OrdValue(LString);


Something like that. I'm not sure if it's even possible to find the 
helper type with typeinfo.


Thanks for your suggestions :)

Regards,

Andrew

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal