Skip to content
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

Allow tuple syntax to be used with consts #1466

Closed
FurkanKambay opened this issue Apr 18, 2018 · 20 comments
Closed

Allow tuple syntax to be used with consts #1466

FurkanKambay opened this issue Apr 18, 2018 · 20 comments

Comments

@FurkanKambay
Copy link

FurkanKambay commented Apr 18, 2018

edit: See #144 instead.

Original post:

Since these are both legal:

public const string CatFoo = "foo";
public const int CatBar = 1396;
// accessing:
var foo = CatFoo;
var bar = CatBar;

This should also be legal:

public const (string Foo, int Bar) Cat = ("foo", 1396);
// accessing:
var foo = Cat.Foo;
var bar = Cat.Bar;

I'm not talking about enabling ValueTuple<> to be const; rather, I'm saying that there should be a way to use the tuple syntax (string foo, int bar) with consts. Since both string and int can be literals, this can be looked at as "consts that have . in their name"

@HaloFour
Copy link
Contributor

How are you expecting this to be encoded in IL?

The CLR only supports a small subset of types for proper literal constants.

The C# compiler also fakes supporting System.Decimal for constants using a special attribute which breaks the decimal value into 5 separate blittable values which the compiler recognizes in place of a proper constant. The VB.NET compiler does the same for System.DateTime as well. I'm not sure such a strategy would work with tuples given the various different potential arities and ordering of types.

@FurkanKambay
Copy link
Author

@HaloFour That's the point of this allowing only literals. It doesn't have to reach IL. It's like current consts.
Look at it this way: these won't be real "tuples" as in ValueTuple<>, more like variables that are just defined like tuples that can have . in their name. All references to the tuple will just be replaced with the constant value.

@HaloFour
Copy link
Contributor

@FurkanKambay

Constant fields are encoded in IL as they can then be referenced by other code in the current (or other) projects. For reference:

public const int I = 123;
public const string S = "123";

is compiled to:

    .field public static literal int32 I = int32(123)
    .field public static literal string S = "123"

and:

public const decimal D = 123.4m;

is compiled to:

    .field public static initonly valuetype [mscorlib]System.Decimal D
    .custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = (
        01 00 01 00 00 00 00 00 00 00 00 00 d2 04 00 00
        00 00
    )

@svick
Copy link
Contributor

svick commented Apr 18, 2018

@FurkanKambay

It doesn't have to reach IL.

Then how would you use a public tuple constant from a different project/assembly?

@FurkanKambay
Copy link
Author

FurkanKambay commented Apr 18, 2018

@HaloFour Ahhh, that makes sense. I can't believe I never thought about that! I was thinking that consts don't make it to IL 🤦‍♂️

How about this: (I'm not sure this will exactly work, but I think it's progress)

const (int foo, int bar) myTuple = (1, 2);

// converts to:

[TupleConstAttribute(Name="myTuple")]
// special name to avoid conflicts
const int __foo = 1;
// or instead of an attribute, maybe include the tuple name in the name
const int <bar>k__myTuple = 2;

So, in IL:

.field private static literal int32 '<foo>k__myTuple' = int32(1) // following the "special name" part of previous snippet
.field private static literal int32 '<bar>k__myTuple' = int32(2)

Or, I'm not very familiar with IL but if it is possible, make the field ValueType<> but still static literal with attributes, maybe?

edit: @svick see line 1 of this comment

@CyrusNajmabadi
Copy link
Member

Why is being const really desirable here? I'm not a fan of const in general across public APIs as it has pretty impactful versioning constraints. Why not just use a "static readonly"?

@FurkanKambay
Copy link
Author

@CyrusNajmabadi because we can have const ints, why not also have const (int, int)? I came up with the idea with two consts I wrote, it's very simple and might be silly but it gave me the idea:
const spaceS = " "; & const spaceC = ' '; -> const (string s, char c) space = (" ", ' ');

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Apr 18, 2018

it's very simple and might be silly but it gave me the idea:

If it's silly why do it? :)

Basically, for something to be a language feature it has to be really useful. The system you've described above seems like a lot of work for very little gain.

@FurkanKambay
Copy link
Author

@CyrusNajmabadi I mean, in my case might be silly, but there may be useful use cases.
Here's one: you have const endpoint strings for an API and they are categorized somehow. You can categorize them by putting each of them in their own tuple.
Just an idea, if a good amount of people like it, then we can add it; otherwise, nothing to lose 😄

@FurkanKambay
Copy link
Author

FurkanKambay commented Apr 18, 2018

@HaloFour I put together a little something. I read that generic attributes are valid in IL (edit: C# support is also coming - #124 ), so I think the 2nd option is the better one:

private const (int, int) foo = (1, 2);

will compile to

.field private static literal int32 '<Item1>k__foo' = int32(1)
.field private static literal int32 '<Item2>k__foo' = int32(2)

or

// by the way, isn't initonly (decimal uses initonly on your comment) the same as readonly?
.field private static literal valuetype [netstandard]System.ValueTuple`2<int32, int32> foo
.custom instance void Namespace.TupleConstantAttribute`2<int32, int32>::.ctor(!0, !1) = ( // 1, 2
    01 00 01 00 00 00 02 00 00 00 00 00
)

@HaloFour
Copy link
Contributor

@FurkanKambay

Maybe. That encoding could work for a private field but I think exposing that kind of mess publicly isn't the best idea.

To @CyrusNajmabadi point, why isn't a static readonly field sufficient here? Constants imply a set of behaviors that often make them less suitable as a part of a public surface, like the versioning issue mentioned. Those problems don't exist with static readonly fields, and you're not limited in any way with how those are initialized. The only times I'll reach for const is when want to name a reusable value that I'm passing to an attribute, which won't work with any of the pseudo-constant shenanigans.

And yes, initonly in IL is readonly in C#. A const decimal is just a static readonly decimal field.

@yaakov-h
Copy link
Member

What good would a constant ValueTuple serve when ValueTuples are inherently mutable?

@jnm2
Copy link
Contributor

jnm2 commented Apr 19, 2018

@yaakov-h A readonly ValueTuple is not mutable, so I would not expect a const one to be.

@CyrusNajmabadi
Copy link
Member

what @jnm2 said. Indeed, it goes beyond that. A readonly value is not mutable. ValueTuple's are just a special case of that.

@jnm2
Copy link
Contributor

jnm2 commented Apr 19, 2018

@CyrusNajmabadi To nitpick unnecessarily, I might call a type mutable even if the values of its fields themselves are readonly, if it contained a reference to a mutable object. Im/mutability would then be in the deep sense of the word, as opposed to the shallow immutability of readonly. So anyway, then ValueTuple does not inherently contain references to mutable objects.

@CyrusNajmabadi
Copy link
Member

Fair distinction!

@FurkanKambay
Copy link
Author

FurkanKambay commented Apr 19, 2018

@HaloFour @CyrusNajmabadi

OK so here's a different way of looking at this:
I just want to be able to reference a const I need by its "category name" like constants.foo but since names cannot contain ., I thought if it was similar to a ValueTuple<>, it might work.

So my proposal isn't allowing ValueTuple<> to be a const; it is that there should be a way to use the tuple syntax (v1, v2) with consts. Maybe this makes more sense. (but if ValueType<> can be consts, then that's better)

@FurkanKambay FurkanKambay changed the title Allow tuples to be const (only those made of constants) Allow tuple syntax to be used with consts Apr 19, 2018
@CyrusNajmabadi
Copy link
Member

I just want to be able to reference a const I need by its "category name" like constants.foo but since names cannot contain ., I thought if it was similar to a ValueTuple<>, it might work.

static class constants {
    public const int foo;
}

?

@Thaina
Copy link

Thaina commented Apr 20, 2018

#144

@FurkanKambay
Copy link
Author

@Thaina Thanks, that proposal includes consts and it's way better. I'm closing this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants