PhobosWatch: manifest => enum

Walter Bright newshound1 at digitalmars.com
Sat Dec 29 00:59:46 PST 2007


Don Clugston wrote:
> Walter Bright wrote:
>> Jérôme M. Berger wrote:
>>>     :(
>>
>> Yeah, I figure I'll get fricasseed over that one. The most compelling 
>> argument is that we already have 3 ways to declare a constant, adding 
>> a fourth gets very difficult to justify. As opposed to a minor 
>> extension to enums.
> 
> This statement really disturbs me, as this is clearly a major change to 
> an enum.

It doesn't change existing usage of enum.

> I think the consequences are quite horrible.
> 
> The primary function of enum is to create a TYPE based on a GROUP of 
> related INTEGRAL constants.

None of the enhancements impair this.

> You can abuse the facility to declare 
> integral constants, but that's a secondary feature at best. The problem 
> is that using enum for abtritrary types is a very poor match for the 
> primary feature of enums.
> 
> We don't want to create a type; we don't want a grouping; and the values 
> are not integral.
> 
> enum : int { A=2, B, C }
> 
> Having an enum automatically get the 'next' value is one of the key 
> feature of enums, and it relies on the base type being an enumerable 
> type.

The only thing it relies on is the ability to add 1 to the previous 
value. The new enums can automatically get the next value for any type 
with this characteristic, including UDT's that overload opAdd, as long 
as they can be evaluated at compile time.


> char [], structs, and floating-point types don't have that 
> behaviour.

You're right about char[], but structs can have that behavior, and fp 
types do. This means that:

     enum Color : string { Red="red", Blue }

would not compile, whereas:

     enum Color : string { Red="red", Blue="blue" }

would.

> You're guaranteed that integral types remain as a special case.
> 
> In another post, you mentioned that this would become allowed, to reduce 
> the effect of the special case:
> enum : float { A=2, B, C }

The above example would result in A being 2.0f, B being 3.0f, and C 
being 4.0f.

> Which leads to the same nonsense you get with operator ++ on floats; a++ 
> is not necessarily different to a. I would hope that this feature never 
> actually gets used.

You're right that, for nans, infinity, and very small values, (a+1)==a. 
But this is an inescapable of reality with fp arithmetic, and we don't 
disallow fp arithmetic because of it. We could, though, add a check that 
if the 'next' value doesn't change after being incremented, an error 
message is produced. There already is an error generated if the value 
being incremented is equal to the underlying type's .max, which prevents 
unintended overflows.

> Does this compile?
> 
> enum : cfloat { A=2, B, C }

Yes. A would be a cfloat with value 2.0+0i, B would be 3.0+0i, C would 
be 4.0+0i. There isn't a special case, all it does is:
  (next value)=(previousvalue) + 1
and run it through the usual semantic analysis. I don't know of a cause 
where one would want to declare complex constants this way, but the aim 
here is consistency.


> The important point is that you are now trying to minimise the effect of 
> the special case which has been created. But there's no way to get rid 
> of it, because it is fundamental to the nature of enums.

I don't understand exactly what the created special case is you're 
referring to. The enhanced enums remove the special case that restricted 
enums to being integral types.

> AFAICT there's also special cases related to the grouping (named vs 
> unnamed enums) and with regard to the typing (name mangling).

Anonymous enums don't have a type (and didn't in D1.0, either). There's 
no way to get a grip on such a type anyway, as it has no name and:
	enum { FOO, BAR } x;
style declarations are not allowed in D.

Let me enumerate (!) the enhancements to enum:

1) The enum 'base type' is no longer restricted to being integral types 
only.
2) Members of anonymous enums can now be of heterogeneous types, the 
types being deduced from their initializers.
3) .init, .min and .max have no meaning for anonymous enums, and so are 
computed only for tagged enums.
4) For anonymous enum members, a type can prefix the identifier as a 
convenience.
5) If there is only one member in an anonymous enum, the { } can be omitted.
6) If .init, .min, .max or 'next' values are not required, then the base 
type doesn't have to support the operations required to produce those 
values.

None of these are takeaways.



More information about the Digitalmars-d mailing list