immutable, cloned, or mix?

I have a class Vector2 (which contains a double “x”, a double “y” and some methods), which is widely used by my game. At the moment some methods that use it accept/return a clone, and some a reference. This is confusing and inconsistent, so I want to change it. Now, however I don’t know which system to choose:

  • Make the class immutable and always pass a reference
    ++ Good for memory
    – Many new allocations if a vector needs to be changed every frame (because it can’t be modified)

OR

  • Keep the class mutable, but always make a clone when accepting/returning an instance of it
    ++ It can be modified directly (for example, the position of an object which changes every frame
    – Every copy takes memory, and clones need to be made every time it’s passed to another method

So, what do you think is the fastest/best way?

Try both, profile the code and compare the results? I doubt there will be any big difference in performance. I would choose the one which produces cleaner code.

AFAIK, the JVM can optimize unnecessary defensive copies away, so using return new Vector2(v); might not allocate a new object if the returned object is not modified by the caller. Could somebody verify this assumption?

Not sure what you mean by ‘and some a reference’, everything is passed by value in java - even references…

Do you mean that some of your methods mutate their parameters, and others return a new object, leaving the paramters unchanged?

A common approach to this is to add an additional ‘target’ (output) parameter into which the results of the operation will be stored.
This approach eliminates both the object creation overhead, and the mutating of method input parameters.

[quote]Not sure what you mean by ‘and some a reference’, everything is passed by value in java - even references…
[/quote]
You pass a reference to a Vector2 instance. The reference is the value

[quote]Do you mean that some of your methods mutate their parameters, and others return a new object, leaving the paramters unchanged?
[/quote]
No, I have for example a method like this:

public void setPosition(Vector2 v) {
  this.pos = v.clone();
}

but also

public Vector2 getPosition() {
  return this.pos;
}

public void add(double x, double y) {
  this.pos.x += x;
  this.pos.y += y;
}

public void move() {
  someobject.getPosition.add(23,34);
}

I’m sure you will agree this isn’t very consistent

[quote]I would choose the one which produces cleaner code.
[/quote]
Then I would choose the first, since a programmer creating methods involving my class will not need to think about making a clone

In your example I’d say the following is where your problem stems:-


public void setPosition(Vector2 v) {
  this.pos = v.clone();
}

If getPosition() is going to return a reference to the encapsulatede member, then setPosition(…) must not re-assign the object to which said member refers.
The above should be changed to something like:-


public void setPosition(Vector2 v) {
  this.pos.set(v);
}

there are more problems in my current approach. for example:

  • getposition returns a reference so it can be modified directly (e.g. to move an object)
  • however, an unaware programmer might store the return value somewhere, then later modify it (not knowing that this is the original instance) and get inexplainable bugs

i wish there were C# structs in Java…::slight_smile:

You can’t write library code that prevents errors in user code.
The above scenario could occur in any application, written against any api.

The important thing is that your API must have a clearly and concisely defined specification, and it must meet said specification precisely.

It depends on the usage of the type. I personally make vectors mutable with a copy constructor.

The most ‘correct’ way would be to make Vector2 immutable because it has value-type semantics - like String, Integer etc… As opposed to reference-type semantics like Player, Level etc.

This will impose some performance overhead, but then we do ok with String, Integers being immutable.

This way your code would look something like this :


public void setPosition(Vector2 v) {
  this.pos = v; //Vector2 is immutable so no need for defensive copying
}

public Vector2 getPosition() {
  return this.pos; //Vector2 is immutable so no need for defensive copying
}

public void add(double x, double y) {
  this.pos = this.pos.add(x, y); //Vector2.add() creates a copy
}

thanks, D.

But you’re not making 1,000’s of string calculations per frame and for larger operations of concatenating strings you would instead use a string buffer! And what benefit is there to making a vector immutable? It is a type of object that is referred back to, so it’s usage does not encourage immutability and instead encourages mutability.

I “solved” this problem by having Vector2f (etc) implement two interfaces, ReadableVector2f and WriteableVector2f. When I don’t want people to think they can edit the vector directly I return a ReadableVector or pass a ReadableVector in and copy it into an existing Vector2f. I use this consistently throughout nearly all of my code.

The technique is not foolproof (a cast will thwart it) but it avoids cloning and avoids garbage, and so it’s good and fast.

Cas :slight_smile:

Interesting approach!

From what little I know of the Sun Swing API, Sun circumvented the problem by not getting/setting objects. The “Coordinates” class has been deprecated.

Strings get special handling by the VM though (both from object pooling and operator overloads). Without them the overhead of your custom vector class is going to be larger, and the syntax to manipulate them is considerably more unweildy.

I use the same method as Cas, it might not be foolproof (especially if you hang on to an ImmutableVector2f for longer than expected) but it does a very good job of signally the intentional use. Bung in a simple copy c’tor to create a mutable version from an immutable vector and it’s quite clean syntactically too.

Does hotspot optimise away the invokeinterface instructions?
to the cheaper a) invokevirtual,
and cheapest b) invokespecial ?

If not, I can imagine such an approach would have a significant runtime overhead,

I used that too, but in comparison to immutable types I think it’s still too mutable. It works fine for types you create and return (which shouldn’t be changed by clients), but it doesn’t free you completely from making defensive copies and it doesn’t make those objects threadsafe.

I’m using the immutable way now, and it seems to work fine :slight_smile:

Correct. If you receive an object the interface semantics of which indicate immutability then that doesn’t say anything about what could happen in reality. Which is why immutable types must be final.

There’s certainly a case for either approach, but immutable objects are usually easier to live with and less problematic, whereas mutable objects are usually somewhat faster (and maybe a bit more convenient in some situations of limited scope).

A side note on value types in C#, they’re probably kinda nice with regards to performance, but they’re one reason why C# is quite a bit more complex to use than Java.

The main benefit is robustness, particularly in a multithreaded environment.

Ultimately it’s an OO guideline that classes with reference semantics should be immutable. There will be a performance penalty (particularly if there are more reads than writes, although if many more writes than reads, immutability can be faster because of less need of synchronization) and games are a perfomance sensitive domain, so it may be a good decision to make them mutable. Your choice.

thanks, D.

Well that’s not entirely true since there are many cases where synchronization is not needed. One thing that many people tend to do is over synchronize ensure thread safety for things that will not be used in such a way where they will be of any concern. Bad design can make you enforce strategies in the wrong time, like overusing design patterns!