Jump to page: 1 2
Thread overview
Enum "Inheritance"?
Feb 23, 2011
%u
Feb 23, 2011
bearophile
Feb 23, 2011
Nick Sabalausky
Feb 24, 2011
%u
Feb 24, 2011
Kagamin
Feb 25, 2011
%u
Feb 25, 2011
Nick Sabalausky
Feb 25, 2011
Kagamin
Feb 25, 2011
%u
Feb 25, 2011
Kagamin
Feb 26, 2011
%u
Feb 27, 2011
Nick Sabalausky
Feb 27, 2011
Nick Sabalausky
Feb 27, 2011
%u
Feb 27, 2011
%u
Feb 27, 2011
spir
Feb 27, 2011
spir
February 23, 2011
I have a question on enum "inheritance" -- I'm wondering if what's happening below is a bug or by design?

I have code like this:

enum AccessMask { GenericRead = 0x80000000 }
enum FileAccess : AccessMask { ReadData = 1 } //Errors
void foo(FileAccess a) { /*Do something*/ }
void bar() { foo(AccessMask.GenericRead); } //Errors

I get two errors:

1. Inside FileAccess, I get an error with the assignment, telling me that it can't work implicitly. If instead of "ReadData = 1" I write "ReadData = cast(AccessMask)1", it works fine, but it's a pain.

2. bar() doesn't compile, because it's passing a less specialized value to a more specialized one. While I understand why this wouldn't work from an actual _object_ inheritance perspective, I don't see why this doesn't work in the case of enums -- after all, isn't the subclass supposed to contain every member member of the superclass? Is this by design, and is there a neat solution?


Thanks!
February 23, 2011
%u:

> enum AccessMask { GenericRead = 0x80000000 }
> enum FileAccess : AccessMask { ReadData = 1 } //Errors

Nice. Has Walter thought about the possibility of such D code?
Similar problems with typedef (that doesn't play well with OOP) have pushed Andrei to remove typedef from D. So be careful, or we'll lose enum too :o)

Bye,
bearophile
February 23, 2011
"%u" <wfunction@hotmail.com> wrote in message news:ik432q$29qu$1@digitalmars.com...
>I have a question on enum "inheritance" -- I'm wondering if what's happening below is a bug or by
> design?
>
> I have code like this:
>
> enum AccessMask { GenericRead = 0x80000000 }
> enum FileAccess : AccessMask { ReadData = 1 } //Errors
> void foo(FileAccess a) { /*Do something*/ }
> void bar() { foo(AccessMask.GenericRead); } //Errors
>
> I get two errors:
>
> 1. Inside FileAccess, I get an error with the assignment, telling me that
> it can't work implicitly.
> If instead of "ReadData = 1" I write "ReadData = cast(AccessMask)1", it
> works fine, but it's a pain.
>
> 2. bar() doesn't compile, because it's passing a less specialized value to
> a more specialized one.
> While I understand why this wouldn't work from an actual _object_
> inheritance perspective, I don't
> see why this doesn't work in the case of enums -- after all, isn't the
> subclass supposed to contain
> every member member of the superclass? Is this by design, and is there a
> neat solution?
>

You're misunderstanding the way enum works. The "enum A : B {}" isn't inheritence, even though the syntax is similar to class inheritence. The part after the ":" is not a parent type, but the underlying representational type.

Ie:

enum IntBased { ValueA = 1; }
enum IntBased : int { ValueA = 1; } // Same as above
enum CharBased : char {ValueA = 'x'; }
enum StringBased : string {ValueA = "hello"; } // Not sure if this actually
works
enum DoubleBased : double {ValueA = 3.14; }
// Etc...

The part after ":" just specifies what type each value is internally stored as. So when you say:

enum AccessMask { GenericRead = 0x80000000 }
enum FileAccess : AccessMask { ... }

...you've just told the compiler that each value of FileAccess is supposed to resolve to an AccessMask, not an int. But then you told it that FileAccess.ReadData is supposed to be 1, but that's impossible because 1 isn't an AccessMask, it's an int. And not only that, but it's an int that doesn't even exist in AccessMask (which is why you need that cast. Although, all that your cast is doing is forcefully creating a completely invalid AccessMask).

What you need to do is something like:

enum AccessMask { GenericRead = 0x80000000 }
enum FileAccess : AccessMask { ReadData = AccessMask.GenericRead }

or:

enum AccessMask { GenericRead = 0x80000000, ReadData = 1 } enum FileAccess : AccessMask { AccessMask.ReadData = 1 }



If neither of those are what you're after, then "enum FileAccess : AccessMask" isn't appropriate for the task anyway.



February 24, 2011
>> enum AccessMask { GenericRead = 0x80000000 }
>> enum FileAccess : AccessMask { ReadData = 1 } //Errors

> Nice. Has Walter thought about the possibility of such D code? Similar problems with typedef
(that doesn't play well with OOP) have pushed Andrei to remove typedef from D. So be careful,
or we'll lose enum too :o)

Lol, okay. Do you have any other suggestions for a better solution on how to avoid duplicating generic access masks like MAXIMUM_ALLOWED inside each access mask type?
February 24, 2011
%u Wrote:

> Lol, okay. Do you have any other suggestions for a better solution on how to avoid duplicating generic access masks like MAXIMUM_ALLOWED inside each access mask type?

You're doing it wrong. Create OO wrapper instead.
February 25, 2011
>> Lol, okay. Do you have any other suggestions for a better
solution on how to avoid duplicating generic access masks like MAXIMUM_ALLOWED inside each access mask type?

> You're doing it wrong. Create OO wrapper instead.

Hm... but:

(1) I'm not going to create a new instance of an entire class every single time I need to check an access mask, that's wasteful. When was the last time you created a "new int()" on the stack and all you did was pass the dereferenced value to a function?

(2) A singleton pattern won't really work with bitwise OR, unless I
instantiate a new access mask object at each call, in which case we
go back to point (1).

Any other ways? Or am I misunderstanding this?
February 25, 2011
"%u" <wfunction@hotmail.com> wrote in message news:ik70pq$1a37$1@digitalmars.com...
>>> Lol, okay. Do you have any other suggestions for a better
> solution on how to avoid duplicating generic access masks like MAXIMUM_ALLOWED inside each access mask type?
>
>> You're doing it wrong. Create OO wrapper instead.
>
> Hm... but:
>
> (1) I'm not going to create a new instance of an entire class every single time I need to check an access mask, that's wasteful. When was the last time you created a "new int()" on the stack and all you did was pass the dereferenced value to a function?
>
> (2) A singleton pattern won't really work with bitwise OR, unless I
> instantiate a new access mask object at each call, in which case we
> go back to point (1).
>
> Any other ways? Or am I misunderstanding this?

What exactly is it that you're trying to do?



February 25, 2011
%u Wrote:

> >> Lol, okay. Do you have any other suggestions for a better
> solution on how to avoid duplicating generic access masks like MAXIMUM_ALLOWED inside each access mask type?
> 
> > You're doing it wrong. Create OO wrapper instead.
> 
> Hm... but:
> 
> (1) I'm not going to create a new instance of an entire class every single time I need to check an access mask, that's wasteful.

I meant, you write File.open or File.isReadable which do the job for you and don't expose OS cruft.
February 25, 2011
> What exactly is it that you're trying to do?


>> (1) I'm not going to create a new instance of an entire class
every single time I need to check an access mask, that's wasteful.
> I meant, you write File.open or File.isReadable which do the job
for you and don't expose OS cruft.


That's what I'm doing! I'm precisely trying to wrap the Windows NT API, and so I'm making classes like NtObject, NtFile, NtToken, etc., to wrap functions like NtOpenFile, NtQueryObject, etc. (I'm aware that some of them are undocumented, but I live with that.)

So I have different kinds of access masks:
1. Generic access masks that can be passed to _any_ procedure and
combined with any other access masks, like GENERIC_READ,
MAXIMUM_ALLOWED, etc.
2. Object-specific access masks that can be only used for specific
objects and that can be combined with each other and with generic
access masks, like FILE_READ_DATA, TOKEN_ALL_ACCESS, etc.

So I'm trying to avoid redundant code here, because any member of an AccessMask enumeration would also be inside the FileAccess enum, the TokenAccess enum, the ThreadAccess enum, etc. But at the same time, I need to be able to pass both specific and generic access masks to functions that take in specific access masks.

So the question is, what's the best way to do it?
February 25, 2011
%u Wrote:

> So the question is, what's the best way to do it?

As long as you expose OS cruft, your wrappers are useless, I'm afraid.
I suggest you to provide safe and meaningful wrappers, e.g. streams, ranges, for concrete business cases which deal with OS directly so that the wrapper won't need flags from user (they are usually encoded in the function name) and know all necessary flags for OS call. Some flags are even win9x legacy and new code should not use them and request only needed access. For example, generic* and maximum* flags are usually never needed and their use is discouraged.
« First   ‹ Prev
1 2