-1

Imagine I have a Point struct with X and Y coordinate. Now i have constructor: Point (int x, int y).

Question: Should I also add method called Point.SetXY (int x, int y)?

example:

// I have some point
point = new Point (5,5);

// and I wanna change some values
point = new Point (7,7);

// or maybe should I do like this?
point.SetXY (7,7); // is it faster?

For classes i know it is faster because u dont need to create new instance on heap etc.

But maybe for structs it doesnt matter?

apocalypse
  • 5,764
  • 9
  • 47
  • 95

3 Answers3

4

Unless there is a very good reason for it, I would suggest having your structs immutable - just create a new struct with the new X and Y values when it is required.

For an example of why mutable structs can be counter-intuitive (or evil (depending upon metrics pertaining to creative license)) Eric Lippert has a very good blog post on the subject.

Community
  • 1
  • 1
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
  • I'm using structs like that: I have a class 'Bullet' (example), and inside this class i have a 'Point position'; So i think im safe, because if alwyas reffer to this field by class. – apocalypse Feb 21 '12 at 16:16
  • That blog post deals with structs whose methods mutate `this`, which can indeed be problematic. Some people seem to regard the fact that `this`-mutating structs are problematic, or that some very early compilers could generate silly code when structs had exposed fields, as an argument against mutable structs in general, but I just don't see it. – supercat Feb 22 '12 at 20:08
2

Ithink you can achieve it by

point.X = 7;
point.Y = 7;

This is fastest

Shiplu Mokaddim
  • 56,364
  • 17
  • 141
  • 187
  • I know this is fastest, but I preffer 1 line of code to set it. – apocalypse Feb 21 '12 at 16:13
  • OK i did test now, both styles are equals, setter style and constructor style for 2000,000,000 loops = 17 seconds. Your style to acces X and Y directly = 5 seconds, so your answer is the best. Thank you. – apocalypse Feb 21 '12 at 16:36
  • @SLaks I think I have updated my answer before I even see you comment. – Shiplu Mokaddim Feb 21 '12 at 17:07
  • @Slaks: Why is it "very wrong"? In every case where a decent compiler will allow it, `someStruct.Field = newValue` has semantics which are equivalent to what `someStruct = someStruct.WithChangedField(newValue)` should do, except that the former will be faster, and the semantics of the former in multi-threaded scenarios are better specified than those of the latter (e.g. threads which write directly to different fields will not interfere with each other, but threads that simultaneously try to replace a struct with instances that are changed in different ways will interfere). – supercat Feb 22 '12 at 18:18
  • 1
    @SLaks: All non-trivial structs in mutable storage locations (i.e. those which can ever hold any value which can be distinguished from the zero-initialized default) are mutable. All structs in immutable storage locations are immutable. Besides, if one has a mutable storage location of a struct type which permits convenient rather than clumsy mutation, regardless of whether one thinks the type should have been designed that way, why should one not mutate it in the manner for which it was designed? – supercat Feb 22 '12 at 18:49
1

Structs with exposed fields are not evil. While some really old compilers would accept code like:

List<Point> myList;
myList[4].X = 5;

which would copy myList[4] to a temporary struct, modify the field X of that temporary struct, and then throw the modified struct away, and making structs immutable was a way to ensure that the compiler would squawk at the above construct, a better way of ensuring that a compiler would squawk at such code would be to change the compiler to forbid writes to fields of temporary structures. Given that such code has forbidden by compilers for a long time, structs with exposed fields are often the best way of holding things that have a fixed number of independent data items (e.g. Point, Rectangle, etc.)

What are problematic are structs in which functions other than constructors or property setters modify this. While compilers will recognize that a write to someStructProperty.someField is attempting to modify someStructProperty, and will forbid it in cases where such modification wouldn't actually work, there is unfortunately no means for the compiler to know that someStructProperty.MutatingFunction() would attempt to modify a temporary instance of the struct. The compiler would thus permit such code even though it couldn't actually work as intended. What I would suggest as a remedy in cases where a function is supposed to modify a struct "in place" would be to define a static method which takes an instance of the struct as a ref parameter. For example, SetPointXY(ref Point pt, int x, int y). The compiler will regard the passing of a struct as a ref parameter as an attempt to modify that struct, and will only allow it in situations where it will actually work.

Note that from a performance standpoint, the only time that writing struct fields individually wouldn't be the fastest way to update a struct would be when one is making most of the struct match either the default value or some other pre-existing struct. There may be some such cases where it would be faster to overwrite a struct with a pre-existing instance and then write the fields that should hold something different, but in general I would suggest that one should use methods or functions to update structs only when code which does so would be more readable than code which sets fields individually. If AreaCode is a public field of type PhoneNumber, the effects of somePhoneNumber.AreaCode = "847"; are far clearer than the effects of somePhoneNumber = new PhoneNumber("847", somePhoneNumber.Exchange, somePhoneNumber.Number, somePhoneNumber.Extension);. Among other things, one would have to study the entire structure to know whether the latter would change any fields other than AreaCode. On the other hand, if one's goal was in fact to have a structure which was blank except for some all-new data, using a constructor or factory method might help make clear the fact that one was doing so; if one simply overwrites all the fields of the struct individually, one would have to study the whole struct to know that there weren't any fields that would be left unchanged.

supercat
  • 77,689
  • 9
  • 166
  • 211