7

Using this code:

struct Foo<T1>
{
    public T1 Item1 { get; private set; }

    public Foo(T1 item1)
    {
        Item1 = item1;
    }
}

I encounter this error:

Backing field for automatically implemented property 'Foo.Item1' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer.

My question is, why is the property Item1 not fully assigned after the constructor is called?

Edit: Changed set to private set because this question has nothing to do with mutability.

tdashroy
  • 1,405
  • 1
  • 19
  • 18
  • 10
    Don't make mutable structs, please. – Mark Byers Dec 14 '10 at 22:02
  • Why shouldn't he? That actually makes things a lot simpler sometimes, and can improve performance quite a bit in some loop-intensive cases. What's wrong with mutable structs? (That also doesn't answer his question.) – user541686 Dec 14 '10 at 22:04
  • @Lambert http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil – George Johnston Dec 14 '10 at 22:07
  • Like all other features, it's only "evil" because people sometimes misuse it... but in good hands, there's nothing "evil" about them, so long as they're used correctly. (In this case, I'd say he might as well expose the fields themselves instead of the properties, but that's another issue.) As an example, if you have a System.Drawing.Rectangle[], how are you supposed to Offset() one without re-instantiating a new one? Do you really have to be forced to write lots of inefficient code just for nothing? – user541686 Dec 14 '10 at 22:10
  • 1
    @Lambert Not only is it easy to come up with broken mutable structs, it's difficult to use them correctly at all. – Tim Robinson Dec 14 '10 at 22:12
  • @Lambert Immutability is a common technique in functional programming; performance is not automatically bad. http://en.wikipedia.org/wiki/Immutable_object – Tim Robinson Dec 14 '10 at 22:14
  • @Tim: In an ideal world, we'd all be doing functional programming, with no mutation of anything, structs or classes. But sometimes that just doesn't cut it -- there's obviously certain cases where it's not adequate, such as when making a binary tree (it's impossible). So sometimes you have to compromise safety for usability. – user541686 Dec 14 '10 at 22:14
  • @Lambert An immutable binary tree: [the F# Map type](http://msdn.microsoft.com/en-us/library/ee353686.aspx) – Tim Robinson Dec 14 '10 at 22:16
  • ...how do you add an element to it? Re-copy a potentially humongous piece of data? – user541686 Dec 14 '10 at 22:16
  • By coming up with a new tree that shares most of its nodes with the old one. Because the nodes are immutable, it doesn't matter that they get re-used. If the tree doesn't need to be rebalanced then you only construct one new node. – Tim Robinson Dec 14 '10 at 22:18
  • But don't you have to copy everything up from the node you're editing, which is O(log n) complexity? (You don't have to touch the children, but you have to re-construct the parent to have this child, then make a parent for that new parent, etc.) – user541686 Dec 14 '10 at 22:20
  • @Tim: By the way, we're just having a course on programming (it used Scheme), with different paradigms (functional, OOP, client/server, etc.), and our professor explicitly mentioned that the whole point of the course wasn't to say "paradigm X is the best", but that we would learn that there's different tools for different problems... and mutation can certainly be a great tool for some problems. – user541686 Dec 14 '10 at 22:20
  • 1
    @Lambert: Mutable structs are a "worst practice" in C#. Saying "they are fine as long as they are used correctly" is specious logic; the problem is that you have to *know* how to use them correctly and *most people do not*. Mutable value types leave little bombs all over your code just waiting for some unsuspecting maintenance programmer to accidentally set them off by doing some trivial-seeming refactoring that treats a mutable value type as a reference type. – Eric Lippert Dec 14 '10 at 23:15
  • 1
    @Lambert: Yes, when rebuilding immutable tree structures you usually have to rebuild the spine, which is O(lg n). Which for a tree with, say, twenty thousand items in it is 15 allocations. Which is hardly anything at all compared to the benefit that you get, namely, you can have a deep stack of past edits in your undo-redo buffer for extremely low cost when every new root pointer has 99.9% of its content recycled from the previous version. – Eric Lippert Dec 14 '10 at 23:22
  • 1
    @Eric: What's wrong with using a mutable struct, say, that's confined to just one method, and never passed around? So long as the guy who programmed the method did so correctly, there's no mines left anywhere for the unsuspecting to trip on. Also, the whole point of the immutable thing wasn't doing it *once* (that's obviously an O(1) case in any way), it was adding things to the tree in a loop, and it doing that clearly increases the time required... which you may or may not want, depending on your application. – user541686 Dec 14 '10 at 23:47
  • @Eric: Also, there's a reason that C, C++, C#, etc. all allow mutation... the standardizing committees (for C/C++) and Microsoft (for C#) were most likely aware of this, but they decided that the feature should be left in there anyway... and I'm guessing they had good reason for doing so. By the way, if you use the tree argument for a linked list, it's actually an O(n) cost... which is clearly much worse than O(log n), and which turns into O(n^2) if you do it in a loop. Do you really think not having mutation is still the best way to program a linked list? – user541686 Dec 14 '10 at 23:52
  • 1
    @Lambert: re "what's wrong with?" Nothing in particular. One can easily come up with trivial, uninteresting cases where a dangerous feature is safe. Those are trivial and uninteresting. Re: binary trees have worst cases: yes, they do. If you are in such a case, use an immutable balanced binary tree; an implementation of one of those is on my blog should you need one. Re: Do I think that an immutable linked list is the best kind of linked list? Yes, absolutely I do; I never insert into the middle of a linked list. – Eric Lippert Dec 15 '10 at 00:04
  • @Eric: Again, it's not a trivial case, and even if it is, it's certainly not uncommon. What if you have someone giving you a singly linked list containing a huge structure from C code? Would you re-copy the entire list just to modify a member? And what if the existing code doesn't even *accept* new lists? Also, I was talking about linked lists in general, not degenerate trees. "I never insert into the middle of a linked list." Then what's the point of using them in the first place? You can't dismiss valid situations and claim all situations are invalid. – user541686 Dec 15 '10 at 00:12
  • 2
    @Lambert: My point is that I use immutable linked lists precisely because they have cheap insertion where I need to insert. If I needed to insert into the middle of a list then I wouldn't use an immutable linked list, I'd use an immutable catenable deque -- an implementation of which is on my blog should you happen to need one. Of course if I am using a C-style API which explicitly expects mutation as the way you communicate with it, then I'd say that's a badly written API, but I'd use it as it was designed to be used. – Eric Lippert Dec 15 '10 at 00:35
  • 1
    @Eric: There's always things that you can improve in an API, but given that you can't realistically change everything to be the way you want it to, sometimes you're just forced to do things a certain way. Which is just one example of a perfectly valid reason to engage in this "bad" practice. :) (Another example: whenever performance is an issue, a case which I think you've been ignoring.) – user541686 Dec 15 '10 at 00:39

1 Answers1

17

Add this() in here:

public Foo(T1 item1) : this()
{
    Item1 = item1;
}

It's because you're assigning to a property, and the compiler can't deduce that the property only assigns a value to a variable; it could do other things before the instance is initialized, and that's not allowed because the structure might have garbage data. So you have to initialize it with the default constructor first, then do what you want.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • @Lambert: the question is, why can't the compiler see the obvious? The compiler does quite a good job of flow analysis in other cases. – Vlad Dec 14 '10 at 22:05
  • I didn't make the compiler, so I don't know. :) But it prevents other situations where the property isn't autogenerated, and where you try to use garbage data. Also, I believe this is likely a CLR issue, not a compiler issue -- the JIT might complain if you try to access a property before the instance is initialized, since it doesn't have the information that the compiler has immediately available to it. – user541686 Dec 14 '10 at 22:07
  • You might also be able to solve this by explicitly implementing your own default constructor. – Nick Larsen Dec 14 '10 at 22:24
  • 1
    That's not allowed for value types in C#, since there's no guarantee that they'll be called in some cases, such as when making an array. – user541686 Dec 14 '10 at 22:25
  • This will have to be done regardless if the struct is generic or not. But this is certainly the correct answer. – Bryan Dec 14 '10 at 22:26
  • Yes, forgot about the mention of generics. Thanks for pointing that out; yes, the generics part doesn't make any difference. – user541686 Dec 14 '10 at 22:28
  • I just looked it up again, there are no default constructors allowed for structs. Thanks for pointing that out. – Nick Larsen Dec 14 '10 at 22:32
  • 3
    @Vlad: Indeed, the compiler could have a rule that said that if the property called was an autoprop then we know that it has no effect other than to set the field. However, two things. (1) That's work, and we barely got auto props into C# 3 at all; they just barely fit into the schedule, and (2) that then means that changing an auto prop into a "normal" prop gives you this bizarre error that you have to put a this() call on your constructor. I agree that this is a bit clunky, but at least it obeys the principle that auto props are just like regular props. – Eric Lippert Dec 14 '10 at 23:19
  • 1
    @Eric: consistency with the regular prop case is a sound reason (at least for me), thanks. – Vlad Dec 15 '10 at 00:11
  • @Mehrdad: Why is it necessary to add `this()` for structs, but not for classes? Is it one of those oh-so-subtle differences between ref and value types? – Kyle Baran Feb 04 '13 at 21:18
  • 1
    @Danjen: There's no *inherent* reason -- it's just a consequence of how they designed the language and the runtime. – user541686 Feb 04 '13 at 21:24