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

Proposal: Initialize to known type instead of anonymous type when possible #16769

Closed
gulshan opened this issue Jan 26, 2017 · 6 comments
Closed

Comments

@gulshan
Copy link

gulshan commented Jan 26, 2017

Given following classes-

class Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

class PointWrapper
{
    public Point Value { get; }
}

the statement

var p1 = new PointWrapper {  // Currently valid
    Value = { X = 0, Y = 0 } 
};

is already valid. No need to specify type of property Value within the initializer. Even new keyword is not required (using new is an error actually). But Point p = new { X = 1, Y = 2 }; is not valid. We have to write

Point p = new Point { X = 1, Y = 2 };  // Currently valid

My proposal is, when the type of an object is known, make the type-name optional with initializers. In other words, convert the right hand anonymous typed object to the specified type enabling-

Point p = new { X = 1, Y = 2 };  // Proposing

It should not affect the case when the type is not already known or specified like-

var p = new { X = 1, Y = 2 };  // Currently valid, no conversion

Same goes for collection initializers, so that this-

List<Point> list = new List<Point>{
    new Point { X = 0, Y = 0 },
    new Point { X = 1, Y = 1 }
};

can be written like-

List<Point> list = new {
    { X = 0, Y = 0 },
    { X = 1, Y = 1 }
};

Related- #16648

@gulshan gulshan changed the title Proposal: Convert anonymous objects to know types Proposal: Convert anonymous objects to known types Jan 26, 2017
@HaloFour
Copy link

Akin to #35.

@HaloFour
Copy link

The following two mean very different things:

var p1 = new PointWrapper {
    Value = { X = 1, Y = 2 } 
};

var p2 = new PointWrapper {
    Value = new Point { X = 3, Y = 4 } 
};

They mean the following:

PointWrapper p1 = new PointWrapper();
p1.Value.X = 1;
p1.Value.Y = 2;

PointWrapper p2 = new PointWrapper();
Point temp = new Point();
temp.X = 3;
temp.Y = 4;
p2.Value = temp;

The difference becomes very apparent when the property is readonly or is not initialized to a value. For example, if Point were instead a reference type and null, the shorter syntax would fail with a NullReferenceException.

@gulshan
Copy link
Author

gulshan commented Jan 26, 2017

@HaloFour Then this "child" object initializer is a potentially dangerous but valid construct, without generating any warning/error. Don't know why was it introduced in the first place. I know there is a workaround to make it work. But I think this construct should be made safe without requiring that workaround, in 3 steps-

  • This proposal to make type optional for initializers if known. The "child" initializer was brought up to show the syntactic similarity only.
  • Instead of just being a syntactic sugar, initializers should be reworked to support initializing read-only (get-only) properties of an object. In this case, the initializer will be required to initialize all read-only properties, unless they have default values. Then initializers will work with upcoming record types also.
  • In the last step, new keyword can be made optional for "children" initializers. Only root initializer having new will suffice for children.

@HaloFour
Copy link

@gulshan

Don't know why was it introduced in the first place.

It was introduced specifically to allow initializing readonly properties. That behavior is shipped and cannot be changed.

Instead of just being a syntactic sugar, initializers should be reworked to support initializing read-only (get-only) properties of an object. In this case, the initializer will be required to initialize all read-only properties, unless they have default values. Then initializers will work with upcoming record types also.

Initializers cannot initialize readonly properties, for many reasons. Assuming that the property is actually some 1:1 match to a field, that field is readonly, and it's illegal in the CLR to write to said field outside of the constructor. And for readonly properties that don't share such a relationship with a field it wouldn't make any sense. At best you'd be hoping that there's some 1:1 relationship between the readonly property and some constructor parameter, but that would be absolutely impossible for the C# compiler to automatically determine. The C# team has already shied away from such automatic behavior for positional deconstruction. If you want something that smells like an initializer for constructor parameters, you have named parameters.

As for record types, you would initialize them via the constructor, not their properties.

@gulshan
Copy link
Author

gulshan commented Jan 27, 2017

Making initializers work with read-only properties is another discussion, IMHO. In this thread, I think we can stick to the main proposal, initialize to known type instead of anonymous type when possible.

@gulshan gulshan changed the title Proposal: Convert anonymous objects to known types Proposal: Initialize to known type instead of anonymous type when possible Jan 27, 2017
@jcouv
Copy link
Member

jcouv commented Oct 22, 2017

This was discussed as part of the "target-typed new" proposal (dotnet/csharplang#100).
I'll go ahead and close the Roslyn issue. The discussion should continue on csharplang. Thanks

@jcouv jcouv closed this as completed Oct 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants