From: Rhino on
On May 21, 4:12 pm, Rhino <no.offline.contact.ple...(a)example.com>
wrote:
> In the course of developing test cases for some of my classes,
> particularly  the classes that are static factories, I've developed some
> confusion about localization. Basically, I'm trying to figure out when I
> want to have separate constructor and getInstance() methods
>
> First, I hope we can all agree that, in an ideal world, every class which
> can produce text output - even if no text is produced per se, most
> classed would be capable of producing error messages for Exceptions -
> should be written so that it can produce that output in the languages of
> the users of those classes. So, if your utility classes are used in
> French-speaking countries, text output and/or error messages will be in
> French and so forth for other languages. Now, I know that many developers
> will not worry about that - after all, the whole IT field seems to be
> fairly English-centric - but I aspire to make all of _my_ classes locale-
> sensitive.
>
> Now, with the preamble out of the way, let's get down to brass tacks.
>
> Let's say that I want to make a static factory class locale-sensitive but
> I don't want to force the user to choose an explicit locale every time
> they try to use the class. That suggests to me that I go one of two ways:
>
> 1. Provide two private constructors - one that takes a specified locale
> and one that uses the default locale - and two corresponding public
> getInstance() methods, one of which takes a specified locale and one that
> uses the default locale. Then, if the user is comfortable with the
> default locale, they use the constructor that doesn't have a locale
> parameter, otherwise, they use the constructor that has a locale
> parameter and specify the locale of their choice.
>
> 2. Provide a single private constructor that has no locale parameter and
> a corresponding public getInstance() method. Also provide getLocale() and
> setLocale() methods so that a user can instantiate with the single
> getInstance() method and then use setLocale() to alter that locale if it
> is not to his liking.
>
> I thought I'd have a look at the Java API and see what happens there. I
> got something of a mixed bag. A handful of classes have getInstance()
> methods that take a Locale parameter, suggesting that they favour
> Approach 1. A handful of classes have setLocale() methods, suggesting
> that they favour Approach 2. However, the vast, vast majority of the
> classes have neither suggesting that they are NOT locale-sensitive and
> have no capability for changing the Locale at all.  
>
> So I thought I'd ask the learned people on this group for their thoughts
> on which approach they'd take when building classes that are meant to be
> locale-sensitive. I'm sure there are variations on the two approaches
> I've enumerated so I'm open to "none of the above" answers :-)
>
> Personally, I'm leaning towards Approach 2. Approach 1 requires doubling
> up of constructors and getInstance() methods and makes you reinstantiate
> the class if you want to change Locales. Approach 2 avoids those extra
> constructors and getInstance() methods and lets you change Locale by
> simply doing setLocale(). There may be negative aspects to that which
> aren't occuring to me though so I hope you will point those out if you
> see them.
>

I've learned a lot in this thread about different aspects of i18n/l10n
(internationalization/localization) and I still expect to learn a bit
more as people respond to my scenario about my little Color Converter
program.... I thank you all for supplying considerations I hadn't
thought of in the design decisions that go with i18n/l10n.

But I'd like to try to sum up a bit now. The conversation has gotten
sufficiently fragmented that I'm not sure what we would all agree on
with regards to the situation I am trying to resolve.

In a nutshell, I have some utility-type classes and I am trying to
figure out how they should best handle matters of Locale.

Notice that I said "utility-TYPE classes". I initially described these
as static factory classes but I'm no longer sure that they should be.

Until a few months ago, all of the methods in these classes were
static and there was no constructor for the class. I had some concerns
and asked about them on a thread here. I don't recall how to give a
URL for a Google Groups discussion so I apologize for not being able
to give you one but it was a discussion that started March 15 2010 and
was entitled "Design Question". In a nutshell, because I had a Locale
variable in the class, this was seen as an element of 'state" for the
class and therefore I was advised to change the class so that it had a
private constructor and a public static getInstance() method. I did
that and, in fact, had two of each: a constructor that took no
parameters and one that took Locale as the parameter, and
corresponding getInstance() methods. I understand why the 'state'
necessitated this kind of change now that I've reread that thread.

However, I find myself seriously doubting that Locale SHOULD be a
class variable after all. And if my reasoning is sound, which I hope
you will tell me, I may be able to go back to having all the methods
be static.

As I look at the classes in the Java API, only a tiny handful of them
have constructors that take a Locale as an argument and only a tiny
handful have setLocale methods. Assuming that the Java API is
considered well-designed by the Java community - and I have to hope it
is :-) - that tells me that the remaining 99.9% of classes are
expecting to provide any locale-specific information in only ONE
Locale. Furthermore, no class invoking the API is typically going to
want to get the information in more than one language at a go.
Essentially, the classes operate on the basis of the Locale defined by
the user.country and user.language properties. Therefore, if my
properties are set to English and Canada, that is the locale that the
JVM is going to try to find - of course it will settle for other
flavours of English if there is no specific en_CA resource bundle -
and use for any other locale-specific text. (DateFormats,
NumberFormats, and their kin handle the localization needs of those
special kinds of data.)

Providing a way to set a specific Locale and even to change that
Locale on the fly so that classes could potentially invoke the class
repeatedly for different Locales is simply overbuilding and is almost
certainly not necessary at all! (I say 'almost' in deference to Lew's
observations about there being no hard and fast rules, which makes a
lot of sense to me.) So I think I can dispose of Locale in
constructors (and their associated getInstance() methods altogether.
Likewise, I can omit and setLocale() and/or getLocale() methods from
my utility classes too. Methods that seek to get ResourceBundles will
simply seek them for the default Locale, as determined via
Locale.getDefault().

Does this all make sense so far? I sure hope it does because I think
I've got myself convinced :-)

The classes will still be fully locale-sensitive; I've proven that by
simply changing user.language and user.country to other values and
information comes out in the desired language just fine. (My
writeLocales() methods writes the display names of the Locales in the
language of the default locale so if my default Locale is en_CA, I get
them in English but if it is de_DE, I them in German, etc.)

As someone interested in the issue of supporting different languages
in a syste, I did some dabbling with the i18n stuff shortly after it
came out. I wrote simple apps that would display a list of locales and
let the user choose their favourite, then go back to the menu and
change them on so that information would be redisplayed in the
replacement Locale. I got in the habit of putting that kind of code in
many of my classes on the theory that I was making them more flexible
but I had never really given a lot of thought to how realistic this
was or how it conformed with the far better designed Java API. Now I
see that it is just unneeded frippery. If a class's methods really do
need to be able to change Locales on the fly, I think I'll be able to
write the code to enable that. But those needs should be few and far
between. For now, I think I should abandon any efforts to have
"dynamic locale switching" (for want of a better term) in my classes.

Am I on the right track here? Or am I throwing out the baby with the
bathwater?

Once we are agreed on that, I would like to follow up with a few
specific detailed questions but I'd like to get the fundamental
principle resolved first.

--
Rhino
From: Lew on
Rhino wrote:
> I was thinking more of cases where user input is faulty and could be
> corrected by the user. For instance, I have a little GUI-based "color
> converter" class: it has an input field where I type the hex
> representation of a Color, e.g. FFCC00, and it gives me the RGB
> representation, e.g. 25, 204, 0, in another field when I click on the
> Convert button. Now, if the user mistypes the hex reprsentation of the
> color, say FFCCZZ, the method that does the conversion detects that ZZ is
> not a valid hex representation of the Blue component of a Color, throws
> an IllegalArgumentExpection with text to that effect (the message is
> retrieved from a ResourceBundle to allow for internationalization) and
> then the try/catch block in the ColorConverter class displays that
> message in a JOptionPane so that the user knows what to fix.
>
> I don't log any of this and certainly don't show the user anything like a
> stacktrace; just the message from the ResourceBundle.

I recommend against popping a dialog or other window in a try/catch block.

Try/catch is for getting out of a mess. If there's a lot of code in there,
you risk getting in another mess.

You also don't separate concerns enough, in this case the "happy-path" logic
from the error-message logic.

Plus, your validation is likely, or should be likely to be off the Event
Dispatch Thread (EDT), since validation isn't really a graphic action but a
logical one. That involves thread coordination from inside a try/catch, not
so good.

Let the catch block cause a return from the validator, and let the caller of
the validator decide where to go next.

--
Lew
From: Arne Vajhøj on
On 25-05-2010 14:57, Rhino wrote:
> But I'd like to try to sum up a bit now. The conversation has gotten
> sufficiently fragmented that I'm not sure what we would all agree on
> with regards to the situation I am trying to resolve.

> However, I find myself seriously doubting that Locale SHOULD be a
> class variable after all. And if my reasoning is sound, which I hope
> you will tell me, I may be able to go back to having all the methods
> be static.
>
> As I look at the classes in the Java API, only a tiny handful of them
> have constructors that take a Locale as an argument and only a tiny
> handful have setLocale methods. Assuming that the Java API is
> considered well-designed by the Java community - and I have to hope it
> is :-) - that tells me that the remaining 99.9% of classes are
> expecting to provide any locale-specific information in only ONE
> Locale.

Note that the Java API is a low level API and localization is
most relevant for higher level business app code.

The huge majority of Java API classes does not have any
need for localization at all.


> Furthermore, no class invoking the API is typically going to
> want to get the information in more than one language at a go.
> Essentially, the classes operate on the basis of the Locale defined by
> the user.country and user.language properties. Therefore, if my
> properties are set to English and Canada, that is the locale that the
> JVM is going to try to find - of course it will settle for other
> flavours of English if there is no specific en_CA resource bundle -
> and use for any other locale-specific text. (DateFormats,
> NumberFormats, and their kin handle the localization needs of those
> special kinds of data.)
>
> Providing a way to set a specific Locale and even to change that
> Locale on the fly so that classes could potentially invoke the class
> repeatedly for different Locales is simply overbuilding and is almost
> certainly not necessary at all! (I say 'almost' in deference to Lew's
> observations about there being no hard and fast rules, which makes a
> lot of sense to me.) So I think I can dispose of Locale in
> constructors (and their associated getInstance() methods altogether.
> Likewise, I can omit and setLocale() and/or getLocale() methods from
> my utility classes too. Methods that seek to get ResourceBundles will
> simply seek them for the default Locale, as determined via
> Locale.getDefault().

That strategy may work OK for fat client apps. It will not work
well for the server side code in web apps.

Arne

From: Arne Vajhøj on
On 25-05-2010 08:30, Tom Anderson wrote:
> On Mon, 24 May 2010, Arne Vajh?j wrote:
>> On 24-05-2010 08:12, Tom Anderson wrote:
>>> On Sun, 23 May 2010, Lew wrote:
>>>> Read /Effective Java/ (2nd ed.), "Item 57: Use exceptions only for
>>>> exceptional conditions", and the rest of section 9.
>>>
>>> No.
>>
>> It is always good to read opinions from qualified people even
>> if you disagree with them.
>
> True. But i don't have that book, and i'm not about to rush out and buy
> it because it contains advice i disagree with! If i come across a copy
> of it (i might be able to borrow one from the tribe upstairs at some
> point), i will certainly read this.

There are other good sections in the book as well.

Put it on your Christmas gift wish list!

Arne
From: Arne Vajhøj on
On 25-05-2010 01:05, Patricia Shanahan wrote:
> Arne Vajh�j wrote:
> ...
>> But when it is user input, then it is really not that exceptional
>> with format errors.
>>
>> If it was reading a file that was generated by a system, then I
>> would consider a format error exceptional.
> ...
>
> Reading these two paragraphs, I think the difference between us is the
> viewpoint we use in evaluating "exceptional". You seem to be using a
> whole program viewpoint. I look at it much more locally.
>
> Typically, in my code, a String conversion method has no idea whether
> the String it is converting came from a GUI TextField, an input file
> edited by a user, or a file that was generated automatically. Its design
> cannot and should not depend on whether an inability to do the
> conversion is due to an error in a user input or in a system generated
> input.
>
> Instead, I look at the issue from the point of view of the method I'm
> defining. What is the primary function of this method? If its primary
> job is conversion of a String to some other type of value, and it cannot
> do it because of incorrect content in the String, it throws an exception.
>
> Of course, somewhere in the call stack there is a method that does know
> where the unconvertible String came from. If the condition is not
> exceptional from its point of view, it should catch the exception and
> take appropriate action.

That is a core problem of the domain logic exceptional criteria. If we
are in the low level API, then we don't have a clue about what is
exceptional.

I would say that from a purity perspective "unknown" would favor
return value over exception, because I like the "convert return
value to an exception at a higher level" a lot more than
the "convert exception to return value at a higher level".

But the practical perspective this situation would favor
exception, because the call stack is often deep and the
exception is simply an easy way to get out to where
it is needed.

Well - I guess there is a reason that programmers will not
be replaced by AI programs soon.

:-)

Arne