commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Luc Maisonobe <>
Subject Re: [Math] Fluent API, inheritance and immutability
Date Tue, 13 Aug 2013 18:04:41 GMT
Hi Gilles,

Le 13/08/2013 18:46, Gilles a écrit :
> Hello Luc.
>> Hi Gilles,
>>>> > [...]
>>>> [...]
>>>> <side rant>Historically, we did not care about thread-safety at all
>>>> in [math], assuming the standard use case was *always* going to be
>>>> one instance per thread.  The statistics aggregators are an example
>>>> where multithreaded access makes sense, but this is much more the
>>>> exception than the rule in [math].  I would really like to get clear
>>>> on which classes really need to be threadsafe themselves rather than
>>>> blindly assuming that all do and insisting that everything be
>>>> immutable so that we don't have to think about how to make things
>>>> threadsafe.</side rant>
>>> We would be more able to advance if we consider that "threadsafe
>>> and "immutable" are _not_ interchangeable.
>>> We have seen (in Commons Math also) that immutability can provide
>>> thread-safety in a cheap way. Immutability is mostly easy to
>>> implement when an object's fields are initialized with data that is
>>> guaranteed to not be held by another object, and whose accessors
>>> will forbid modification.
>> Immutability is not used only for thread safety.
>> It is an interesting property even for single threaded applications and
>> more so for applications that are built from several layers developed by
>> different teams (which is obviously the case for  [math] as we only
>> develop the lowest layer.
>> Without immutability, developers at upper levels do not only have to
>> know the API, they also have to known the gory details of *all*
>> underlying levels and how the manage their input. Otherwise, they need
>> to perform copies by themselves for defensive programming, and often
>> forget to do so.
> You don't have to convince me that immutability is a nice feature; I try
> to have it everywhere I can. :-)
> But by actually trying to have it _in the context the fluent API paradigm_
> I discovered the hard way that it is not always nice (hence this thread).

OK. I thought you were speaking about immutability on a broad scope. My bad.

> Looking on the web about fluent API, most design/usage/examples do not
> provide immutability: the primary purpose of "fluent" is to chain
> on-the-fly modifications of an object's properties. [This is the complete
> opposite of immutability!]

Well, as the fluent API return an object, there is no reason it is the
same as the initial one. It is just like String.trim() returns a new
instance and does not strip the whitespace within the original instance,
which remains immutable.

> Then you can mitigate that by having a helper class (aka "builder") that is
> mutable, will collect all the changes, and then create an immutable
> instance
> of the "interesting" class).
> Again, this is a nice trick, but does not get along well with class
> hierarchies (cf. a question I asked before in this thread: How to combine
> the builders for all the levels of hierarchy?).
> One solution is to duplicate all setter "withXxx" methods at all levels of
> the hierarchy: huge duplication and plenty of potential copy/paste bugs.
> Also, it's not clear to me what exactly is the problem with upper levels
> in this particular case.
> Do we need to forbid further calls to "withXxx" methods?

I don't know. Let's try with your own interpretation and we will see.

> Also, I've indicated that a fluent API that will create a new instance
> at every call to "withXxx" can be completely counter-intuitive (and the
> source of "subtle" bugs too).

It should surely be documented, but this is a nice feature for me. It
allows easy copying as a side effect when you really want to set up
something from a prototype instance. The case Evan wrote about is an
example of the use case I have in mid: you start by preconfiguring part
of the algorithm, and at the end you duplicate this prototype in several
instances that will have only one slight modification each.

> This is related to the previous point: immutabilty or unmodifiability?
>>> Alois, it seems that "final" is (was?) useful for performance
>>> reason. [But again, this would probably be noticeable only with
>>> many allocations. Is there such a case for optimizer objects?]
>>> However, designing a class to be immutable is not always cheap. An
>>> example is the combination that is the subject of this thread; here,
>>> "costly" means: a lot of repetitive code lines[1], which could be
>>> easily avoided by dropping immutability, without loosing anything
>>> because:
>>> 1. the code is _not_ threadsafe anyways (with or without "final"),
>>> 2. the code could be made thread-safe, with or without "final".
>> Yes, but this only a part 'and I think a small part) of the deal. I
>> really think we should do it, even if it is costly from a development
>> point of view, even for single threaded applications, just for the
>> better safety it provides for upper levels. And yes, I know this is not
>> sufficient to get completely safe code, but it is really a *big* step
>> forward and helps developers of upper layers to concentrate on other
>> things.
> IMHO, code duplication always indicates that _something_ is wrong.
> It might not be obvious to discover what; but the right solution quite
> often entails that duplication is eventually eliminated. So: better not
> to introduce it in the first place.
>>> Hence, I think that when the functionality is well circumscribed,
>>> and it is easy to make everything "final", it's worth it. But when
>>> it's not that easy, we should indeed not insist on it[2] without
>>> 1. use-cases that show the need for multi-threaded usage of the
>>>    class, and
>>> 2. providing proof that immutability does indeed bring thread-safety.
>> I don't agree with 2, for the reasons above (we don't use immutability
>> only for the sake of thread safety).
> It would really help me to see how the current design in
>  o.a.c.m.fitting.leastsquares
> is "dangerous".

I don't think it is dangerous. I thought you were speaking on a broader


> Thanks,
> Gilles
>> best regards,
>> Luc
>>> I still think that CM should care about multi-threading (reasons
>>> detailed in other posts) but we should focus on tasks where the
>>> developers can readily _measure_ the benefits rather than spend (a
>>> lot of) time designing complex schemes which are not required by
>>> common use-cases.
>>> In addition to "stat", a few other CM areas where MT is of direct
>>> application are: FFT, Genetic Algorithms, Machine-learning, ...
>>> Regards,
>>> Gilles
>>>> > [...]
>>> [1] Cf. diff (in recent commits of optimizer classes in package
>>>     "o.a.c.m.fitting.leastsquares") between mutable and immutable
>>>     versions of the code.
>>> [2] Because we loose something on the "simplicity" side.
> ---------------------------------------------------------------------
> To unsubscribe, e-mail:
> For additional commands, e-mail:

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message