New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Binary literals #215

Closed
MadsTorgersen opened this Issue Feb 3, 2015 · 40 comments

Comments

@MadsTorgersen
Contributor

MadsTorgersen commented Feb 3, 2015

There’s a relatively common request to add binary literals to C# and VB. For bitmasks (e.g. flag enums) this seems genuinely useful, but it would also be great just for educational purposes.

Binary literals would look like this:

int nineteen = 0b10011;

Syntactically and semantically they are identical to hexadecimal literals, except for using b/B instead of x/X, having only digits 0 and 1 and being interpreted in base 2 instead of 16.

There’s little cost to implementing these, and little conceptual overhead to users of the language.

Syntax

The grammar would be as follows:

integer-literal:
  ...
binary-integer-literal

binary-integer-literal:
0bbinary-digitsinteger-type-suffixopt
0Bbinary-digitsinteger-type-suffixopt

binary-digits:
binary-digit
binary-digitsbinary-digit

binary-digit:   one of
0 1

@monoman

This comment has been minimized.

Show comment
Hide comment
@monoman

monoman commented Feb 4, 2015

👍

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Feb 4, 2015

Contributor

A think a digit separator would also help. _
0b_10000000_00000000_00000000_0000_0000

Contributor

AdamSpeight2008 commented Feb 4, 2015

A think a digit separator would also help. _
0b_10000000_00000000_00000000_0000_0000

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 4, 2015

Contributor

👍

Contributor

SirCmpwn commented Feb 4, 2015

👍

@alanfo

This comment has been minimized.

Show comment
Hide comment
@alanfo

alanfo Feb 5, 2015

Good idea and, whilst you're at it, why don't you add octal literals as well?

VB and F# already support these which are still occasionally useful when doing interop with older unmanaged code or translating it to C#.

Perhaps a prefix of '0o' or '0O' followed by the octal digits would be a suitable syntax as this is what F# and Swift use.

alanfo commented Feb 5, 2015

Good idea and, whilst you're at it, why don't you add octal literals as well?

VB and F# already support these which are still occasionally useful when doing interop with older unmanaged code or translating it to C#.

Perhaps a prefix of '0o' or '0O' followed by the octal digits would be a suitable syntax as this is what F# and Swift use.

@tmat

This comment has been minimized.

Show comment
Hide comment
@tmat

tmat Feb 6, 2015

Member

@alanfo I don't think we should add new features like octal literals to C# whose only benefit is to make somewhat convenient to deal with legacy code.

Member

tmat commented Feb 6, 2015

@alanfo I don't think we should add new features like octal literals to C# whose only benefit is to make somewhat convenient to deal with legacy code.

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 6, 2015

Contributor

That's not the only benefit. I would benefit from this in several modern projects. Anything that uses bitwise math stands to gain a lot from binary literals. Here are a couple of examples:

Contributor

SirCmpwn commented Feb 6, 2015

That's not the only benefit. I would benefit from this in several modern projects. Anything that uses bitwise math stands to gain a lot from binary literals. Here are a couple of examples:

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 6, 2015

Contributor

Mask out the lower five bits - & 0xE0 or & 0b11100000?

Contributor

SirCmpwn commented Feb 6, 2015

Mask out the lower five bits - & 0xE0 or & 0b11100000?

@tmat

This comment has been minimized.

Show comment
Hide comment
@tmat

tmat Feb 6, 2015

Member

@SirCmpwn I meant octal, not binary. Binary literals are certainly useful. My comment perhaps wasn't clear.

Member

tmat commented Feb 6, 2015

@SirCmpwn I meant octal, not binary. Binary literals are certainly useful. My comment perhaps wasn't clear.

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 6, 2015

Contributor

@tmat no worries. An obvious use case that comes to mind for octal is Unix file permissions.

Contributor

SirCmpwn commented Feb 6, 2015

@tmat no worries. An obvious use case that comes to mind for octal is Unix file permissions.

@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado Feb 6, 2015

@tmat, @SirCmpwn and since that's where C# is heading hard and heavy now, it might make sense to consider the effort of introducing octal numbers.

paulomorgado commented Feb 6, 2015

@tmat, @SirCmpwn and since that's where C# is heading hard and heavy now, it might make sense to consider the effort of introducing octal numbers.

@tmat

This comment has been minimized.

Show comment
Hide comment
@tmat

tmat Feb 6, 2015

Member

@SirCmpwn @paulomorgado Could you give an example of source code that would need to specify permissions in octal?

I would rather specify them using
[Flags]enum Permission { None = 0, Execute = 1, Write = 2, Read = 4}

and then new FilePermission(owner: Permission.Read | Permission.Write, group: Permission.Read, all: Permission.None)

I don't see how I would use octal numbers, other then to obfuscate and write something like int permission = 0o077.

Member

tmat commented Feb 6, 2015

@SirCmpwn @paulomorgado Could you give an example of source code that would need to specify permissions in octal?

I would rather specify them using
[Flags]enum Permission { None = 0, Execute = 1, Write = 2, Read = 4}

and then new FilePermission(owner: Permission.Read | Permission.Write, group: Permission.Read, all: Permission.None)

I don't see how I would use octal numbers, other then to obfuscate and write something like int permission = 0o077.

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 6, 2015

Contributor

Unix permissions are ubiquitous. A very large number of programmers recognize them when written in octal. When I see 0o777, I immediately think "all permissions for all people". 0o755 tells me "full perms for owner and read+execute for others". Which is better?

int permission = (Permission.Read | Permission.Write | Permission.Execute << PermissionGroup.Owner) |
                 (Permission.Read | Permission.Execute) << PermissionGroup.Group |
                 (Permission.Read | Permission.Execute) << PermissionGroup.User;

or...

int permission = 0o777;
Contributor

SirCmpwn commented Feb 6, 2015

Unix permissions are ubiquitous. A very large number of programmers recognize them when written in octal. When I see 0o777, I immediately think "all permissions for all people". 0o755 tells me "full perms for owner and read+execute for others". Which is better?

int permission = (Permission.Read | Permission.Write | Permission.Execute << PermissionGroup.Owner) |
                 (Permission.Read | Permission.Execute) << PermissionGroup.Group |
                 (Permission.Read | Permission.Execute) << PermissionGroup.User;

or...

int permission = 0o777;
@tmat

This comment has been minimized.

Show comment
Hide comment
@tmat

tmat Feb 6, 2015

Member

Makes sense - in some contexts you might need to work with Linux permissions often and is advantageous to have a shortcut. However, I'm still not convinced this use case warrants a language feature.

You can write a helper method today that converts from decimal number to octal and use it like so:
int permission = Permission(755);

Member

tmat commented Feb 6, 2015

Makes sense - in some contexts you might need to work with Linux permissions often and is advantageous to have a shortcut. However, I'm still not convinced this use case warrants a language feature.

You can write a helper method today that converts from decimal number to octal and use it like so:
int permission = Permission(755);

@alanfo

This comment has been minimized.

Show comment
Hide comment
@alanfo

alanfo Feb 6, 2015

@tmat

I wouldn't underestimate the value of being able to deal more conveniently with legacy code to some C# developers, particularly as we're only talking about a relatively trivial addition to the language. The effort needed to implement octal literals (using the suggested prefix) would be no more than for binary literals.

Sure, if I'm translating C code to C#, I can write a method to convert octal literals to decimal - let's say:

      public static int FromOctal(int octal)
      {
          bool negative = (octal < 0);
          if (negative) octal = -octal;
          int multiplier = 1;
          int result = 0;
          while(octal > 0)
          {
              int digit = octal % 10;
              result += multiplier * digit;
              octal /= 10;
              multiplier <<= 3;
          }  
         if (negative) result = -result;
         return result;
     }

and then replace 0145 in C, say, with FromOctal(0145).

However, as in the case of Unix permissions, this isn't very convenient when in F# one could simply write 0o145 or in VB &O145.

Moreover, octal literals would have the same educational value as binary literals - they'd help teach students that decimal isn't the only game in town :)

BTW, I certainly wouldn't suggest that we used the same syntax as C/C++/Java for expressing octal literals i.e. simply prefix with them a zero. That wouldn't be possible now in C# anyway as it would be a breaking change (0145 is the same as 145 decimal) and it always was a horrible, confusing syntax in my view.

alanfo commented Feb 6, 2015

@tmat

I wouldn't underestimate the value of being able to deal more conveniently with legacy code to some C# developers, particularly as we're only talking about a relatively trivial addition to the language. The effort needed to implement octal literals (using the suggested prefix) would be no more than for binary literals.

Sure, if I'm translating C code to C#, I can write a method to convert octal literals to decimal - let's say:

      public static int FromOctal(int octal)
      {
          bool negative = (octal < 0);
          if (negative) octal = -octal;
          int multiplier = 1;
          int result = 0;
          while(octal > 0)
          {
              int digit = octal % 10;
              result += multiplier * digit;
              octal /= 10;
              multiplier <<= 3;
          }  
         if (negative) result = -result;
         return result;
     }

and then replace 0145 in C, say, with FromOctal(0145).

However, as in the case of Unix permissions, this isn't very convenient when in F# one could simply write 0o145 or in VB &O145.

Moreover, octal literals would have the same educational value as binary literals - they'd help teach students that decimal isn't the only game in town :)

BTW, I certainly wouldn't suggest that we used the same syntax as C/C++/Java for expressing octal literals i.e. simply prefix with them a zero. That wouldn't be possible now in C# anyway as it would be a breaking change (0145 is the same as 145 decimal) and it always was a horrible, confusing syntax in my view.

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 6, 2015

Contributor

I've been mostly playing devil's advocate for octal here, since I don't really have a use-case. That being said, I don't see any reason not to implement it - the actual implementation would be pretty simple and the side effects are minimal, if they exist at all. If there are use-cases, why not implement octal?

Contributor

SirCmpwn commented Feb 6, 2015

I've been mostly playing devil's advocate for octal here, since I don't really have a use-case. That being said, I don't see any reason not to implement it - the actual implementation would be pretty simple and the side effects are minimal, if they exist at all. If there are use-cases, why not implement octal?

@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado Mar 3, 2015

@tmat,

I also don't have a use-case. Probably the teams working on porting .NET to *nix systems have some experience by now.

Your DCO (Decimal-Coded Octal - as opposed to BCD) seems good enough for me to handle permissions.

paulomorgado commented Mar 3, 2015

@tmat,

I also don't have a use-case. Probably the teams working on porting .NET to *nix systems have some experience by now.

Your DCO (Decimal-Coded Octal - as opposed to BCD) seems good enough for me to handle permissions.

@dsaf

This comment has been minimized.

Show comment
Hide comment
@dsaf

dsaf May 23, 2015

@MadsTorgersen Please consider #263 for C# 7 as well. It's currently closed due to absence of lexical grammar, but I have just submitted a draft one.

dsaf commented May 23, 2015

@MadsTorgersen Please consider #263 for C# 7 as well. It's currently closed due to absence of lexical grammar, but I have just submitted a draft one.

@wedge905

This comment has been minimized.

Show comment
Hide comment
@wedge905

wedge905 Jul 8, 2015

Yes, please implement binary literals! I was sad to see it got cut from C#6.
This would be extremely useful in NetMF!

wedge905 commented Jul 8, 2015

Yes, please implement binary literals! I was sad to see it got cut from C#6.
This would be extremely useful in NetMF!

@Tizana

This comment has been minimized.

Show comment
Hide comment
@Tizana

Tizana Jul 12, 2015

As embedded engineer and making C# code for Windows IOT on Rasbperry pi and working a lot on binary register and bitwise. it was so sad for me to know that no Binary literals are available inside this language 👎

hope from the bottom of my heart this will be add in the near future. 👍

Tizana commented Jul 12, 2015

As embedded engineer and making C# code for Windows IOT on Rasbperry pi and working a lot on binary register and bitwise. it was so sad for me to know that no Binary literals are available inside this language 👎

hope from the bottom of my heart this will be add in the near future. 👍

@gafter gafter added this to the C# 7 and VB 15 milestone Aug 26, 2015

@SirCmpwn

This comment has been minimized.

Show comment
Hide comment
@SirCmpwn

SirCmpwn Feb 24, 2016

Contributor

I'm going to give a 👎 to that, then. Seems complicated and doesn't have prior art to justify it.

Contributor

SirCmpwn commented Feb 24, 2016

I'm going to give a 👎 to that, then. Seems complicated and doesn't have prior art to justify it.

@MattGertz MattGertz added the Retriage label Mar 1, 2016

@gafter gafter modified the milestones: 1.2, 2.0 (RTM) Mar 22, 2016

@giggio

This comment has been minimized.

Show comment
Hide comment
@giggio

giggio Apr 18, 2016

This should be tagged New Language Feature - Binary Literals.

giggio commented Apr 18, 2016

This should be tagged New Language Feature - Binary Literals.

@shaggygi

This comment has been minimized.

Show comment
Hide comment
@shaggygi

shaggygi Aug 29, 2016

Contributor

I noticed comments above related to Binary Literal strings, but is it finalized (in another issue or design notes) how strings will work? For example, are there any examples how string interpolation would look like compared to hexadecimal... $"{value:X2}";

Contributor

shaggygi commented Aug 29, 2016

I noticed comments above related to Binary Literal strings, but is it finalized (in another issue or design notes) how strings will work? For example, are there any examples how string interpolation would look like compared to hexadecimal... $"{value:X2}";

@svick

This comment has been minimized.

Show comment
Hide comment
@svick

svick Aug 29, 2016

Contributor

@shaggygi String interpolation is defined in terms of string.Format(), so I think that adding support for binary to numeric format strings is a question for corefx, not Roslyn.

Contributor

svick commented Aug 29, 2016

@shaggygi String interpolation is defined in terms of string.Format(), so I think that adding support for binary to numeric format strings is a question for corefx, not Roslyn.

@shaggygi

This comment has been minimized.

Show comment
Hide comment
@shaggygi

shaggygi Aug 29, 2016

Contributor

@svick Okay. I'll try to ping that repo and reference this topic.

Contributor

shaggygi commented Aug 29, 2016

@svick Okay. I'll try to ping that repo and reference this topic.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Aug 29, 2016

Regarding the octal, see dotnet/corefx#2993 (comment). F# and VB has octal cocktail, why can't C# has it? The number theory guys would be happy too. :)

ghost commented Aug 29, 2016

Regarding the octal, see dotnet/corefx#2993 (comment). F# and VB has octal cocktail, why can't C# has it? The number theory guys would be happy too. :)

@gafter gafter assigned MadsTorgersen and unassigned gafter Oct 28, 2016

@strohlaj

This comment has been minimized.

Show comment
Hide comment
@strohlaj

strohlaj Nov 23, 2016

What would be the best way to represent negative numbers using the binary literal syntax?
The logical negation '~'? Is there a way to include the signed bit in the binary literal syntax like so:

int maxIntValue = 0b0_1111111_11111111_11111111_11111111; //int.MaxValue;
int two = 0b0_0000000_00000000_00000000_00000010; //2
int one = 0b0_0000000_00000000_00000000_00000001; //1
int zero = 0b0_0000000_00000000_00000000_00000000; //0
int negOne = 0b1_1111111_11111111_11111111_11111111; //-1
int negTwo = 0b1_1111111_11111111_11111111_11111110; //-2
int minIntValue = 0b1_0000000_000000000_00000000_00000000; //int.MinValue;

This might only work if we know what type the binary literal is being assigned.

In the current preview build the last 3 require a cast to uint thereby no longer being negative numbers. Perhaps I missed a better way to represent negative numbers using the binary literal syntax.

strohlaj commented Nov 23, 2016

What would be the best way to represent negative numbers using the binary literal syntax?
The logical negation '~'? Is there a way to include the signed bit in the binary literal syntax like so:

int maxIntValue = 0b0_1111111_11111111_11111111_11111111; //int.MaxValue;
int two = 0b0_0000000_00000000_00000000_00000010; //2
int one = 0b0_0000000_00000000_00000000_00000001; //1
int zero = 0b0_0000000_00000000_00000000_00000000; //0
int negOne = 0b1_1111111_11111111_11111111_11111111; //-1
int negTwo = 0b1_1111111_11111111_11111111_11111110; //-2
int minIntValue = 0b1_0000000_000000000_00000000_00000000; //int.MinValue;

This might only work if we know what type the binary literal is being assigned.

In the current preview build the last 3 require a cast to uint thereby no longer being negative numbers. Perhaps I missed a better way to represent negative numbers using the binary literal syntax.

@CyrusNajmabadi

This comment has been minimized.

Show comment
Hide comment
@CyrusNajmabadi

CyrusNajmabadi Nov 23, 2016

Contributor

@strohlaj:

What about:

int negOne = - 0b1.

C# does not have negative literals. It has negative constant expressions. So this just fits with that.

Contributor

CyrusNajmabadi commented Nov 23, 2016

@strohlaj:

What about:

int negOne = - 0b1.

C# does not have negative literals. It has negative constant expressions. So this just fits with that.

@strohlaj

This comment has been minimized.

Show comment
Hide comment
@strohlaj

strohlaj Nov 23, 2016

I like it and that definitely works. My only real complaint (and this is strictly an opinion) is that it seems to hide the binary representation of the negative number.

strohlaj commented Nov 23, 2016

I like it and that definitely works. My only real complaint (and this is strictly an opinion) is that it seems to hide the binary representation of the negative number.

@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado Nov 23, 2016

@strohlaj

Do you really usually care that 0b1_1111111_11111111_11111111_11111110 is decimal -2?

paulomorgado commented Nov 23, 2016

@strohlaj

Do you really usually care that 0b1_1111111_11111111_11111111_11111110 is decimal -2?

@GeirGrusom

This comment has been minimized.

Show comment
Hide comment
@GeirGrusom

GeirGrusom Nov 23, 2016

unchecked((sbyte)0b11111111)

GeirGrusom commented Nov 23, 2016

unchecked((sbyte)0b11111111)
@strohlaj

This comment has been minimized.

Show comment
Hide comment
@strohlaj

strohlaj Nov 23, 2016

@paulomorgado
I've tried thinking of a hypothetical situation where it would make more sense but nothing comes immediately to my mind. I will say that it's nice from an educational perspective. For students to visually see the negative integers in binary form as they actually are would be nice for teaching how ones compliment works.

strohlaj commented Nov 23, 2016

@paulomorgado
I've tried thinking of a hypothetical situation where it would make more sense but nothing comes immediately to my mind. I will say that it's nice from an educational perspective. For students to visually see the negative integers in binary form as they actually are would be nice for teaching how ones compliment works.

@wedge905

This comment has been minimized.

Show comment
Hide comment
@wedge905

wedge905 Nov 23, 2016

When dealing with hex or binary literals, it's wrong to think of them in terms of numbers. It's more accurate to think of them in terms of bits and bytes. They are just arbitrary data, which is meaningless by itself. The meaning is assigned to the data by the reader.
Example:
What number is this? 0b11110100
If you assume that those bits represent an 8-bit signed int, then it's -12
but if you assume an 8-bit unsigned int, then it's 244
even if you assume 16-bit signed, then it's still 244

It's all in how you read it, which is why @GeirGrusom's answer is the best, because that's exactly what he's doing there, changing how you read the number.

wedge905 commented Nov 23, 2016

When dealing with hex or binary literals, it's wrong to think of them in terms of numbers. It's more accurate to think of them in terms of bits and bytes. They are just arbitrary data, which is meaningless by itself. The meaning is assigned to the data by the reader.
Example:
What number is this? 0b11110100
If you assume that those bits represent an 8-bit signed int, then it's -12
but if you assume an 8-bit unsigned int, then it's 244
even if you assume 16-bit signed, then it's still 244

It's all in how you read it, which is why @GeirGrusom's answer is the best, because that's exactly what he's doing there, changing how you read the number.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Mar 27, 2017

Member

This has been implemented in C# 7.0. See also dotnet/csharplang#55

Member

gafter commented Mar 27, 2017

This has been implemented in C# 7.0. See also dotnet/csharplang#55

@gafter gafter closed this Mar 27, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment