Rhino wrote:
In all honesty, I hadn't even thought of SortedMap when I wrote the
code again the other day. I just knew that I wanted the result to
be in alphabetical order, not random the way that
Locales.getAvailableLocales() provides them. The article on the Map
interface pointed out that TreeMap would assure that I had
alphabetical order so I went with that. Now that you've reminded me
about SortedMap, I can see the merit of it. It's not much different
than TreeMap but it does give those additional features,
WTF are you talking about? I got lost in your antecedent-free
pronouns. Are you referring to the methods in 'TreeMap' that are
not implementations of 'SortedMap' methods?
As for 'SortedMap' not being "much different [from] TreeMap', well
that makes perfect sense since 'TreeMap' implements 'SortedMap'.
OTOH, some might say that an interface in some ways is always "much
different" from a concrete class, but that difference is the basis
of the recommendation to move to a wider ("looser") type.
like range operations. I don't see those as being _necessary_ for
my humble little getLocales() method, which I'm really just writing
for myself, but some future user of the class could conceivably
benefit from those extra features. Or maybe _I_ will get a benefit
from those features a little further down the road! I've modified
the code to produced a SortedMap - just replaced all "Map" with
"SortedMap", dead easy! - and reran my unit tests. Naturally, they
still worked fine.
You're the API writer. YOU dictate what "some future user" gets to
do.
Fair enough.
It's a best practice to add a lot of "potentially useful" cruft to a
type. Implement what you need now, and refactor later if the need
arises.
(I saw your amendment about the missing "not" in that paragraph.)
I probably tend to overbuild a lot of the time anyway, in the sense
of adding functionality that isn't all that likely to be used. My
current thread about the internationalization/localization is proof
of that. I tend to anticipate needs that others aren't sure will ever
happen. Not all the time of course; it's just a tendency, not an
obsession ;-)
This is a universal tendency. Everyone has it to some extent. From
what i remember of the dim depths of time, i had it rather strongly
when i was starting out programming, although it manifested itself in
writing overcomplicated class hierarchies and mad epicyclic structures
of composed objects. Kent Beck once accused me of suffering from
'premature abstraction'. I think it's common to suffer from it
strongly when you first start thinking about design, and to grow out
of it in time. Well, or to become an architect, architects being the
Peter Pans of the programming world.
I remember a first year Algebra course at university where the professor
couldn't say ANYTHING without making it as abstract as humanly possible.
Where you or I might say "1 + 1 = 2", he'd write something like " N,
where it is a member of a universe of possible number systems which may
include integers, when added to X, where it is a member of a universe of
a possible number systems which may include integers, may result in Z,
where it is a member of a universe of possible number systems which may
include integers". Or something like that anyway. And of course he'd
write it on the board in proper algebraic notation which I've long
forgotten. The abstractions, which I'm grossly oversimplifying, made his
point, which was probably very simple, so obscure that I was utterly lost
within moments of him starting. I struggled as best I could for a couple
of weeks or so but I was so completely lost, I realized I would fail very
badly if I stayed in this class. I soon found another algebra course,
taught by a prof who was far less abstract, and was fine. As insightful
and interesting as the first prof's abstractions probably were, they were
way beyond anything I could follow at the time ;-) (For what it's worth,
a friend who knew others in the class said that a very large percentage
of the rest of the students in that class said virtually all of them had
dropped the course not long after I did. I hope they prof learned to be a
little more concrete from that experience
It's unusual to be in a situation where there is a real choice between
a class and an interface. When you're deciding the type of a variable,
you ask, as Lew said, "what is the most general type that guarantees
the behaviour i want from this variable". You don't worry about
whether that type is a class or an interface.
Sorry, I probably put my initial remarks badly.
Sigh. I've accumulated a number of confusions over my time with Java.
Sometimes, I can put them aside and still get by just fine. Sometimes, I
think I've finally seen the light and understand the obscure point for a
while, but then an example or a remark a newsgroup like this makes me
wonder if I understood the point correctly after all. And of course I'm
not sufficiently disciplined to actually write all of these confusions
down or to systematically resolve them via research and/or newsgroup
questions.....
I'm pretty sure that one of those fundamental confusions was on my mind
when I made my very general remark about confusion between interfaces and
classes but since I truly can't think of anything specific, and since I
don't have the time right now to mentally reconstruct and type my List of
Java Confusions for you, let's just put all that aside for some other
time.
Right now, I think I would benefit from the answer to a new mystery.
I do database stuff fairly frequently and mostly use my copy of DB2 as my
database engine. Naturally, I use ResultSets for a lot of this work. I
know that ResultSet is an interface, not a class, but it is rich in
exactly the sorts of methods I need to grab the Strings, integers and
whatnot in the database or to write them to the database. A short time
ago, I was looking at the source for ResultSet and found that not one of
the many methods in that interface are implemented; every single method
seems to be abstract. I see in the JavaDoc that there are a number of
"sub-interfaces" - I'm really not sure what a sub-interface is and how it
is different from a interface and that it has a "super-interface" -
again, I'm not sure what that is! - but the perplexing thing is that I am
not explicitly using the super-interface or any of the sub-interfaces yet
my code still works fine. That kind of thing disorients me; I wonder how
that could possibly be working and why I don't need to change from
ResultSet to a real class or another sub-interface or whatever. My
pragmatic self is capable of just ignoring all of that and saying "It's a
mystery but I'm not going to question it since it obviously works." But
my more idealistic self is bothered that it isn't obvious to me why the
ResultSet works despite its troubling aspects.
Can you possibly shed some light on what is happening there?
When you're designing an inheritance hierarchy to exploit
polymorphism, you can choose to make the root type an interface or an
exposed base class. Like:
public abstract class DataStore {
public abstract Data load(String id);
}
public class RelationalDataStore extends DataStore {
public Data load(String id) {
// code
}
}
vs
public interface DataStore {
public Data load(String id);
}
public class RelationalDataStore implements DataStore {
public Data load(String id) {
// code
}
}
The mainstream modern school of thought is that you should always
choose the interface, so there's no real dilemma there either.
Okay. That seems clear enough