Actually, FlagsAttribute can’t do more; that’s why it’s an attribute


A few years ago, Abhinaba wondered why FlagsAttribute didn't also alter the way enumeration values are auto-assigned.

Because attributes don't change the language. They are instructions to the runtime environment or (in rarer cases) to the compiler. An attribute can instruct the runtime environment to treat the function or class in a particular way. For example, you can use an attribute to tell the runtime environment that you want the program entry point to run in a single-threaded apartment, to tell the runtime environment how to look up your p/invoke function, or to tell the compiler to suppress a particular class of warnings.

But changing how values for enumerations are assigned, well that actually changes the language. An attribute can't change the operator precedence tables. An attribute can't change the way overloaded functions are resolved. An attribute can't change the statement block tokens from curly braces to square braces. An attribute can't change the IL that gets generated. The code still compiles to the same IL; the attribute just controls the execution environment, such as how the JIT compiler chooses to lay out a structure in memory.

Attribute or not, enumerations follow the same rule for automatic assignment: An enumeration symbol receives the value one greater than the previous enumeration symbol.

Comments (27)
  1. Mathieu Garstecki says:

    I find this explanation strange, I would have considered the behavior of FlagsAttribute a modification of the language, or isn’t modifying the type of operands an operator can work on a modification of its definition ?

    In fact, there already are attributes that modify the generated IL anyway, take the Conditional attribute for example.

    The behaviour wanted by Abhinaba seems more like a possible functionnality that has not been included in C#: just choose the values of your flags yourself.

    [ConditionalAttribute is the “or (in rarer cases) to the compiler”. -Raymond]
  2. Brian says:

    IANAC#P, but it seems like [Flags] does modify the compiler in some way, in that it doesn’t generate a warning if you try to OR two values together from the same enum.  I’m not quite sure how that’s different from modifying the compiler to generate different auto-assigned values.

    … unless of course the [Flags] attribute is really just adding an overloaded | operator.

  3. Sunil Joshi says:

    There’s nothing to stop someone from writing a .net language that behaves this way; doing so might even be considered sensible. So I agree with the others that the reason c# behaves this is historical. If it had occured to them in time might well have made the original specification.  

  4. Xn says:

    ConditionalAttribute does not alter the language semantics, it just excludes a piece of code from compiling (nothing more than a nobilitated #if).

    What RC was about to say is that Attributes can change compiler behavior (like #pragma warning or #if etc. in C/C++), can change interaction on reflecting code, but not change the underlying language semantics (like enum value assignments, or not raising errors for invalid code.. for example you cannot have a IKnowHowToSwitchAttribute which enables C-like switch statements because they are invalid C# code).

    What FlagsAttribute should do, is just stop the compiler to complain about perfectly valid code (logic operator usage) and help reflecting code over the type (for IntelliSense, or a smarter PropertyGrid).

  5. Gregory says:

    But some language features are implemented with help of attributes (extension methods is example).

  6. Gregory says:

    FlagsAttribute itself changes the behavior of the compiler in whether bitwise operations are allowed to be done on values of the enum type without casting to the underlying integer type.

    This is not the case, bitwise operations are allowed on any enumeration.

  7. Erzengel says:

    I’m sorry Raymond, but I completely disagree with this reasoning.

    A scripting language I maintain changes a few pieces of syntactic sugar depending on the Attributes the functions, classes, and enums particularly.

    Like you said, “They are instructions … (in rarer cases) to the compiler”. With a simple switch I can change the operator precedence table for a method or line within my compiler.

    Why doesn’t it? Because features start off not implemented. Someone has to think of the feature and implement it. That is the only reason. Attributes can change compiler behavior, the compiler I maintain does so.

    Sorry Raymond, I just don’t agree with your logic based upon empirical experience.

    [s/the compiler/the C# compiler/g. If you design your own language, you can make attributes do whatever you want. But C# prefers to segregate language from metadata. -Raymond]
  8. Timothy Fries says:

    This is not the case, bitwise operations are allowed on any enumeration.

    You’re right, I don’t know where that came from.  The other two examples still stand.

  9. Erzengel says:

    [s/the compiler/the C# compiler/g. If you design your own language, you can make attributes do whatever you want. But C# prefers to segregate language from metadata. -Raymond]

    My point is, the C# compiler CAN if it wanted to. But since the feature is not a part of the standard, it doesn’t. Not because attributes can’t do that, but because it was “decided” (probably because the decision never came up, therefore the “default” value of “not implemented” was “decided”) in the standards that it doesn’t. This is a pure design decision, or lack thereof, rather than a technical limitation of attributes. That’s just my opinion from my experience with a custom compiler.

    [Well, yeah, it could if it wanted to, but that sort of goes against the spirit of attributes. -Raymond]
  10. MadQ says:

    Actually, the FlagsAttribute does change the way the values are generated. It even causes all the correct bitmasks to be assigned!

    [Flags]

    enum Meh

    {

       One = 1,

       Two,

       TwoOrOneMask,

       Four,

       FourOrOneMask,

       FourOrTwoMask,

       FourOrTwoOrOneMask,

       Eight

    }

    But contrary to Abhinaba’s statement, we did gain a lot from the FlagsAttribute. The Enum.ToString() method and Debuggers use it to decide how to display an enum value. It aids in static analysis. It tells other developers something about the purpose of the enum type. If you’re really ambitious and have CPU cycles to spare, you can write a single method to validate values of all your enum types, taking into account whether a particular enum type has the FlagsAttribute or not.

    "Gosh, I’m smart!" – Richard Feynman

    P.S. Extra points if you can create a Feynman diagram for the Meh enum.

  11. Timothy Fries says:

    I find the explanation strange too, since like Mathieu mentioned, ConditionalAttribute is a striking counterexample — not just because it affects the resulting IL, but because it also affects the language pre-IL generation as well (it becomes a compile error to use a method with ConditionalAttribute for explicit or implicit delegate construction); which runs counter to the reasoning given for why FlagsAttribute doesn’t have the behavior described.

    ExtensionAttribute is another example of an attribute affecting the language (though in that case there’s corresponding keyword support as well).

    But both of these examples seem to me to be a valid argument for why the C# language *could* handle FlagsAttribute to alter the logic for assigning values to an enum.

    The counter-argument (which I suspect is probably closer to the actual reason) is that none of the attributes that alter language behavior were around for C# 1.0 so at the time FlagsAttribute came into being, there was no precedent for the desired behavior; and that ConditionalAttribute and ExtensionAttribute are purely additive, they change behavior explicitly in new code only and neither ever existed without its language special behavior. Changing the behavior of FlagsAttribute now would be a breaking change to a recompile of existing, unchanged code; and the C# team hates breaking changes.

  12. Don Reba says:

    If C# were to embrace the possibility of changing the language via attributes, then it would have required a full-blown metaprogramming model, like Nemerle, for instance. It would have been too bold a step for Microsoft to make.

  13. Dean Harding says:

    I don’t think it would have made sense to change the way the auto-assigned values worked. Certainly, you couldn’t really do it in the general case. For example, if they did change things to auto-increment by powers-of-two instead of by just adding 1, what would this do:

    [Flags]

    enum MyFlags

    {

     Foo = 3,

     Bar,

     FooBar,

    }

    ?

  14. steveg says:

    @Don Reba: Agreed. C# and .Net were sufficiently bold for the time. That is what you meant, wasn’t it?

  15. C# does change overload resolution based upon attributes.  In .NET 1/2/3 it changes based upon the ParamArrayAttribute.  

    In .NET 4 C# recognizes DefaultParameterValueAttribute and OptionalAttribute although I believe these are both technically pseudo-custom attributes – but ParamArrayAttribute is definitely a normal attribute which changes how the compiler behaves when calling a method.

  16. Timothy Fries says:

    > Attributes can change compiler behavior, can change interaction on reflecting code, but not change the underlying language semantics

    ExtensionAttribute changes the behavior of the compiler in choosing how to implement a callsite.

    ConditionalAttribute changes the behavior of the compiler in choosing whether to implement a callsite, and whether a line of code is valid for determining whether locals have been initialized, and whether a method is valid to use in a delegate constructor (both implicit and explicit).

    FlagsAttribute itself changes the behavior of the compiler in whether bitwise operations are allowed to be done on values of the enum type without casting to the underlying integer type.

    All three of these are behaviorial changes at the compiler level that are least similar in scope to an attribute being able to alter how the compiler assigns default values to enum fields.   The argument that it *can’t* be done because Attributes don’t affect compilation doesn’t hold water in the face of the counterexamples.

  17. ShuggyCoUk says:

    I would add that there is one attribute which unequivocally does cause different IL:

    http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimplattribute.aspx

    [MethodImpl(MethodImplOptions.Synchronized)]

    Which makes the compiler emit the required lock(this) equivalent instructions.

    Since this is something that shouldn’t be used it’s not like it’s a big deal but there you go.

    I don’t like auto assigned values much anyway since they break binary compatibility unless you always add to the end so frankly I’d prefer an attribute to say explicitly that you don’t want such behaviour…

  18. ShuggyCoUk says:

    Ignore me I tell a lie, http://blogs.msdn.com/ricom/archive/2004/05/05/126542.aspx the JIT emits the relevant instructions so I’m talking rubbish…

  19. Anonymous Coward says:

    Hm. Whether some change in behaviour is a change in the language yes or no seems a bit metaphysical to me. Main point is that the behaviour has changed; where the boundary  between the language and other aspects of the programming environment lies is more or less arbitrary. Suppose I wrote a preprocessor that would detect "import braces" in Python code and act on it? The decision to include the statement in the preprocessor or compiler as such is of course a change to the language, but suppose its presence for a moment. Would the actual usage of this import change the language? I don’t know, and frankly I don’t care. Because nothing follows from the answer to that question and thus the question is meaningless. So using "because it would change the language" as an argument doesn’t really work.

    That said, in my opinion it would have been cleaner to add a flags statement, that would check whether the contents are non-overlapping valid flags or explicitly ored from the others, etc. But that is an opinion, a design decision, whatever you want to call it. I will not pretend that I think this would be better because I think the behaviour would be a change to the language or the existing behaviour of [flags] already would be. I just think it’s cleaner because flags don’t really enumerate a set of constants and I think putting an attribute on flags to fix that is an ugly hack. But that’s just an opinion. An aesthetic decision if you will. I can’t say that it logically must be so, and neither can the designers of C#.

  20. Mihailik says:

    [Well, yeah, it could if it wanted to, but that sort of goes against the spirit of attributes. -Raymond]

    So much for writing an article then spectacularly contradicting themselves in comments :-)

    If it’s all about spirit, Raymond, you should have shed more light on spirit and bother less for IL generation.

    [I guess I didn’t make it clear. Obviously, a language can do anything it wants, but the point was that modifying the language itself based on attributes is not why attributes are there. -Raymond]
  21. Mihailik says:

    Speaking about spirit, whole idea of having FlagsAttribute was a tiny spiritual mistake.

    That’s clear in the hindsight, now point a finger at a C# developer who knows what is the actual material difference between having and not having that on a type?

    Nobody knows because nobody cares. Therefore whole discussion is a mute point, or a moo point as Joey liked to say. Certainly introducing a behaviour to never-used feature is a road to the pain land.

  22. aaron says:

    This seems to be generating a comment storm really fast.  I think this is really another case of _standard disclaimers apply_.

    For instance, multiple comments before mine point out that “An attribute can’t change the IL that gets generated” is strictly incorrect — the ConditionalAttribute changes the behavior of a method call expression in Microsoft’s C# language implementation.  

    _However_, we seem to have forgotten this blogs disclaimers:

    “Statements are not independently fact-checked. They are based on personal experience and recollection, augmented by informed guesswork”

    Occasional errors to be expected.

    [I did say “with rare exceptions”. Perhaps I should have linked to ConditionalAttribute. I still maintain that attributes should not alter the core language. Sure you can create a language where it does, but I would argue that that is an abuse of attributes, because it makes it harder to reason about code. What next [AlterOperatorPrecedenceAttribute]? -Raymond]
  23. Mihailik says:

    Raymond, that is still your mistake thinking ConditionalAttribute is a unique case.

    There are several prominent cases, ‘exceptions’ if you would.

    You’re wrong saying attributes should not affect language meaning. In fact that very purpose was intended in attributes by design, amongst several others.

    One major usage of attributes is to let language designers be more creative than underlying platform is, by injecting special meaning into compiled assemblies, recognizing it and modifying the behaviour.

    Most of non-conventional languages heavily use attributes. C# itself when implementing non-conventional (by previous standards) features often employs them too.

  24. While things like ParamArrayAttribute, ExtensionAttribute, and ConditionalAttribute may seem like they contradict this blog entry, there’s a slightly different way of looking at it. Those attributes don’t have any more power to change the language than FlagsAttribute does. All these attributes do nothing. But many compilers elect to change how they generate code in the face of these exceptional attributes.

    So it’s certainly true that the designers of the C# language could have decided to make it do something different when FlagsAttribute is present just like it does for these other attributes. But the fact would remain that FlagsAttribute does nothing. The choice here lies with the compiler writer, not the attribute author.

    And while this may seem like splitting hairs (as Anonymous Coward above seems to think, although ‘metaphysical’ seems a tad melodramatic) it highlights an important point about why you want language-altering attributes kept to a minimum. For a language-altering attribute to work consistently, it requires the compilers for every .NET language to know about and add support for that attribute, because only compilers have the power to realise the effect the attribute promises. This amounts to a tax on compiler writers, which is undesirable in a framework designed to accommodate many languages.

    Or to look at it from the response a prospective attribute author might get from compiler writers: what makes your attribute so great that every compiler vendor in the world should bend over backwards to support it?

  25. Erzengel says:

    Or to look at it from the response a prospective attribute author might get from compiler writers: what makes your attribute so great that every compiler vendor in the world should bend over backwards to support it?

    Who says that the attribute author wants that? Like I said before, I use attributes as part of the scripting language compiler I maintain (and helped develop). The attributes were authored by the same people who authored the script compiler, and that’s the only compiler that’s expected to "bend over backward to support it". It’s there only to support language features, just like ParamArray and Extension do in C#. And just like those attributes, ignoring the attributes attached by the script’s compiler (or manually attached in C#, as happens) is acceptable so long as you provide all the data.

    For example, there’s a ScriptContextAttribute that the scripting language treats similar to C#’s implicit "this" reference. The "context" keyword, when used, requires the ScriptContextAttribute be attached to the function and a Script reference be passed as the first (non-this) parameter.

    In the script, this is all done automatically. The signature looks like "void func(int i)". In C#, the function’s signature is seen as "[ScriptContext] void func(Script context, int i)". So long as you provide a meaningful Script for the context parameter, it works. You don’t have to pay attention to that attached attribute, just the function’s signiture.

    As far as I’m aware, I’m not requesting any compiler to "bend over backwards" for our attributes.  Only our own compiler has to do that.

    If we thought it necessary, I could implement Abhinaba’s [Flags] changing how enums assign incremental values in our scripting language. But it would only work in our scripting language, and would be a feature of our compiler, not of FlagsAttribute.

    The thing is, most attributes that change the language are language features in that language. You don’t apply [ParamArray] directly, instead you do "params object[] Parameters". You don’t apply [Extension], you do "this IEnumerator This". In my language, you don’t apply [ScriptContext], you just use the context keyword or a function with the ScriptContextAttribute (If you’re making a library in C# that is going to be used by my scripting language, then you’ll have to apply ScriptContextAttribute yourself when needed). If C# wanted to change the behavior of enums assigning incremental values, there should probably be a "flags" keyword you can put in front of the enum keyword, just as you can put static in front of class.

    I think that’s the point Raymond is trying to make. Sure, attributes are used by compilers to change semantics, but usually you don’t apply the attribute yourself, the compiler does. When you have to apply the attribute manually, don’t expect if to change the compiler’s behavior.

  26. streuth says:

    The only thing that matters to me is that an enum can be used as a member of a struct, in conjunction with the bitfield operator.

    Perhaps it’s scary, but it works, and helps (me at least).

    The thing for me is that if you alter the way the enum works, it has the potential to break anything that expects typical enum behaviour.

    In addition, if you want to make an enum represent flags, it’s not at all clear how the flags would auto arrange. For example, is the enumeration element "Zero" bit 0 set, or is it actually an arbitrary length word set to zero?

    The thing for me that sways this, is that if you wanted the functionality that Abhinaba was looking for, he could have a struct, and named the individual bits using the bitfield operator.

    As it stands you can do both things, albeit by a lateral method. If you change the way enum works, you risk making one of these things work no longer.

  27. streuth says:

    I possibly ought to say that I personally would like to see a "bit" type in C++. Perhaps SystemC will oblige, if I ever need it!

Comments are closed.