153

I'm always surprised that even after using C# for all this time now, I still manage to find things I didn't know about...

I've tried searching the internet for this, but using the "~" in a search isn't working for me so well and I didn't find anything on MSDN either (not to say it isn't there)

I saw this snippet of code recently, what does the tilde(~) mean?

/// <summary>
/// Enumerates the ways a customer may purchase goods.
/// </summary>
[Flags]
public enum PurchaseMethod
{   
    All = ~0,
    None =  0,
    Cash =  1,
    Check =  2,
    CreditCard =  4
}

I was a little surprised to see it so I tried to compile it, and it worked... but I still don't know what it means/does. Any help??

chue x
  • 18,573
  • 7
  • 56
  • 70
hugoware
  • 35,731
  • 24
  • 60
  • 70
  • 4
    This is an awesome and elegant solution allowing for smooth upgrading of the enum over time. Unfortunately it conflicts with CA-2217 and will throw an error if you use the code analysis :( http://msdn.microsoft.com/en-us/library/ms182335.aspx – Jason Coyne Sep 13 '12 at 14:49

10 Answers10

140

~ is the unary one's complement operator -- it flips the bits of its operand.

~0 = 0xFFFFFFFF = -1

in two's complement arithmetic, ~x == -x-1

the ~ operator can be found in pretty much any language that borrowed syntax from C, including Objective-C/C++/C#/Java/Javascript.

Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
Jimmy
  • 89,068
  • 17
  • 119
  • 137
60

I'd think that:

[Flags]
public enum PurchaseMethod
{
    None = 0,
    Cash = 1,
    Check = 2,
    CreditCard = 4,
    All = Cash | Check | CreditCard
 }

Would be a bit more clear.

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
  • 10
    It certainly is. The only good effect of the unary is that if someone adds to the enumeration, All automagically includes it. Still, the benefit doesn't outweigh the lack of clarity. – ctacke Dec 22 '08 at 21:47
  • 13
    I don't see how that's more clear. It adds either redundancy or ambiguity: does "All" mean "exactly the set of these 3" or "everything in this enum"? If I add a new value, should I also add it to All? If I see somebody else *hasn't* added a new value to All, is that intentional? ~0 is explicit. – Ken Apr 02 '09 at 18:46
  • 16
    Personal preference aside, if the meaning of ~0 was as clear to the OP as it is to you and I, he never would have posed this question in the first place. I'm not sure what that says about the clarity of one approach versus the other. – Sean Bright Apr 02 '09 at 19:36
  • 9
    Since some programmers that use C# might not yet know what << means, should we code around that, too, for more clarity? I think not. – Kurt Koller Sep 18 '12 at 22:10
  • 3
    @InsidiousForce, funny story, I read an article the other day which was advocating EXACTLY that practice for exactly that reason... – Paul Dec 19 '13 at 18:58
  • 4
    @Paul, that's kind of crazy. Let's stop using ; in English because many people don't understand its use. Or all those words they don't know. Wow, such a small set of operators, and we should dumb down our code for the people that don't know what bits are and how to manipulate them? – Kurt Koller Jan 04 '14 at 04:39
  • 1
    IMO, there is a difference between "let's stop using" and "let's use a more known alternative" – Memet Olsen Feb 23 '16 at 09:17
23
public enum PurchaseMethod
{   
    All = ~0, // all bits of All are 1. the ~ operator just inverts bits
    None =  0,
    Cash =  1,
    Check =  2,
    CreditCard =  4
}

Because of two complement in C#, ~0 == -1, the number where all bits are 1 in the binary representation.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Looks like they are creating a bit flag for the payment method: 000 = None; 001 = Cash; 010 = Check; 100 = Credit Card; 111 = All – Dillie-O Dec 22 '08 at 21:44
  • It's not two's complement, that's invert all the bits and add one, so that the two's complement of 0 is still 0. The ~0 simply inverts all the bits or one's complement. – Beardo Dec 22 '08 at 22:45
  • No, two's complement is simply inverting all the bits. – configurator Dec 22 '08 at 22:57
  • 2
    @configurator -- that's not correct. The ones complement is a simple inversion of bits. – Dave Markle Dec 22 '08 at 23:06
  • c# uses two complement to represent negative values. of course ~ is not two complement, but simply inverts all bits. i'm not sure where you got that from, Beardo – Johannes Schaub - litb Dec 22 '08 at 23:49
  • Just to clarify (for my sake). This doesn't do anything special in C# since -1 != 7, so basically you will have to end up doing [All = Cash | Check | CreditCard] ? – avgbody Jan 16 '09 at 22:16
17

Its better than the

All = Cash | Check | CreditCard

solution, because if you add another method later, say:

PayPal = 8 ,

you will be already done with the tilde-All, but have to change the all-line with the other. So its less error-prone later.

regards

blabla999
  • 3,130
  • 22
  • 24
  • It's better if you also say why it's less error-prone. Like: if you store the value in a database/binary file and then add another flag to the enumeration, it'd be included in the 'All' which means that 'All' will always mean all, and not just as long as the flags are the same :). – Aidiakapi Apr 19 '12 at 15:41
11

Just a side note, when you use

All = Cash | Check | CreditCard

you have the added benefit that Cash | Check | CreditCard would evaluate to All and not to another value (-1) that is not equal to all while containing all values. For example, if you use three check boxes in the UI

[] Cash
[] Check
[] CreditCard

and sum their values, and the user selects them all, you would see All in the resulting enum.

configurator
  • 40,828
  • 14
  • 81
  • 115
9

For others who found this question illuminating, I have a quick ~ example to share. The following snippet from the implementation of a paint method, as detailed in this Mono documentation, uses ~ to great effect:

PaintCells (clipBounds, 
    DataGridViewPaintParts.All & ~DataGridViewPaintParts.SelectionBackground);

Without the ~ operator, the code would probably look something like this:

PaintCells (clipBounds, DataGridViewPaintParts.Background 
    | DataGridViewPaintParts.Border
    | DataGridViewPaintParts.ContentBackground
    | DataGridViewPaintParts.ContentForeground
    | DataGridViewPaintParts.ErrorIcon
    | DataGridViewPaintParts.Focus);

... because the enumeration looks like this:

public enum DataGridViewPaintParts
{
    None = 0,
    Background = 1,
    Border = 2,
    ContentBackground = 4,
    ContentForeground = 8,
    ErrorIcon = 16,
    Focus = 32,
    SelectionBackground = 64,
    All = 127 // which is equal to Background | Border | ... | Focus
}

Notice this enum's similarity to Sean Bright's answer?

I think the most important take away for me is that ~ is the same operator in an enum as it is in a normal line of code.

Mike
  • 3,641
  • 3
  • 29
  • 39
5

It's a complement operator, Here is an article i often refer to for bitwise operators

http://www.blackwasp.co.uk/CSharpLogicalBitwiseOps.aspx

Also msdn uses it in their enums article which demonstrates it use better

http://msdn.microsoft.com/en-us/library/cc138362.aspx

missaghi
  • 5,044
  • 2
  • 33
  • 43
1

The alternative I personally use, which does the same thing than @Sean Bright's answer but looks better to me, is this one:

[Flags]
public enum PurchaseMethod
{
    None = 0,
    Cash = 1,
    Check = 2,
    CreditCard = 4,
    PayPal = 8,
    BitCoin = 16,
    All = Cash + Check + CreditCard + PayPal + BitCoin
}

Notice how the binary nature of those numbers, which are all powers of two, makes the following assertion true: (a + b + c) == (a | b | c). And IMHO, + looks better.

Camilo Martin
  • 37,236
  • 20
  • 111
  • 154
1

I have done some experimenting with the ~ and find it that it could have pitfalls. Consider this snippet for LINQPad which shows that the All enum value does not behave as expected when all values are ored together.

void Main()
{
    StatusFilterEnum x = StatusFilterEnum.Standard | StatusFilterEnum.Saved;
    bool isAll = (x & StatusFilterEnum.All) == StatusFilterEnum.All;
    //isAll is false but the naive user would expect true
    isAll.Dump();
}
[Flags]
public enum StatusFilterEnum {
      Standard =0,
      Saved =1,   
      All = ~0 
}
Gavin
  • 491
  • 3
  • 5
1

Each bit in [Flags] enum means something enabled (1) or disabled (0).
~ operator is used to invert all the bits of the number. Example: 00001001b turns into 11110110b.
So ~0 is used to create the value where all bits are enabled, like 11111111b for 8-bit enum.

Just want to add that for this type of enums it may be more convenient to use bitwise left shift operator, like this:

[Flags]
enum SampleEnum
{
    None   = 0,      // 0000b
    First  = 1 << 0, // 0001b
    Second = 1 << 1, // 0010b
    Third  = 1 << 2, // 0100b
    Fourth = 1 << 3, // 1000b
    All    = ~0      // 1111b
}
aluky
  • 491
  • 6
  • 11