How to handle Sets with Generics










2














I am trying to convert a set of Bytes to an enumerated set using Generics. But the code does not compile. TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType does actually correctly return the enumerated value but I cannot include this value in the enumerated set.



interface 

type TByteSet = set of Byte;
type TMyNewEnum = (meZero, meOne, meTwo);
type TMyNewEnumSet = set of TMyNewEnum;

type
TEnum<T> = class(TObject)
public
class function ToString(const aEnumValue: T): string; reintroduce;
class function FromString(const aEnumString: string; const aDefault: T): T;
class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
end

implementation
Var
MyByteSet: TMyByteSet;
MyEnumSet: TMyNewEnumSet;
...
class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
var
B: Byte;
begin
Assert(PTypeInfo(TypeInfo(T)).Kind = tkEnumeration, 'Type parameter must be an Enumeration');
for B in Value do
begin
EnumSet := EnumSet + TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType<T>; //This line does not compile
end;
end;
...



//intended Usage
MyByteSet := [0, 2];
TEnum<TMyNewEnum>.FromByteSet(MyByteSet, MyEnumSet);
//I would like MyEnumSet to contain [meZero, meTwo]

end.


Any ideas?










share|improve this question





















  • Why are you using generics if you know you want to return a TmyNewEnumSet? Then you can get rid of TValue and simply cast. So I assume this is not really what you want. You want to return a T, right? But even then, what you want can not be done in a generic way. See David's answer which tells you why. If you really want to return a TMyNewEnumSet, you can probably simply cast, i.e. EnumSet := TMyNewEnumSet(Byte(ByteSet));(untested, can't check this here).
    – Rudy Velthuis
    Nov 12 '18 at 16:36











  • What I ultimately want is to return a generic Set (in the above example the out parameter - TMyNewEnumSet) containing the individual enumerated contents. I was hoping that this interim step would lead me there.
    – gorepj01
    Nov 12 '18 at 16:49










  • My answer explains why there is no such thing as a generic set in the current Delphi language. I think we are done therefore.
    – David Heffernan
    Nov 12 '18 at 17:10










  • You could follow the example of TList<T>, which uses the new intrinsics to call the appropriate helper function, depending on T. You could simply refuse to handle anything but tkEnumeration, and if Tis a tkEnumeration, resolve this with a low level byte packing code, returning the right bit pattern. You could use untyped var or const parameters for that. Declare the "return" value as untyped out or var.
    – Rudy Velthuis
    Nov 12 '18 at 17:10
















2














I am trying to convert a set of Bytes to an enumerated set using Generics. But the code does not compile. TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType does actually correctly return the enumerated value but I cannot include this value in the enumerated set.



interface 

type TByteSet = set of Byte;
type TMyNewEnum = (meZero, meOne, meTwo);
type TMyNewEnumSet = set of TMyNewEnum;

type
TEnum<T> = class(TObject)
public
class function ToString(const aEnumValue: T): string; reintroduce;
class function FromString(const aEnumString: string; const aDefault: T): T;
class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
end

implementation
Var
MyByteSet: TMyByteSet;
MyEnumSet: TMyNewEnumSet;
...
class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
var
B: Byte;
begin
Assert(PTypeInfo(TypeInfo(T)).Kind = tkEnumeration, 'Type parameter must be an Enumeration');
for B in Value do
begin
EnumSet := EnumSet + TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType<T>; //This line does not compile
end;
end;
...



//intended Usage
MyByteSet := [0, 2];
TEnum<TMyNewEnum>.FromByteSet(MyByteSet, MyEnumSet);
//I would like MyEnumSet to contain [meZero, meTwo]

end.


Any ideas?










share|improve this question





















  • Why are you using generics if you know you want to return a TmyNewEnumSet? Then you can get rid of TValue and simply cast. So I assume this is not really what you want. You want to return a T, right? But even then, what you want can not be done in a generic way. See David's answer which tells you why. If you really want to return a TMyNewEnumSet, you can probably simply cast, i.e. EnumSet := TMyNewEnumSet(Byte(ByteSet));(untested, can't check this here).
    – Rudy Velthuis
    Nov 12 '18 at 16:36











  • What I ultimately want is to return a generic Set (in the above example the out parameter - TMyNewEnumSet) containing the individual enumerated contents. I was hoping that this interim step would lead me there.
    – gorepj01
    Nov 12 '18 at 16:49










  • My answer explains why there is no such thing as a generic set in the current Delphi language. I think we are done therefore.
    – David Heffernan
    Nov 12 '18 at 17:10










  • You could follow the example of TList<T>, which uses the new intrinsics to call the appropriate helper function, depending on T. You could simply refuse to handle anything but tkEnumeration, and if Tis a tkEnumeration, resolve this with a low level byte packing code, returning the right bit pattern. You could use untyped var or const parameters for that. Declare the "return" value as untyped out or var.
    – Rudy Velthuis
    Nov 12 '18 at 17:10














2












2








2







I am trying to convert a set of Bytes to an enumerated set using Generics. But the code does not compile. TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType does actually correctly return the enumerated value but I cannot include this value in the enumerated set.



interface 

type TByteSet = set of Byte;
type TMyNewEnum = (meZero, meOne, meTwo);
type TMyNewEnumSet = set of TMyNewEnum;

type
TEnum<T> = class(TObject)
public
class function ToString(const aEnumValue: T): string; reintroduce;
class function FromString(const aEnumString: string; const aDefault: T): T;
class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
end

implementation
Var
MyByteSet: TMyByteSet;
MyEnumSet: TMyNewEnumSet;
...
class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
var
B: Byte;
begin
Assert(PTypeInfo(TypeInfo(T)).Kind = tkEnumeration, 'Type parameter must be an Enumeration');
for B in Value do
begin
EnumSet := EnumSet + TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType<T>; //This line does not compile
end;
end;
...



//intended Usage
MyByteSet := [0, 2];
TEnum<TMyNewEnum>.FromByteSet(MyByteSet, MyEnumSet);
//I would like MyEnumSet to contain [meZero, meTwo]

end.


Any ideas?










share|improve this question













I am trying to convert a set of Bytes to an enumerated set using Generics. But the code does not compile. TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType does actually correctly return the enumerated value but I cannot include this value in the enumerated set.



interface 

type TByteSet = set of Byte;
type TMyNewEnum = (meZero, meOne, meTwo);
type TMyNewEnumSet = set of TMyNewEnum;

type
TEnum<T> = class(TObject)
public
class function ToString(const aEnumValue: T): string; reintroduce;
class function FromString(const aEnumString: string; const aDefault: T): T;
class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
end

implementation
Var
MyByteSet: TMyByteSet;
MyEnumSet: TMyNewEnumSet;
...
class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
var
B: Byte;
begin
Assert(PTypeInfo(TypeInfo(T)).Kind = tkEnumeration, 'Type parameter must be an Enumeration');
for B in Value do
begin
EnumSet := EnumSet + TValue.FromOrdinal(TypeInfo(T), Ord(B)).AsType<T>; //This line does not compile
end;
end;
...



//intended Usage
MyByteSet := [0, 2];
TEnum<TMyNewEnum>.FromByteSet(MyByteSet, MyEnumSet);
//I would like MyEnumSet to contain [meZero, meTwo]

end.


Any ideas?







delphi generics






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 12 '18 at 16:13









gorepj01

232




232











  • Why are you using generics if you know you want to return a TmyNewEnumSet? Then you can get rid of TValue and simply cast. So I assume this is not really what you want. You want to return a T, right? But even then, what you want can not be done in a generic way. See David's answer which tells you why. If you really want to return a TMyNewEnumSet, you can probably simply cast, i.e. EnumSet := TMyNewEnumSet(Byte(ByteSet));(untested, can't check this here).
    – Rudy Velthuis
    Nov 12 '18 at 16:36











  • What I ultimately want is to return a generic Set (in the above example the out parameter - TMyNewEnumSet) containing the individual enumerated contents. I was hoping that this interim step would lead me there.
    – gorepj01
    Nov 12 '18 at 16:49










  • My answer explains why there is no such thing as a generic set in the current Delphi language. I think we are done therefore.
    – David Heffernan
    Nov 12 '18 at 17:10










  • You could follow the example of TList<T>, which uses the new intrinsics to call the appropriate helper function, depending on T. You could simply refuse to handle anything but tkEnumeration, and if Tis a tkEnumeration, resolve this with a low level byte packing code, returning the right bit pattern. You could use untyped var or const parameters for that. Declare the "return" value as untyped out or var.
    – Rudy Velthuis
    Nov 12 '18 at 17:10

















  • Why are you using generics if you know you want to return a TmyNewEnumSet? Then you can get rid of TValue and simply cast. So I assume this is not really what you want. You want to return a T, right? But even then, what you want can not be done in a generic way. See David's answer which tells you why. If you really want to return a TMyNewEnumSet, you can probably simply cast, i.e. EnumSet := TMyNewEnumSet(Byte(ByteSet));(untested, can't check this here).
    – Rudy Velthuis
    Nov 12 '18 at 16:36











  • What I ultimately want is to return a generic Set (in the above example the out parameter - TMyNewEnumSet) containing the individual enumerated contents. I was hoping that this interim step would lead me there.
    – gorepj01
    Nov 12 '18 at 16:49










  • My answer explains why there is no such thing as a generic set in the current Delphi language. I think we are done therefore.
    – David Heffernan
    Nov 12 '18 at 17:10










  • You could follow the example of TList<T>, which uses the new intrinsics to call the appropriate helper function, depending on T. You could simply refuse to handle anything but tkEnumeration, and if Tis a tkEnumeration, resolve this with a low level byte packing code, returning the right bit pattern. You could use untyped var or const parameters for that. Declare the "return" value as untyped out or var.
    – Rudy Velthuis
    Nov 12 '18 at 17:10
















Why are you using generics if you know you want to return a TmyNewEnumSet? Then you can get rid of TValue and simply cast. So I assume this is not really what you want. You want to return a T, right? But even then, what you want can not be done in a generic way. See David's answer which tells you why. If you really want to return a TMyNewEnumSet, you can probably simply cast, i.e. EnumSet := TMyNewEnumSet(Byte(ByteSet));(untested, can't check this here).
– Rudy Velthuis
Nov 12 '18 at 16:36





Why are you using generics if you know you want to return a TmyNewEnumSet? Then you can get rid of TValue and simply cast. So I assume this is not really what you want. You want to return a T, right? But even then, what you want can not be done in a generic way. See David's answer which tells you why. If you really want to return a TMyNewEnumSet, you can probably simply cast, i.e. EnumSet := TMyNewEnumSet(Byte(ByteSet));(untested, can't check this here).
– Rudy Velthuis
Nov 12 '18 at 16:36













What I ultimately want is to return a generic Set (in the above example the out parameter - TMyNewEnumSet) containing the individual enumerated contents. I was hoping that this interim step would lead me there.
– gorepj01
Nov 12 '18 at 16:49




What I ultimately want is to return a generic Set (in the above example the out parameter - TMyNewEnumSet) containing the individual enumerated contents. I was hoping that this interim step would lead me there.
– gorepj01
Nov 12 '18 at 16:49












My answer explains why there is no such thing as a generic set in the current Delphi language. I think we are done therefore.
– David Heffernan
Nov 12 '18 at 17:10




My answer explains why there is no such thing as a generic set in the current Delphi language. I think we are done therefore.
– David Heffernan
Nov 12 '18 at 17:10












You could follow the example of TList<T>, which uses the new intrinsics to call the appropriate helper function, depending on T. You could simply refuse to handle anything but tkEnumeration, and if Tis a tkEnumeration, resolve this with a low level byte packing code, returning the right bit pattern. You could use untyped var or const parameters for that. Declare the "return" value as untyped out or var.
– Rudy Velthuis
Nov 12 '18 at 17:10





You could follow the example of TList<T>, which uses the new intrinsics to call the appropriate helper function, depending on T. You could simply refuse to handle anything but tkEnumeration, and if Tis a tkEnumeration, resolve this with a low level byte packing code, returning the right bit pattern. You could use untyped var or const parameters for that. Declare the "return" value as untyped out or var.
– Rudy Velthuis
Nov 12 '18 at 17:10













2 Answers
2






active

oldest

votes


















-1














You can achieve what you want quite simply, but not the way you are trying to do it (which has been pointed out by others)



If you step through the following program you will see in the debugger that MyEnumSet ends up with the desired value.



program Project3;

$APPTYPE CONSOLE

$R *.res

uses
System.SysUtils;


type TByteSet = set of Byte;
type TMyNewEnum = (meZero, meOne, meTwo);
type TMyNewEnumSet = set of TMyNewEnum;

type
TEnum<T> = class(TObject)
public
class procedure FromByteSet(const Value: TByteSet; out EnumSet: T);
end;

Var
MyByteSet: TByteSet;
MyEnumSet: TMyNewEnumSet;


procedure Test( const Parm1 : TByteSet; out Parm2 : TMyNewEnumSet );
var
iResult : TMyNewEnumSet absolute Parm1;
begin
Parm2 := iResult;
end;


TEnum<T>

class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet : T );
var
iResult : T absolute Value;
begin
EnumSet := iResult;
end;

begin
MyByteSet := [0,2];
TEnum<TMyNewEnumSet>.FromByteSet( MyByteSet, MyEnumSet);
end.


Of course, you will need to add error checking (bounds and so on) for which you can use RTTI.






share|improve this answer






























    2














    What you are attempting is not possible. For it to be possible, you would need to be able to constrain the generic type parameter to be a type over which a set can be formed. But no such generic constraint is supported by the language.



    In fact your existing code already contains the tell-tale signs of the root problem. You have:



    type
    TEnum<T> = class(TObject)
    public
    class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
    end;


    The elephant in the room here is that FromByteSet makes no reference to T and so is not generic.



    In order to make the function generic you would need something like this:



    type
    TEnum<T: record> = class(TObject)
    private
    type SetOfT = set of T;
    public
    class procedure FromByteSet(const Value: TByteSet; out EnumSet: SetOfT);
    end;


    This does not compile. The compiler objects to the type declaration with:




    [dcc32 Error]: E2001 Ordinal type required


    That's because the compiler cannot be sure that T is an ordinal type. In order for it to do so, because T is a generic type parameter, you would need there to impose a generic constraint that T was an ordinal type. But the language supports no such constraint.






    share|improve this answer






















      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53266055%2fhow-to-handle-sets-with-generics%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      -1














      You can achieve what you want quite simply, but not the way you are trying to do it (which has been pointed out by others)



      If you step through the following program you will see in the debugger that MyEnumSet ends up with the desired value.



      program Project3;

      $APPTYPE CONSOLE

      $R *.res

      uses
      System.SysUtils;


      type TByteSet = set of Byte;
      type TMyNewEnum = (meZero, meOne, meTwo);
      type TMyNewEnumSet = set of TMyNewEnum;

      type
      TEnum<T> = class(TObject)
      public
      class procedure FromByteSet(const Value: TByteSet; out EnumSet: T);
      end;

      Var
      MyByteSet: TByteSet;
      MyEnumSet: TMyNewEnumSet;


      procedure Test( const Parm1 : TByteSet; out Parm2 : TMyNewEnumSet );
      var
      iResult : TMyNewEnumSet absolute Parm1;
      begin
      Parm2 := iResult;
      end;


      TEnum<T>

      class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet : T );
      var
      iResult : T absolute Value;
      begin
      EnumSet := iResult;
      end;

      begin
      MyByteSet := [0,2];
      TEnum<TMyNewEnumSet>.FromByteSet( MyByteSet, MyEnumSet);
      end.


      Of course, you will need to add error checking (bounds and so on) for which you can use RTTI.






      share|improve this answer



























        -1














        You can achieve what you want quite simply, but not the way you are trying to do it (which has been pointed out by others)



        If you step through the following program you will see in the debugger that MyEnumSet ends up with the desired value.



        program Project3;

        $APPTYPE CONSOLE

        $R *.res

        uses
        System.SysUtils;


        type TByteSet = set of Byte;
        type TMyNewEnum = (meZero, meOne, meTwo);
        type TMyNewEnumSet = set of TMyNewEnum;

        type
        TEnum<T> = class(TObject)
        public
        class procedure FromByteSet(const Value: TByteSet; out EnumSet: T);
        end;

        Var
        MyByteSet: TByteSet;
        MyEnumSet: TMyNewEnumSet;


        procedure Test( const Parm1 : TByteSet; out Parm2 : TMyNewEnumSet );
        var
        iResult : TMyNewEnumSet absolute Parm1;
        begin
        Parm2 := iResult;
        end;


        TEnum<T>

        class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet : T );
        var
        iResult : T absolute Value;
        begin
        EnumSet := iResult;
        end;

        begin
        MyByteSet := [0,2];
        TEnum<TMyNewEnumSet>.FromByteSet( MyByteSet, MyEnumSet);
        end.


        Of course, you will need to add error checking (bounds and so on) for which you can use RTTI.






        share|improve this answer

























          -1












          -1








          -1






          You can achieve what you want quite simply, but not the way you are trying to do it (which has been pointed out by others)



          If you step through the following program you will see in the debugger that MyEnumSet ends up with the desired value.



          program Project3;

          $APPTYPE CONSOLE

          $R *.res

          uses
          System.SysUtils;


          type TByteSet = set of Byte;
          type TMyNewEnum = (meZero, meOne, meTwo);
          type TMyNewEnumSet = set of TMyNewEnum;

          type
          TEnum<T> = class(TObject)
          public
          class procedure FromByteSet(const Value: TByteSet; out EnumSet: T);
          end;

          Var
          MyByteSet: TByteSet;
          MyEnumSet: TMyNewEnumSet;


          procedure Test( const Parm1 : TByteSet; out Parm2 : TMyNewEnumSet );
          var
          iResult : TMyNewEnumSet absolute Parm1;
          begin
          Parm2 := iResult;
          end;


          TEnum<T>

          class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet : T );
          var
          iResult : T absolute Value;
          begin
          EnumSet := iResult;
          end;

          begin
          MyByteSet := [0,2];
          TEnum<TMyNewEnumSet>.FromByteSet( MyByteSet, MyEnumSet);
          end.


          Of course, you will need to add error checking (bounds and so on) for which you can use RTTI.






          share|improve this answer














          You can achieve what you want quite simply, but not the way you are trying to do it (which has been pointed out by others)



          If you step through the following program you will see in the debugger that MyEnumSet ends up with the desired value.



          program Project3;

          $APPTYPE CONSOLE

          $R *.res

          uses
          System.SysUtils;


          type TByteSet = set of Byte;
          type TMyNewEnum = (meZero, meOne, meTwo);
          type TMyNewEnumSet = set of TMyNewEnum;

          type
          TEnum<T> = class(TObject)
          public
          class procedure FromByteSet(const Value: TByteSet; out EnumSet: T);
          end;

          Var
          MyByteSet: TByteSet;
          MyEnumSet: TMyNewEnumSet;


          procedure Test( const Parm1 : TByteSet; out Parm2 : TMyNewEnumSet );
          var
          iResult : TMyNewEnumSet absolute Parm1;
          begin
          Parm2 := iResult;
          end;


          TEnum<T>

          class procedure TEnum<T>.FromByteSet(const Value: TByteSet; out EnumSet : T );
          var
          iResult : T absolute Value;
          begin
          EnumSet := iResult;
          end;

          begin
          MyByteSet := [0,2];
          TEnum<TMyNewEnumSet>.FromByteSet( MyByteSet, MyEnumSet);
          end.


          Of course, you will need to add error checking (bounds and so on) for which you can use RTTI.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 12 '18 at 19:01

























          answered Nov 12 '18 at 18:03









          Dsm

          5,1081219




          5,1081219























              2














              What you are attempting is not possible. For it to be possible, you would need to be able to constrain the generic type parameter to be a type over which a set can be formed. But no such generic constraint is supported by the language.



              In fact your existing code already contains the tell-tale signs of the root problem. You have:



              type
              TEnum<T> = class(TObject)
              public
              class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
              end;


              The elephant in the room here is that FromByteSet makes no reference to T and so is not generic.



              In order to make the function generic you would need something like this:



              type
              TEnum<T: record> = class(TObject)
              private
              type SetOfT = set of T;
              public
              class procedure FromByteSet(const Value: TByteSet; out EnumSet: SetOfT);
              end;


              This does not compile. The compiler objects to the type declaration with:




              [dcc32 Error]: E2001 Ordinal type required


              That's because the compiler cannot be sure that T is an ordinal type. In order for it to do so, because T is a generic type parameter, you would need there to impose a generic constraint that T was an ordinal type. But the language supports no such constraint.






              share|improve this answer



























                2














                What you are attempting is not possible. For it to be possible, you would need to be able to constrain the generic type parameter to be a type over which a set can be formed. But no such generic constraint is supported by the language.



                In fact your existing code already contains the tell-tale signs of the root problem. You have:



                type
                TEnum<T> = class(TObject)
                public
                class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
                end;


                The elephant in the room here is that FromByteSet makes no reference to T and so is not generic.



                In order to make the function generic you would need something like this:



                type
                TEnum<T: record> = class(TObject)
                private
                type SetOfT = set of T;
                public
                class procedure FromByteSet(const Value: TByteSet; out EnumSet: SetOfT);
                end;


                This does not compile. The compiler objects to the type declaration with:




                [dcc32 Error]: E2001 Ordinal type required


                That's because the compiler cannot be sure that T is an ordinal type. In order for it to do so, because T is a generic type parameter, you would need there to impose a generic constraint that T was an ordinal type. But the language supports no such constraint.






                share|improve this answer

























                  2












                  2








                  2






                  What you are attempting is not possible. For it to be possible, you would need to be able to constrain the generic type parameter to be a type over which a set can be formed. But no such generic constraint is supported by the language.



                  In fact your existing code already contains the tell-tale signs of the root problem. You have:



                  type
                  TEnum<T> = class(TObject)
                  public
                  class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
                  end;


                  The elephant in the room here is that FromByteSet makes no reference to T and so is not generic.



                  In order to make the function generic you would need something like this:



                  type
                  TEnum<T: record> = class(TObject)
                  private
                  type SetOfT = set of T;
                  public
                  class procedure FromByteSet(const Value: TByteSet; out EnumSet: SetOfT);
                  end;


                  This does not compile. The compiler objects to the type declaration with:




                  [dcc32 Error]: E2001 Ordinal type required


                  That's because the compiler cannot be sure that T is an ordinal type. In order for it to do so, because T is a generic type parameter, you would need there to impose a generic constraint that T was an ordinal type. But the language supports no such constraint.






                  share|improve this answer














                  What you are attempting is not possible. For it to be possible, you would need to be able to constrain the generic type parameter to be a type over which a set can be formed. But no such generic constraint is supported by the language.



                  In fact your existing code already contains the tell-tale signs of the root problem. You have:



                  type
                  TEnum<T> = class(TObject)
                  public
                  class procedure FromByteSet(const Value: TByteSet; out EnumSet: TMyNewEnumSet);
                  end;


                  The elephant in the room here is that FromByteSet makes no reference to T and so is not generic.



                  In order to make the function generic you would need something like this:



                  type
                  TEnum<T: record> = class(TObject)
                  private
                  type SetOfT = set of T;
                  public
                  class procedure FromByteSet(const Value: TByteSet; out EnumSet: SetOfT);
                  end;


                  This does not compile. The compiler objects to the type declaration with:




                  [dcc32 Error]: E2001 Ordinal type required


                  That's because the compiler cannot be sure that T is an ordinal type. In order for it to do so, because T is a generic type parameter, you would need there to impose a generic constraint that T was an ordinal type. But the language supports no such constraint.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 12 '18 at 16:30









                  Rudy Velthuis

                  24.1k43474




                  24.1k43474










                  answered Nov 12 '18 at 16:29









                  David Heffernan

                  515k348131205




                  515k348131205



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53266055%2fhow-to-handle-sets-with-generics%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      這個網誌中的熱門文章

                      Barbados

                      How to read a connectionString WITH PROVIDER in .NET Core?

                      Node.js Script on GitHub Pages or Amazon S3