www.digitalmars.com         C & C++   DMDScript  

D - enum inheritance

reply "Sean L. Palmer" <seanpalmer earthlink.net> writes:
We should make it so that enums by default have no operators, but you can
make an enum inherit from any other (maybe integral only?) scalar type.  How
you do the inheritance is up to you.  But what you inherit is the storage
and operators of.  This lets you then either alter the behavior of the
operators by inserting code either before or after the call to the
overridden (super) method.  Or you can add additional operators or
conversions.  That way I can say make my own int type with 8 bits (at least)
of storage and optional automatic masking to the correct range (if it's more
bits than were needed). I can define my own constants within that scope of
numbers, and the new upper and lower bound of values (min and max).  Whether
or not to clamp or saturate hopefully could be added by the end user
programmer.  If I only provide the values as public and hide the operators
you can make your own enum.

Then say you could make your own << operator for instance:

public enum d3flags : private int8
{
    macro d3flags texcoords(uint ncoords) { return (ncoords&7)<<3; } //
evaluated at compile time
    macro uint texcoords(d3flags flags) { return (flags>>3)&7; } //
evaluated at compile time
    macro d3flags operator | (d3flags x, d3flags y) { return
cast(int8)x|cast(int8)y; }
    macro d3flags operator == (d3flags x, d3flags y) { return
cast(int8)x==cast(int8)y; }
    private macro this(int8 i) { this = i; }// conversion
};
public static const d3flags
{
    position = 1<<0;
    normal  = 1<<1;
    color    = 1<<2;
    empty = 0;
}

public enum vecflags : private uint
{
    // making my own wrapping type
    macro vecflags operator ++() { return cast(int)this < cast(int)z ?
cast(int)this << 1 : x; }
    macro vecflags operator --() { return cast(int)this > cast(int)x ?
cast(int)this >> 1 : z; }
    macro vecflags operator | (vecflags x, vecflags y) { return
cast(int)x|cast(int)y; }
    none = 0;
}
public static const vecflags x = 1<<0;
public static const vecflags y = 1<<1;
public static const vecflags z = 1<<2;

Note the use of macro as kind of a "forced" inline.  It says "evaluate this
at compile time in the context of the point of call".  If everything is
compile time constant the whole thing can resolve at compile time.  That's
what I'm talking about.  And if any of it isn't constant, that part gets
done at runtime.  Maybe you can use the keyword const for this purpose,
instead of macro.

If a function returns a constant, the function *must* evaluate at compile
time, if given constant parameters.

Things like sine/cosine should be able to evaluate at compile time also, if
given constant parameters.  But I want every D programmer to have access to
be able to build types as powerful and with as good of code generation as
the builtin types.

My examples above are a bit contrived since I want to be able to make my
enums not have to be dot-qualified.  I suppose some kind of with statement
could make that tolerable.

with vecflags
    vecflags myflags = x | y | z;

I know the existing compilers can't handle any of the example code yet.

Since we're using enum as replacement for define macros in C, for int types,
why not let it provide float values too?

enum constants : extended
{
    pi = 3.1415926535897932384626433832795;
}

Sean
Sep 21 2002
parent "Sandor Hojtsy" <hojtsy index.hu> writes:
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message
news:amjfid$ck9$1 digitaldaemon.com...
 We should make it so that enums by default have no operators, but you can
 make an enum inherit from any other (maybe integral only?) scalar type.
How
 you do the inheritance is up to you.  But what you inherit is the storage
 and operators of.  This lets you then either alter the behavior of the
 operators by inserting code either before or after the call to the
 overridden (super) method.  Or you can add additional operators or
 conversions.  That way I can say make my own int type with 8 bits (at
least)
 of storage and optional automatic masking to the correct range (if it's
more
 bits than were needed). I can define my own constants within that scope of
 numbers, and the new upper and lower bound of values (min and max).
Whether
 or not to clamp or saturate hopefully could be added by the end user
 programmer.  If I only provide the values as public and hide the operators
 you can make your own enum.

 Then say you could make your own << operator for instance:

 public enum d3flags : private int8
 {
     macro d3flags texcoords(uint ncoords) { return (ncoords&7)<<3; } //
 evaluated at compile time
     macro uint texcoords(d3flags flags) { return (flags>>3)&7; } //
 evaluated at compile time
     macro d3flags operator | (d3flags x, d3flags y) { return
 cast(int8)x|cast(int8)y; }
     macro d3flags operator == (d3flags x, d3flags y) { return
 cast(int8)x==cast(int8)y; }
     private macro this(int8 i) { this = i; }// conversion
 };
 public static const d3flags
 {
     position = 1<<0;
     normal  = 1<<1;
     color    = 1<<2;
     empty = 0;
 }

 public enum vecflags : private uint
 {
     // making my own wrapping type
     macro vecflags operator ++() { return cast(int)this < cast(int)z ?
 cast(int)this << 1 : x; }
     macro vecflags operator --() { return cast(int)this > cast(int)x ?
 cast(int)this >> 1 : z; }
     macro vecflags operator | (vecflags x, vecflags y) { return
 cast(int)x|cast(int)y; }
     none = 0;
 }
 public static const vecflags x = 1<<0;
 public static const vecflags y = 1<<1;
 public static const vecflags z = 1<<2;
 Note the use of macro as kind of a "forced" inline.  It says "evaluate
this
 at compile time in the context of the point of call".  If everything is
 compile time constant the whole thing can resolve at compile time.  That's
 what I'm talking about.  And if any of it isn't constant, that part gets
 done at runtime.  Maybe you can use the keyword const for this purpose,
 instead of macro.
Why do you need a keyword for this? An optimizing compiler should inline all those functions by itself.
 If a function returns a constant, the function *must* evaluate at compile
 time, if given constant parameters.
Mhm, you mean compile-time constant parameters. Are you sure you will only pass compile-time constant parameters to these particular functions?
 Things like sine/cosine should be able to evaluate at compile time also,
if
 given constant parameters. But I want every D programmer to have access to
 be able to build types as powerful and with as good of code generation as
 the builtin types.
I agree.
 My examples above are a bit contrived since I want to be able to make my
 enums not have to be dot-qualified.  I suppose some kind of with statement
 could make that tolerable.

 with vecflags
     vecflags myflags = x | y | z;
I don't see the reason for this "with" statement here. This should work without it.
 Since we're using enum as replacement for define macros in C, for int
types,
 why not let it provide float values too?

 enum constants : extended
 {
     pi = 3.1415926535897932384626433832795;
 }
#defines are partially replaced by enums and const-s. Enum is creating a new *type*. Would you like to do this? constants c = constants.pi; extended e = cast(extended) constants.pi; No. (some implicit conversion may help, but I still think enums shouldn't have implicit conversion) So you should rather: const extended pi = 3.1415926535897932384626433832795; Or if you would like to have namespaces, emulate them: class constants { static const extended pi = 3.1415926535897932384626433832795; }; In what aspect is enum better for this purpose? Sandor
Sep 23 2002