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

Champion "Target-typed new expression" (VS 16.8, .NET 5) #100

Open
3 of 5 tasks
gafter opened this issue Feb 14, 2017 · 204 comments
Open
3 of 5 tasks

Champion "Target-typed new expression" (VS 16.8, .NET 5) #100

gafter opened this issue Feb 14, 2017 · 204 comments
Assignees
Labels
Design Review Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion
Milestone

Comments

@gafter
Copy link
Member

gafter commented Feb 14, 2017

Summary: Allow Point p = new (x, y);

Shipped in preview in 16.7p1.


  • Proposal added
  • Discussed in LDM
  • Decision in LDM (let's go ahead with prototype)
  • Finalized (done, rejected, inactive)
  • Spec'ed

See also dotnet/roslyn#35

Test plan: dotnet/roslyn#28489

@gafter gafter changed the title Target-typed new expression Champion Target-typed new expression Feb 15, 2017
@gulshan
Copy link

gulshan commented Feb 15, 2017

At least this can be done with object initializers without type-name, which currently generate anonymous types.

@Thaina
Copy link

Thaina commented Mar 26, 2017

I am more fond of var everywhere instead of empty new

@jnm2
Copy link
Contributor

jnm2 commented Mar 26, 2017

@Thaina I absolutely agree for locals, but for fields and properties this would actually be preferable to me and a_m_a_z_i_n_g, not gonna lie.

private readonly Dictionary<(Foo foo, Bar bar), List<Baz>> bazByFooAndBar = new();

Love it! Plus also:

private readonly Dictionary<Foo, Bar> barByFoo;

public ctor(IDictionary<Foo, Bar> initialValues)
{
   barByFoo = new(initialValues);
}

I do a lot of field initialization requiring access to this, so I end up saying new and repeating long types quite frequently in constructor bodies.

@Thaina
Copy link

Thaina commented Mar 26, 2017

@jnm2 Well, readonly in constructor seem great

But still that the only place I think we should do like that, I don't like mutable reference so field should not new anywhere. I wish we could have var field instead

@Richiban
Copy link

@Thaina

I wish we could have var field instead

I believe this is a limitation of the fact that C# has a two-pass compiler. The entire signature of a class needs to be known before any of the initialization expressions can be executed, so if you use var for a field the compiler doesn't know the type on the right-hand side of the =.

@alrz
Copy link
Contributor

alrz commented May 22, 2017

I think private var fields (and let for readonly) are ok, as long as they are immediately initialized, just like what we have for local vars.

@gafter
Copy link
Member Author

gafter commented May 22, 2017

I think private var fields (and let for readonly) are ok, as long as they are immediately initialized, just like what we have for local vars.

@alrz A var-declared local's initialization can only rely on earlier-declared locals. That eliminates the possibility of cycles. Fields do not have any corresponding restrictions that would eliminate such cycles by defining an order in which the types are inferred.

In any case, that would be a completely separate language proposal.

@iam3yal
Copy link
Contributor

iam3yal commented May 23, 2017

Yes please, let's make things less verbose whenever possible and whenever it make sense. :)

@gordanr
Copy link

gordanr commented May 23, 2017

I'm not sure is it related with this topic.

public List<Error> ValidateInput() => new List<Error>();

This piece of code could be, with some generalization, written as

public List<Error> ValidateInput() => new();

I really don't know is it readable and right direction. Possibly not. Just to leave a little note.

@lachbaer
Copy link
Contributor

public List<Error> ValidateInput() => new();

I'm a bit riven by this. On one hand I think that a method's body should be independent of its signature, meaning that the creation of an object for a return should be verbose. On the other hand for expressions, so expression method bodies as well, this is very neat. It's like default vs. default(T), but I think default is valid in block bodies as well?

@masaeedu
Copy link

masaeedu commented Jun 2, 2017

Constructors are kind of useless at the moment, you can't do type inference with them, can't pass a bound constructor as a first class function, etc. etc. At the same time you're stuck using them if you want to use readonly or getter-only properties. The end result is that every class I write has a static "constructor" function that simply delegates to the regular constructor, but behaves like a normal function from the perspective of consuming code.

It would be great if there could be some focus on bringing constructor functions into parity with plain old static methods, instead of piecemeal workarounds like this.

@Joe4evr
Copy link
Contributor

Joe4evr commented Dec 6, 2017

Reading the raw notes:

It may be that there's a subset of the feature that's simpler. We would need that subset to not preclude going further later.

Looking at the concern that an API adding a new overload could break consumers, the "simple" subset of places where target-typed new can be applied (that I'm pretty sure won't preclude further options) would be

  • Local variables
  • Field/property intializers
  • (maybe) return statements

The first two are the places where it seems like most people are really clamoring for it; the last one I just came up at the spur of the moment.

@mkane91301
Copy link

@mkane91301

And my argument is I would prefer the naked new and don't allow target-typed new AT ALL for arguments to overloaded constructors or methods, even when the compiler can resolve the call with no ambiguity. I feel that when there are overloads, using a target-typed new makes the code LESS readable because it's even more confusing to the reader than to the compiler as to which overload is intended.

Therein lies the problem, calling an overloaded method with an anonymous type is already perfectly legal. That's why there must be syntax that clearly distinguishes a target-type new expression from an anonymous type expression.

And if target-typed new was not allowed for overloaded and generic arguments, simply because they make the code less readable, then there’s no ambiguity between a construct that’s forbidden and one that already exists so there’s no reason to require parentheses.

@HaloFour
Copy link
Contributor

@mkane91301

Even if it's not ambiguous to the compiler it's still ambiguous and confusing to the reader. I would find it to be very strange if a target-typed new expression suddenly turned into an anonymous type expression by introducing an overload.

@mkane91301
Copy link

@mkane91301

Even if it's not ambiguous to the compiler it's still ambiguous and confusing to the reader. I would find it to be very strange if a target-typed new expression suddenly turned into an anonymous type expression by introducing an overload.

I agree with that. Personally, I would be fine if target-typed new was only supported for initializing fields and properties, which is the only case where you type the same type name twice in a row. I’d be fine with requiring the parentheses. But I think I’ve shown that it’s a small edge case where the compiler could not tell that leaving out the parentheses was a grammatical error for target-typed new and not an illegal cast from an anonymous type. I think it’s reasonable to ask for an improved error message, which was my original point.

@CyrusNajmabadi
Copy link
Member

I think it’s reasonable to ask for an improved error message, which was my original point

Definitely. However, improved error messages should be requested at dotnet/Roslyn, not csharplang. Thanks!

@harold-b
Copy link

Playing with the preview, I've really enjoyed this feature, thank you.

However, I've missed it when initializing arrays. Are there plans to support target typed new for array types?

I realize I can use Implicitly Typed Array syntax, but this won't work when initializing an array with no initial elements, even if there is an explicit declaration of the target variable type.

It would be useful to have the ability to initialize them as such:

public (float, int, string)[] foo = new [2];

@PathogenDavid
Copy link

PathogenDavid commented Jul 30, 2020

Are there plans to support target typed new for array types?

It does not appear that there is, from the proposed spec:

  • The following kinds of types are not permitted as targets of the conversion
    • [...]
    • Array types: arrays need a special syntax to provide the length.

Arrays are also listed in the 2018-06-25 LDM meeting notes as an unconstructible type.

I agree it seems like arrays should be supported. Based on the wording from the spec, I think it'd be considered to be its own feature separate from C# 9's target-typed new.

@harold-b
Copy link

It does not appear that there is, from the proposed spec:

Ah, I missed that document. Thank you for providing the info. I suppose that's that. Hopefully in the future 🤞

@jcouv
Copy link
Member

jcouv commented Jul 30, 2020

We discussed target-typing for array creation, but in many useful cases it is not trivial to figure out the target element type. For instance IEnumerable<short> array = new[] { 1 };.
Here's the championed proposal: #2701

@lcsondes
Copy link

@jcouv If I understand that correctly that's for having new() within new[]{/*here*/}. This on the other hand is KnownType[] arr = new[5];, is that covered?

@harold-b
Copy link

@jcouv, understood, looks like there's some design decisions that need to be settled first. Thanks for the example and the link to the proposal.

If I understand that correctly that's for having new() within new[]{/here/}

@lcsondes it looks like both are covered in the linked proposal:

For the sake of completeness, I'd suggest to also make new[] a target-typed expression,

IEnumerable<KeyValuePair<string, string>> Headers = new[]
{
    new("Foo", foo),
    new("Bar", bar),
}

@jcouv jcouv changed the title Champion "Target-typed new expression" Champion "Target-typed new expression" (VS 16.8, .NET 5) Sep 1, 2020
@MadsTorgersen MadsTorgersen modified the milestones: 9.0 candidate, 9.0 Sep 9, 2020
@333fred 333fred added the Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification label Oct 16, 2020
@lcsondes
Copy link

lcsondes commented Jul 9, 2021

What's the plan for new[1]? It doesn't seem to have shipped.

@333fred
Copy link
Member

333fred commented Jul 9, 2021

What's the plan for new[1]? It doesn't seem to have shipped.

See #2701.

@lcsondes
Copy link

lcsondes commented Jul 9, 2021

What's the plan for new[1]? It doesn't seem to have shipped.

See #2701.

Thank you, but that only seems to talk about target-typed expressions between the {}. Right now I think the compiler is expecting a , or ] after new[ which would not need a change to cover the examples in #2701 but would need to change to cover new[123]. (see also #100 (comment))

Is this secretly covered? It would be nice if we could get an explicit yes/no.

@CyrusNajmabadi
Copy link
Member

I'm not sure what you mean by 'secretly covered'

@lcsondes
Copy link

lcsondes commented Jul 9, 2021

That I do not see a number within square brackets in any of the proposed target-typed new array examples.

@333fred
Copy link
Member

333fred commented Jul 9, 2021

That is the proposal I just linked.

@lcsondes
Copy link

lcsondes commented Jul 9, 2021

All I'm trying to get is an explicit yes/no on whether that one covers new[1] specifically, because all it talks about is new[]{new(1)}.

@PathogenDavid
Copy link

PathogenDavid commented Jul 9, 2021

That is the proposal I just linked.

I think it's something LDM could naturally include alongside that proposal, but unless I'm blind nothing in the #2701 suggests that it would enable something like int[] myArray = new[10]; as an equivalent alternative to to int[] myArray = new int[10]; (Which I believe is what @lcsondes is asking about.)

@CyrusNajmabadi
Copy link
Member

We can't give an explicit yes/no since it hasn't been designed yet.

I can say that it would definitely be part of the discussion. However, there's no guarantees that can be given for a future feature that hasn't even been brought to ldm to do.

@julealgon
Copy link

@CyrusNajmabadi why is this issue still open and with pending tasks? Hasn't this already shipped some time ago?

Apologies if I'm missing something obvious, but this is not making much sense to me.

@theunrepentantgeek
Copy link

Issues are left open until the relevant specs and documentation are fully updated.

@333fred
Copy link
Member

333fred commented Jul 9, 2021

That's what the Implemented Needs ECMA Spec label is referring to.

@GunelYusuf

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Review Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion
Projects
None yet
Development

No branches or pull requests