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

Lift Object initializers to constructor role #2558

Closed
gulshan opened this issue May 24, 2019 · 6 comments
Closed

Lift Object initializers to constructor role #2558

gulshan opened this issue May 24, 2019 · 6 comments

Comments

@gulshan
Copy link

gulshan commented May 24, 2019

Object initializers are quite popular and arguably the default way of constructing/initializing objects in C#. I am proposing here to lift their role to constructor level. Which means object initializers will be able to set properties, which are otherwise only settable in constructors. Some arguments for it-

  • Modern programming languages usually facilitate and even encourage two things- Immutability and Non-nullability(or expressing and tracking absence of values). C# has long supported getter-only properties and readonly type members supporting immutability. And non-nullability support was there for value types and coming for reference types. But Object initializers do not play nice with them. If lifted to constructor level, immutability and non-nullability will become more common without awkward code-circus. This will result in safer code.

  • Being a popular way and arguably default way to initialize objects (specially data objects), object initializers deserve to be a core language feature rather than being a syntactic sugar like it is now.

  • If records ever come to C#, most probably this is going to happen one way or another, at least for the records.

Now the question is, isn't this a breaking change? Of course, internally it changes the meaning and implementation of the construct. But on the surface it still carries the same meaning- initializing an object. In exiting usages, it will keep doing what developer intended it to do. But it will enable new scenarios. Currently I cannot think of any situation where this breaks current code- generate errors/warnings or working against the intent of developer. Please discuss if you can find one.

Still I think, there should not be a silent behavior change and this should be enabled under a flag. And compiler should keep supporting both meanings of object initializers for some time at least. But I think, rather than having its own flag, this can be tagged with "Nullable reference type" compiler flag- same flags enabling both features. One reason for this is, the shortcomings of object initializers become more visible with nullability tracking. Also enabling two features together can facilitate warnings on not initializing non-nullable readonly properties.

Any thoughts?

@HaloFour
Copy link
Contributor

HaloFour commented May 24, 2019

Why don't named arguments for constructors suffice here? That's likely what will be used for records, not object initializers.

I don't like the idea of setting a readonly property from outside of the constructor. It's a violation of the contract and I think opens up abuse to setting those properties outside of "initialization" (which doesn't exist beyond syntax candy). If initialization could support a builder pattern for immutable types I'd be happier with that, although this is something you can write today pretty easily.

As for a compiler flag, each one creates a dialect of the language. The bar for creating such a flag should be absurdly high. If a normal language feature needs to break 100 points, a language dialect should have to exceed a billion, in that they're only considered to solve "billion dollar mistake" caliber problems.

@john-h-k
Copy link

arguably the default way of constructing/initializing objects in C#

I strongly disagree. Constructors are and should be used a lot more often

@gulshan
Copy link
Author

gulshan commented May 26, 2019

Regarding constructors vs object initializers, I was in favor of constructors, with named parameters when needed. My own proposal #1614 is based on the merits of constructors. But without any primary constructors in C#(unlike Kotlin), naming style deference between (constructor) parameters and properties, constructors are more of a chore, specially for DTO or data classes. Object initializers are more flexible. That's why object initializers are often used. That's why language designers and library writers tries to keep the provision of using objects initializers for data classes. EF core is doing that for models. I don't the future, but all the previous discussion regarding record tried to keep the option of using object initializers. One proposal was only supporting object initializers. Some proposals were there to support initializers with some magic (mutable nullable builder classes), which will still change the definition of object initialization in some way. And developers have to keep that thing in mind.

Regarding compiler flag, I admit that adding a compiler flag is like introducing a dialect of the language. I don't want a separate dialect of C# based on just this feature. What I want is, include this feature in the "Nullable reference type" dialect. May the name of the compiler flag/ dialect be changed to something like "safe" or "strict" for clarity. One may argue that although this feature looks like object initializers, but it is something else(a real constructor with the ability to initialize readonly properties/values) which is superseding object initializers. And thus it should have its own name for clarity- something like "Ad-hoc constructors"? But I think naming part comes later.

@juliusfriedman
Copy link

Why can't you just use a static function which accepts your type and then encapsulate that through the use of an Action? I don't see why the entire language needs to support a feature just so you can Memorize if you have initialized a type or not? If the readonly is assigned in the constructor that you can call an arbitrary init method from there anyway. IMHO this is much more a matter of library design than that of a language feature which is needed.

@gulshan
Copy link
Author

gulshan commented May 27, 2019

Some previous issues discussing the problem of object initializers with nullability and immutability-
#2452
#2328
Some of these felt like stopgap solutions to me.

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

5 participants