September 22, 2002 enum inheritance | ||||
---|---|---|---|---|
| ||||
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 |
September 23, 2002 Re: enum inheritance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | "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 |
Copyright © 1999-2021 by the D Language Foundation