commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From luc.maison...@free.fr
Subject Re: [math] Mutable "Vector3D"
Date Fri, 24 Apr 2009 15:00:23 GMT

----- "Gilles Sadowski" <gilles@harfang.homelinux.org> a écrit :

> Hello.

Hi Gilles,

> 
> Would you consider implementing a _mutable_ 3D-vector class?
> A crude benchmark which I just did shows that re-using the same object
> is
> always (if sometimes only slightly) more efficient than re-creating
> it.

3D vectors have been changed from mutable to immutable for both robustness and efficiency
reasons ...

When small benchmarks are set up, the overall context is completely under control and instances
are created/used/reused in a specific use case, corresponding to a simplified view. In these
cases, instances modification appear faster and manageable.

Real life situations with complex systems are not that simple.

Here is a summary of a real case problem, encountered on an operational library using commons-math
and Vector3D before it was turned to immutable. In a complex application with lots of data
sharing and time-dependent data, we wrote something like:

  Vector3D computeMotion(Trajectory trajectory) {
    Vector3D initialPosition = trajectory.getCurrentPosition();
    complexAlgorithm.processTrajectory(trajectory, targetDate);
    Vector3D finalPosition   = trajectory.getCurrentPosition();
    return finalPosition.subtract(initialPosition);
  }

The team developing computeMotion and the team developing Trajectory worked apart from one
another.

With mutable vector, you must be sure the two teams are aware that at each interface they
must really know who is responsible for the data, the caller or the callee. They may decide
that getCurrentPosition should build and return a new vector, which belongs to the caller
which can do what it wants with it, including modifying it. In this case, two vectors are
built since getPosition is called twice and processTrajectory has no implementation constraint.
They may decide that the getCurrentPosition should return a reference to an internal vector,
then computeMotion should be rewritten to clone initialPosition before finalPosition is retrieved.
They should also know if the clone must be created before or after the processTrajectory call
because the internal reference may be modified internally. Failing to have a very precise
interface definition which includes the responsibilities at each level leads to difficult
to find bugs.

In order to avoid these bugs, you often resort in using defensive programming and adding a
copy yourself, just in case the other team did not do its job properly. In some case, when
what you develop is by itself an intermediate library and you don't know how the instances
you create will be used, you *must* do this copy.

This leads to a strange result: you have a potentially buggy code if one of the team forgot
to do defensive programming properly and you have a code that is really inefficient just because
everybody copies everything even when in fact it is not needed.

With immutable object, on the other hand, you really don't have to worry at all. People cannot
change the object whatever they do, so you just keep references around and create new instances
when you want to change one coordinates. You cannot do otherwise and don't rely on programming
rules or developers being smart. There are much fewer bugs and since new instances are created
only when needed, at the end you have not that much allocations.Here is a good article about
immutable objects: <http://www.ibm.com/developerworks/java/library/j-jtp02183.html>

At the end, it appears that for complex applications with several layers, there are more copies
and allocations with mutable objects than with immutable objects!

Another point to note is that the generational garbage collectors work better with really
short lived objects. So small immutable instances are handled quickly and allocation should
not be feared. It is efficient now, see <http://www.ibm.com/developerworks/java/library/j-jtp09275.html>.

The points above are not theoretical one. Vector3D was mutable and it cost us weeks of works
at that time to track difficult bugs in a complex application. This was not a simple problem
of communication: I was involved in all teams from commons-math to high level application,
the rest of the team was just around me and we exchanged lots of information. After we changed
to immutable, all problems were gone and we didn't notice any performance drawback. In fact,
another team in another project facing huge performances problems looked at what we have done
and changed also their objects to immutable: they got significant performance improvements
after that change because their code was copying everything beforehand and it was not needed
anymore afterward.

Luc

> 
> [I can help with the editing work.]
> 
> Best,
> Gilles
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Mime
View raw message