views:

257

answers:

6

When you design immutable classes, do you prefer:

Layer.ColorCorrect ( layer )

or

layer.ColorCorrect ( )

To me #1 seems more intuitive, instead of #2, which looks like it modifies the object that's referenced, since it's an instance method, it might as well change the internals, right?

+6  A: 

I would prefer to use an instance method, but choose the name to reflect the fact that it doesn't change the existing instance. For example:

layer.AfterColorCorrection()

or

layer.WithCorrectedColors()

Using static methods becomes tiresome pretty quickly. Also, if you make it clear to your users that the type is immutable, they should get the hang of that pretty quickly. Everyone gets tripped up by String.Replace not actually replacing anything in the target - but they don't keep making the same mistake. With better names as well you should be fine.

I asked a related question about "adding" to an immutable list - the best solution there IMO is to use "Plus" rather than "Add"; again, it doesn't imply that the original value is changed. You may find other answers to that question useful.

Jon Skeet
Thanks Jon. Your question is very helpful. Looks like you are also very concerned about the best possible practices :)
Joan Venge
I like to think about best practices, certainly. You'd have to ask my colleagues to what extent my production code reflects them though...
Jon Skeet
lol. Personally I try to use whatever I learn asap so I don't forget about integrating them to my work :) Just out of curiosity, are you using C# for most things you do at work?
Joan Venge
No, unfortunately we don't use C# much - my main project is in Java. My 20% project is porting Protocol Buffers to C# though, so that's fun :)
Jon Skeet
Sounds like fun :) Thanks Jon.
Joan Venge
Downvoters: please leave a comment. It makes it much more useful.
Jon Skeet
@Jon: Who would downwote this is beyond me. But don't worry man, I am by your side :)
Joan Venge
+1  A: 

Typically you'd have something like:

layer = layer.ColorCorrect([required parameters here]);

This would be similar to

mystring = mystring.Substring(1, 2);

Where a new string is created that is the substring of the first.

Neil Barnwell
Thanks, you mean params as in params keyword to pass other values?
Joan Venge
No, just as a placeholder to signify that there might be parameters.
Neil Barnwell
A: 

Its absolutely against OOPS principles to write static method, pass an instance and make it almost look like procedural programming like "C". Also in 1st method you are typing Layer twice, which kind of makes it ambiguous to reader.

Akash Kava
Thanks. What's OOPS? Also can you please tell why it's not good practice. Also the layer var was just an example. What if it was something like, normalMap, and then passed to Layer.ColorCorrect which would tell the programmer that it's a layer.
Joan Venge
OOPS means object oriented programming system.Usually if class's members need to be modified, you create properties by making accessors and mutators. Most of the functions may never modify anything, still they are coded as instance methods.
Akash Kava
A: 

Using the static method kind of rules out inheritance, doesn't it? That seems like a pretty significant limitation.

Ken
+4  A: 

My personal preference is to focus on making it visible that the type is immutable. For instance I would call it ImmutableLayer vs. Layer. Or if for some reason Immutable is not a good word to prefix the name with I will add an attribute to the class indicating it's Immutable (attribute is added in both cases).

This has it's ups and downs. The up is it gives a central place to check for immutabliity. Just take a quick peek and the type and you're in business. There is no need to learn new method names or conventions. The downside to the approach is that you can't tell in certain type infererence scenarios that the value is immutable. For instance, this code works just as well for an ImmutableCollection and a normal List

var col = GetTheCollection();
col.Add(42);

However I do not like to change method names to accomidate immutability. The reason being that it is a problem you will have to solve repeatedly. Naming things should be easy, but it's incredibly difficult some times. Think of all of the types you've ever wanted to make immutable. Imagine having to find new names or conventions for every mutating method on those types. It's a non-trivial task and you will spend a lot of time educating users on those new conventions.

My dream scenario though is to find a way to increase the visiblity of immutable types. Because that's the real problem here, not knowing the type is immutable. Currently there is no good way to do this for all scenarios, but I'm hopeful for the next version of the languages / IDE.

JaredPar
+3  A: 

@JaredPar has the best answer, IMO, but none of the answers are great, because today there aren't any "great" solutions for this. We need better tooling, and design guidelines that evolve in concert with the tooling, to better deal with the rising popularity of immutable objects.

@JonSkeet's answer works well in an API context where nearly everything is mutable, but it falls down as immutable objects become the norm (as all the methods have long awful names).

The "best" name depends on the code context you're surrounded by. The only strategy that I think is viable across the spectrum of "mostly mutable" to "mostly immutable" contexts is the one Jared mentions, where the tooling makes it obvious whether a given object is immutable, and then every method has the 'imperative' name (e.g. o.Add) which either side-effects the receiver object (if it's mutable) or returns a new object (if it's immutable).

(Aside: sadly, "fluent" effect-ful APIs like "StringBuilder" mean you can't just look at the method signature to decide if the receiver object immutable, as such examples 'return this' to be fluent, giving the same signature as 'return a copy'.)

Brian