How to handle Sets with Generics
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
add a comment |
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
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 ofTList<T>
, which uses the new intrinsics to call the appropriate helper function, depending onT
. You could simply refuse to handle anything buttkEnumeration
, and ifT
is atkEnumeration
, 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
add a comment |
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
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
delphi generics
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 ofTList<T>
, which uses the new intrinsics to call the appropriate helper function, depending onT
. You could simply refuse to handle anything buttkEnumeration
, and ifT
is atkEnumeration
, 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
add a comment |
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 ofTList<T>
, which uses the new intrinsics to call the appropriate helper function, depending onT
. You could simply refuse to handle anything buttkEnumeration
, and ifT
is atkEnumeration
, 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 T
is 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 T
is 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
add a comment |
2 Answers
2
active
oldest
votes
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.
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
add a comment |
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.
add a comment |
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.
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.
edited Nov 12 '18 at 19:01
answered Nov 12 '18 at 18:03
Dsm
5,1081219
5,1081219
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
edited Nov 12 '18 at 16:30
Rudy Velthuis
24.1k43474
24.1k43474
answered Nov 12 '18 at 16:29
David Heffernan
515k348131205
515k348131205
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 onT
. You could simply refuse to handle anything buttkEnumeration
, and ifT
is atkEnumeration
, 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