strongly typed enum - `class` keyword optional? - c++11

In 'modern' C++ that suppports strongly typed enums: is the class keyword optional?
I saw code that defines enums like:
enum SomeEnum: unsigned int {
VAL1 = 0,
VAL2 = 1,
// ...
};
Is this a different thing, a sloppyness of the compiler (VS 2015 (MSVC 19)) or is the class keyword implicit if the enum is strongly typed?

The code in the question declares a normal unscoped enumeration, whose underlying type is however fixed. So it is different from enum class because it still does not introduce a scope for its enumerators.

Since c++11 even normal enums (which still exist) can accept an underlying type specification. See here.
enum-key attr(optional) identifier(optional) enum-base(optional)(C++11) { enumerator-list(optional) }
Emphasis mine
So it is a normal enum not a enum class but with a enum-base specification.

What you call "strongly typed enum" is really named scoped enumerations, and for those the class or struct keyword is mandatory.
Using the "inheritance" syntax is not part of scoped enumerations, they can be used for normal unscoped enumerations as well.

Related

Enums support for inheritance

I frequently come across a situation where we create a class that acts on some enumeration, but later we derive and we want to add more values to the enumeration without changing the base class.
I see this question from 2009:
Base enum class inheritance
However, I know there were a number of changes to enum in C++11, 14, 17.
Do any of those changes allow for extension of enums from base class to derived?
class Base
{
enum State {STATE_1, STATE_2, STATE_3};
};
class Derived : public Base
{
enum State {STATE_4};
};
...where we want derived to have an enumeration describing the states it can be in, which are: STATE_1, STATE_2, STATE_3, and STATE_4. We don't really want to change the enumeration in the base class, because other derived classes might not have the ability to be in STATE_4. We don't really want to create a new enumeration either, because we already have one for State in the Base.
Do we still use static const values instead in order to accomplish this 8 years later?
class Base
{
static int STATE_1= 0;
static int STATE_2= 1;
static int STATE_3= 2;
};
class Derived : public Base
{
static int STATE_4= 3;
};
No, C++ does not allow this sort of thing. Base::Color is a completely separate type from Derived::Color, with zero connection to them. This is no different from any other nested types; nested types defined in a base class are not connected to nested types defined in a derived class.
Nor can enumerations be inherited from one another.
This sort of things tends to go against good OOP practices anyway. After all, if a derived class introduces a new enumerator, how would the base class handle it? How would different derived class instances handle it?
If Base defines an operation over an enumeration, then Base defines the totality of the enumeration it operates on, and every class derived from it ought to be able to handle all of those options. Otherwise, something is very wrong with your virtual interface.
Why not just using namespaces to group enums?
namespace my_codes {
enum class color { red, green, blue } ;
enum class origin { server, client } ;
} // my_codes
Usage might be
struct my_signal {
my_codes::color flag ;
my_codes::origin source ;
} ;
But beware: "overkill is my biggest fear..." :) I would not enjoy some deep hierarchy of namespaces with enums in them and a such ...

F# Equivalent of Enum.TryParse

In C#, the following code is valid:
MyEnum myEnum = MyEnum.DEFAULT;
if (Enum.TryParse<MyEnum>(string, out myEnum))
{
Console.WriteLine("Success!");
}
So I thought I would use this in F#. Here is my attempt:
let mutable myEnum = MyEnum.DEFAULT
if Enum.TryParse<MyEnum>(string, &myEnum) then
printfn "Success!"
But it complains
a generic construct requires that the type 'MyEnum' have a default constructor
What in the world does that mean?
This is a rather unhelpful (if technically correct) message that the compiler gives you if you try to parse a discriminated union value using Enum.TryParse.
More precisely, if you look at that function, you'll see that it's parameterized with a type that's constrained to be a value type with a default constructor. DU's meet neither of this criteria - this is what the compiler complains about.
When defining an enum in F#, unlike C#, you need to explicitly give each label a value:
type MyEnum =
| Default = 0
| Custom = 1
| Fancy = 2
Skipping the values would make the compiler interpret the type as a discriminated union, which is a very different beast.

Method references to raw types harmful?

The code below contains a reference to Enum::name (notice no type parameter).
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), Enum::name);
}
public static <T, R> ColumnType<T, R> simpleColumn(BiFunction<JsonObject, String, T> readFromJson,
Function<T, R> writeToDb) {
// ...
}
Javac reports a warning during compilation:
[WARNING] found raw type: java.lang.Enum missing type arguments for
generic class java.lang.Enum
Changing the expression to Enum<T>::name causes the warning to go away.
However Idea flags the Enum<T>::name version with a warning that:
Explicit type arguments can be inferred
In turn Eclipse (ECJ) doesn't report any problems with either formulation.
Which of the three approaches is correct?
On one hand raw types are rather nasty. If you try to put some other type argument e.g. Enum<Clause>::name will cause the compilation to fails so it's some extra protection.
On the other hand the above reference is equivalent to e -> e.name() lambda, and this formulation doesn't require type arguments.
Enviorment:
Java 8u91
IDEA 15.0.3 Community
ECJ 4.5.2
There is no such thing as a “raw method reference”. Whilst raw types exist to help the migration of pre-Generics code, there can’t be any pre-Generics usage of method references, hence there is no “compatibility mode” and type inference is the norm. The Java Language Specification §15.13. Method Reference Expressions states:
If a method or constructor is generic, the appropriate type arguments may either be inferred or provided explicitly. Similarly, the type arguments of a generic type mentioned by the method reference expression may be provided explicitly or inferred.
Method reference expressions are always poly expressions
So while you may call the type before the :: a “raw type” when it referes to a generic class without specifying type arguments, the compiler will still infer the generic type signature according to the target function type. That’s why producing a warning about “raw type usage” makes no sense here.
Note that, e.g.
BiFunction<List<String>,Integer,String> f1 = List::get;
Function<Enum<Thread.State>,String> f2 = Enum::name;
can be compiled with javac without any warning (the specification names similar examples where the type should get inferred), whereas
Function<Thread.State,String> f3 = Enum::name;
generates a warning. The specification says about this case:
In the second search, if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as if it were a method invocation expression with argument expressions of types P2, ..., Pn. If ReferenceType is a raw type, and there exists a parameterization of this type, G<...>, that is a supertype of P1, the type to search is the result of capture conversion (§5.1.10) applied to G<...>;…
So in the above example, the compiler should infer Enum<Thread.State> as the parametrization of Enum that is a supertype of Thread.State to search for an appropriate method and come to the same result as for the f2 example. It somehow does work, though it generates the nonsensical raw type warning.
Since apparently, javac only generates this warning when it has to search for an appropriate supertype, there is a simple solution for your case. Just use the exact type to search:
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), T::name);
}
This compiles without any warning.

How do the different enum variants work in TypeScript?

TypeScript has a bunch of different ways to define an enum:
enum Alpha { X, Y, Z }
const enum Beta { X, Y, Z }
declare enum Gamma { X, Y, Z }
declare const enum Delta { X, Y, Z }
If I try to use a value from Gamma at runtime, I get an error because Gamma is not defined, but that's not the case for Delta or Alpha? What does const or declare mean on the declarations here?
There's also a preserveConstEnums compiler flag -- how does this interact with these?
There are four different aspects to enums in TypeScript you need to be aware of. First, some definitions:
"lookup object"
If you write this enum:
enum Foo { X, Y }
TypeScript will emit the following object:
var Foo;
(function (Foo) {
Foo[Foo["X"] = 0] = "X";
Foo[Foo["Y"] = 1] = "Y";
})(Foo || (Foo = {}));
I'll refer to this as the lookup object. Its purpose is twofold: to serve as a mapping from strings to numbers, e.g. when writing Foo.X or Foo['X'], and to serve as a mapping from numbers to strings. That reverse mapping is useful for debugging or logging purposes -- you will often have the value 0 or 1 and want to get the corresponding string "X" or "Y".
"declare" or "ambient"
In TypeScript, you can "declare" things that the compiler should know about, but not actually emit code for. This is useful when you have libraries like jQuery that define some object (e.g. $) that you want type information about, but don't need any code created by the compiler. The spec and other documentation refers to declarations made this way as being in an "ambient" context; it is important to note that all declarations in a .d.ts file are "ambient" (either requiring an explicit declare modifier or having it implicitly, depending on the declaration type).
"inlining"
For performance and code size reasons, it's often preferable to have a reference to an enum member replaced by its numeric equivalent when compiled:
enum Foo { X = 4 }
var y = Foo.X; // emits "var y = 4";
The spec calls this substitution, I will call it inlining because it sounds cooler. Sometimes you will not want enum members to be inlined, for example because the enum value might change in a future version of the API.
Enums, how do they work?
Let's break this down by each aspect of an enum. Unfortunately, each of these four sections is going to reference terms from all of the others, so you'll probably need to read this whole thing more than once.
computed vs non-computed (constant)
Enum members can either be computed or not. The spec calls non-computed members constant, but I'll call them non-computed to avoid confusion with const.
A computed enum member is one whose value is not known at compile-time. References to computed members cannot be inlined, of course. Conversely, a non-computed enum member is once whose value is known at compile-time. References to non-computed members are always inlined.
Which enum members are computed and which are non-computed? First, all members of a const enum are constant (i.e. non-computed), as the name implies. For a non-const enum, it depends on whether you're looking at an ambient (declare) enum or a non-ambient enum.
A member of a declare enum (i.e. ambient enum) is constant if and only if it has an initializer. Otherwise, it is computed. Note that in a declare enum, only numeric initializers are allowed. Example:
declare enum Foo {
X, // Computed
Y = 2, // Non-computed
Z, // Computed! Not 3! Careful!
Q = 1 + 1 // Error
}
Finally, members of non-declare non-const enums are always considered to be computed. However, their initializing expressions are reduced down to constants if they're computable at compile-time. This means non-const enum members are never inlined (this behavior changed in TypeScript 1.5, see "Changes in TypeScript" at the bottom)
const vs non-const
const
An enum declaration can have the const modifier. If an enum is const, all references to its members inlined.
const enum Foo { A = 4 }
var x = Foo.A; // emitted as "var x = 4;", always
const enums do not produce a lookup object when compiled. For this reason, it is an error to reference Foo in the above code except as part of a member reference. No Foo object will be present at runtime.
non-const
If an enum declaration does not have the const modifier, references to its members are inlined only if the member is non-computed. A non-const, non-declare enum will produce a lookup object.
declare (ambient) vs non-declare
An important preface is that declare in TypeScript has a very specific meaning: This object exists somewhere else. It's for describing existing objects. Using declare to define objects that don't actually exist can have bad consequences; we'll explore those later.
declare
A declare enum will not emit a lookup object. References to its members are inlined if those members are computed (see above on computed vs non-computed).
It's important to note that other forms of reference to a declare enum are allowed, e.g. this code is not a compile error but will fail at runtime:
// Note: Assume no other file has actually created a Foo var at runtime
declare enum Foo { Bar }
var s = 'Bar';
var b = Foo[s]; // Fails
This error falls under the category of "Don't lie to the compiler". If you don't have an object named Foo at runtime, don't write declare enum Foo!
A declare const enum is not different from a const enum, except in the case of --preserveConstEnums (see below).
non-declare
A non-declare enum produces a lookup object if it is not const. Inlining is described above.
--preserveConstEnums flag
This flag has exactly one effect: non-declare const enums will emit a lookup object. Inlining is not affected. This is useful for debugging.
Common Errors
The most common mistake is to use a declare enum when a regular enum or const enum would be more appropriate. A common form is this:
module MyModule {
// Claiming this enum exists with 'declare', but it doesn't...
export declare enum Lies {
Foo = 0,
Bar = 1
}
var x = Lies.Foo; // Depend on inlining
}
module SomeOtherCode {
// x ends up as 'undefined' at runtime
import x = MyModule.Lies;
// Try to use lookup object, which ought to exist
// runtime error, canot read property 0 of undefined
console.log(x[x.Foo]);
}
Remember the golden rule: Never declare things that don't actually exist. Use const enum if you always want inlining, or enum if you want the lookup object.
Changes in TypeScript
Between TypeScript 1.4 and 1.5, there was a change in the behavior (see https://github.com/Microsoft/TypeScript/issues/2183) to make all members of non-declare non-const enums be treated as computed, even if they're explicitly initialized with a literal. This "unsplit the baby", so to speak, making the inlining behavior more predictable and more cleanly separating the concept of const enum from regular enum. Prior to this change, non-computed members of non-const enums were inlined more aggressively.
There are a few things going on here. Let's go case by case.
enum
enum Cheese { Brie, Cheddar }
First, a plain old enum. When compiled to JavaScript, this will emit a lookup table.
The lookup table looks like this:
var Cheese;
(function (Cheese) {
Cheese[Cheese["Brie"] = 0] = "Brie";
Cheese[Cheese["Cheddar"] = 1] = "Cheddar";
})(Cheese || (Cheese = {}));
Then when you have Cheese.Brie in TypeScript, it emits Cheese.Brie in JavaScript which evaluates to 0. Cheese[0] emits Cheese[0] and actually evaluates to "Brie".
const enum
const enum Bread { Rye, Wheat }
No code is actually emitted for this! Its values are inlined. The following emit the value 0 itself in JavaScript:
Bread.Rye
Bread['Rye']
const enums' inlining might be useful for performance reasons.
But what about Bread[0]? This will error out at runtime and your compiler should catch it. There's no lookup table and the compiler doesn't inline here.
Note that in the above case, the --preserveConstEnums flag will cause Bread to emit a lookup table. Its values will still be inlined though.
declare enum
As with other uses of declare, declare emits no code and expects you to have defined the actual code elsewhere. This emits no lookup table:
declare enum Wine { Red, Wine }
Wine.Red emits Wine.Red in JavaScript, but there won't be any Wine lookup table to reference so it's an error unless you've defined it elsewhere.
declare const enum
This emits no lookup table:
declare const enum Fruit { Apple, Pear }
But it does inline! Fruit.Apple emits 0. But again Fruit[0] will error out at runtime because it's not inlined and there's no lookup table.
I've written this up in this playground. I recommend playing there to understand which TypeScript emits which JavaScript.

How to declare a value type in CIL: `.class value` or just `.class`?

I have taken a look at a C# struct FooStruct in ILDASM, and have seen the following:
ILDASM here displays two differing declarations:
one starting with .class value public (rear window & front window's title bar)
one starting with just .class public (front window)
And I wonder which syntax (if not both) is the correct one for declaring a value type? Is the value modifier strictly necessary, or optional, or a syntax error?
Short answer: Value type definitions only require extends [mscorlib]System.ValueType; the value attribute appears to be optional and has no apparent effect.
I assume that the CLI specification (ECMA-335) would be the best place to look for an authorative answer.
MUST a value type definition include the value attribute?
Section II.10 deals with defining types. More specifically, subsection II.10.1.3 states:
The type semantic attributes specify whether an interface, class, or value type shall be defined. … If [the interface] attribute is not present and the definition extends
(directly or indirectly) System.ValueType, and the definition is not for System.Enum, a value type shall be defined (§II.13). Otherwise, a class shall be defined (§II.11).
The value attribute is not mentioned at all in the whole section.
Conclusion: A correct value type definition does not have to include value. Deriving from System.ValueType is sufficient.
MAY a value type definition include the value modifier?
The CLI standard also contains a grammar for ILASM (in section VI.C.3). According to that grammar, there exists a value attribute for .class type definitions. I additionally searched the standard for concrete value type definitions and found these examples:
.class public sequential ansi serializable sealed beforefieldinit System.Double extends System.ValueType …
.class private sealed Rational extends [mscorlib]System.ValueType …
.class value sealed public MyClass extends [mscorlib]System.ValueType …
Conclusion: A value attribute may be included in a value type definition.
And what does the value attribute MEAN?
I tried to compile these three IL type definitions into an assembly:
.class public sealed … A extends [mscorlib]System.ValueType { … }
.class value public sealed … B extends [mscorlib]System.ValueType { … }
.class value public sealed … C extends [mscorlib]System.Object { … } // !!!
There was no compilation error, even though the value attribute is used in a reference type declaration (see last line). Looking at the resulting assembly using Visual Studio 2012's Object Browser reveals two value types (struct) A and B, and one reference type (class) C.
Speculation: The presence of the value attribute has no effect whatsoever on the type definition. It is only there as a potential aid for humans in spotting value type definitions.
This great book contains simple
answer: when you provide extends clause then value flag is ignored, but if you doesn't provide
extends and use value then ilasm will declare given type as value type.
In other words value was introduced as syntactic sugar, to quickly declare value type.

Resources