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] Object initializers for factory methods #133

Closed
ashmind opened this issue Jan 28, 2015 · 9 comments
Closed

[Proposal] Object initializers for factory methods #133

ashmind opened this issue Jan 28, 2015 · 9 comments

Comments

@ashmind
Copy link
Contributor

ashmind commented Jan 28, 2015

Problem

This is another one of the issues when a change to logic significantly changes code structure.
Let's say I had the following:

var x = new X {
    A = a,
    B = b,
    C = { D = { d1, d2 } }
};

Now I decided all X should be created through an XFactory instead.
So I get:

var x = factory.CreateX();
x.A = a;
x.B = b;
x.C.D.Add(d1);
x.C.D.Add(d2);

One small logical change causes a total restructure of not-really-related code.

Potential solution

Provide a way to use object initializer with any existing object.
Example:

var x = factory.CreateX() with {
    A = a,
    B = b,
    C = { D = { d1, d2 } }
};

Keyword with here is provided to remove any syntax ambiguities.

Pros
  1. More consistent syntax everywhere. Shorter syntax for setting a few properties when you need that.
Cons
  1. New kind of expression-with-side-effects when used on an existing object.
@RichiCoder1
Copy link

The con could be a big con, but it could be a pro if you expand the scope of the idea. Setting multiple properties on an object after it's been created is not an unheard of thing.

@paulomorgado
Copy link

@ashmind,

Can you give an example of what syntax ambiguities does the use of with remove?

Can you elaborate on the cons part?

Are you aware that this:

var x = new X {
    A = a,
    B = b,
    C = { D = { d1, d2 } }
};

is translated into this?

X tmp = new X();
tmp.A = a;
tmp.B = b;
tmp.C.D.Add(d1);
tmp.C.D.Add(d1);
X x = tmp;

The use cases for a block assignment are many. One is the assign properties of return values of methods. But I could also do something like this:

var x = new X { A = 1, B = 2 };
var y = x { A = a, B = b, C = { D = { d1, d2 } } };

I just think you got the motivation all wrong.

@ashmind
Copy link
Contributor Author

ashmind commented Mar 6, 2015

Can you give an example of what syntax ambiguities does the use of with remove?

I'm not sure if there are any in the spec at the moment, but allowing x { A = 3 } for arbitrary x seems confusing and may block some other features from being introduced in the future.

Can you elaborate on the cons part?

E.g.

var x = new X();
var y = GetSomething(1, 2, x with { A = 5 }, 4, 5);
// x here has A = 5, which is not immediately obvious

I suppose it can be avoided if initializers are limited to method call results only.

Are you aware that this / is translated into this?

Yes, however I don't want to write it myself for factory methods, given that translator is already in the language.

I just think you got the motivation all wrong.

Can you elaborate? Is your motivation mostly about allowing modification of existing objects?

@paulomorgado
Copy link

@ashmind, I still find the whole thing lacks consistency. You talk about side effects when there aren't any, in comparison.

Sure shorthand would be nice. But that's just it. There are no other pros or cons involved.

@amironov
Copy link

amironov commented May 6, 2015

The proposal also solves the problem of object initializers in using (IDisposable) statement.

Syntax can be similar to the existing (compare x = {...} and C = {...}):

using (var x = new X()) {
    x = {
        A = 1,
        B = 2,
        C = { D = { 3, 4 } },
    };
}

@Licshee
Copy link

Licshee commented May 25, 2016

IMHO we this problem should be split into two, or at least there are quite a few questions we are discussing:

  1. removing "with" keyword should not lead to ambiguity, but only if applied immediately after a method call, it's a visual/readability thing;
  2. allow initializer syntax to show up immediately after a variable or field/property doesn't look like a good idea, mostly b/c when we use initializer syntax, we are usually in a situation where the result should be available as soon as possible, like:
cmd.Parameters.Add(cmd.CreateParameter() { ParameterName = "@name", Value = value });
  1. but there are cases where applying initializer syntax to a property can be useful, or even a variable, i.e.:
cmd.Parameters {
    cmd.CreateParameter() { ParameterName = "@key", Value = key },
    cmd.CreateParameter() { ParameterName = "@value", Value = value }, 
};

and this lacks some sort of readability;

So far the original idea from @ashmind is the best solution for the questions listed above.

@MadsTorgersen
Copy link
Contributor

It's desirable to allow the same initializers on factories as constructor calls. We need to think this through in conjunction with with expressions, and with object initializers for immutable objects.

@Spongman
Copy link

i agree that the 'with' keyword seems unnecessary. i'd like to see this simple extension of 'object initializers' to arbitrary expressions:

  1. new Foo { A = 1 }
  2. new Foo () { A = 1 }
  3. foo { A = 1}
  4. (GetBar().Foos[3]) { A = 1}

@gafter
Copy link
Member

gafter commented Aug 10, 2017

Issue moved to dotnet/csharplang #803 via ZenHub

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

10 participants