On Thu, 24 Dec 2015 16:56:54 +0100, Luc Maisonobe wrote:
[...]
When our users build a large application, they rely on numerous
different libraries and tools, both open-source and proprietary.
These libraries do have standard interfaces so they can be used
together. The Java standard library is one of them. the
getLocalizedMessage method is specified there. Many of the
libraries
and tolls user will assemble rely on it. Deciding that for the sake
of Apache Commons Math we do not abide to this and decide that all
other existing code should adapt to a different design is a clear
no go for me.
Does the JVM abide by this?
Yes,
Then, how to explain that the following code
---CUT---
for (Locale loc : new Locale[] { Locale.ENGLISH, Locale.FRENCH
}) {
Locale.setDefault(loc);
System.out.println("Locale=" + loc);
try {
final int a = 2;
double r = a / 0;
} catch (Exception e) {
System.out.println("JVM toString(): " + e);
System.out.println("JVM getLocalizedMessage(): " +
e.getLocalizedMessage());
}
try {
throw new NotStrictlyPositiveException(-1);
} catch (Exception e) {
System.out.println("CM -> toString(): " + e);
System.out.println("CM -> getLocalizedMessage(): " +
e.getLocalizedMessage());
}
}
---CUT---
produces this output:
---CUT---
Locale=en
JVM toString(): java.lang.ArithmeticException: / by zero
JVM getLocalizedMessage(): / by zero
CM -> toString():
org.apache.commons.math4.exception.NotStrictlyPositiveException: -1 is
smaller than, or equal to, the minimum (0)
CM -> getLocalizedMessage(): -1 is smaller than, or equal to, the
minimum (0)
Locale=fr
JVM toString(): java.lang.ArithmeticException: / by zero
JVM getLocalizedMessage(): / by zero
CM -> toString():
org.apache.commons.math4.exception.NotStrictlyPositiveException: -1
n'est pas strictement plus grand que le minimum (0)
CM -> getLocalizedMessage(): -1 n'est pas strictement plus grand que le
minimum (0)
---CUT---
?
as well as JUnit, Eclipse, Maven, and all tools I use.
The point is that CM code is not user-level code: requirements that
have nothing to do with mathematical algorithms should not have
top-level priority here. This is what has always biased this
discussion.
This issue is not one of a design that would not use
"getLocalizedMessage"
just that CM is not the place to do so. CM throws exception; caller
handle them in any way they want.
For example:
try {
// ...
// Use a low-level library: do not let foreign exceptions bubble
up.
try {
CMAlgo algo = new CMAlgo();
algo.run();
} catch(RuntimeException e) {
if (e instanceof CMAlgoException)
throw new MyCMAlgoException(e);
} else {
throw new MyUnexpectedException(e);
}
}
// ...
} catch (MyRuntimeException e) {
LOG.error(e.getLocalizedMessage()); //
}
Times thousands times as CM call in complex applications that do
a lot of math occur everywhere.
But you do not have to do the above a thousand times only at the point
where you need to extract the message.
public class MyApp {
public static void main(String[] args) {
final Locale loc = new locale(args[0]);
try {
final MyApp app = new MyApp(args[1], args[2]);
app.run();
} catch (RuntimeException e) {
if (e instanceof MathException) {
LOG.error(translate(e, loc));
exit(1);
}
}
}
private void run() {
// ...
}
}
Look at it, it is *only* one field with its setter and two one line
methods defined in the top level MathException class in order to
abide to a standardized interface widely used.
OK, and I also worked a lot to make it less of a duplication mess.
I don't think that I can oppose you on these 3 lines given all the
work you do. ;-)
Thanks.
But once and for all, I'd like that we acknowledge that this
decision
has nothing to do with good design.
I don't claim this to be good design. It is only meant to be
practical
and not cumbersome for users.
If it is not practical or cumbersome, then it is not good design. :-)
The list of translated type could still be maintained here, in the
same
way the unit tests and user guide are.
I'm not sure. If we decide to delegate the localization to the user
and simply provide the two one-liners hook to call it, then we can
remove the list of translated types and let the user handle it. It
would also allow them to support additional languages. For now,
we support only one, we could drop it using this delegation
mechanism.
I just meant it as a service to the international of users. :-)
We could centralize the translations as is done for other resources
like
the userguide.
This is fine with me.
I'm also fine if we don't provide this service!
[...]
The setLocalizer method is not a computation algorithm expected
to be called millions of times and that therefore could experience
clashes in case of concurrency.
I was not considering this case.
Just the inherent potential problem of a global setter for a
low-level library.
Do you know of other libraries that do such a thing?
At least Orekit (for something called DataProvidersManager, which
is a singleton and uses initialization-on-demand holder idiom),
but this example is biased ;-)
Another example would be log4j2, with the MainMapLookup singleton
and its setMainArguments method that is intended to be called once
with the main arguments, but nothing prevents it to be called
at will (and there are no protections against concurrent accesses).
There is also the JSCH library which uses a private static map for
config and has setters and getters allowing to change its content
(here, there are some protections agains concurrent access).
In many case, as long as you need to store some configuration,
you end up with either a static field (often private and
with getters/setters) or an instance field in a singleton.
It happens in the best libraries.
IMHO, this (mis)feature cannot be what makes them "best".
Why is "slf4j" configured the way it is?
Best regards,
Gilles
[...]
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org