Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #3578 > unrolled thread
| Started by | Zapanaz <http://joecosby.com/code/mail.pl@foo.com> |
|---|---|
| First post | 2011-05-05 12:21 -0700 |
| Last post | 2011-05-10 19:40 -0300 |
| Articles | 15 on this page of 75 — 14 participants |
Back to article view | Back to comp.lang.java.programmer
"Program to an interface" - When to break a design pattern Zapanaz <http://joecosby.com/code/mail.pl@foo.com> - 2011-05-05 12:21 -0700
Re: "Program to an interface" - When to break a design pattern Joshua Cranmer <Pidgeot18@verizon.invalid> - 2011-05-05 15:43 -0400
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-05 17:19 -0400
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-05 21:47 +0200
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 14:14 -0600
Re: "Program to an interface" - When to break a design pattern Zapanaz <http://joecosby.com/code/mail.pl@foo.com> - 2011-05-05 13:26 -0700
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-05 22:27 +0200
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 14:42 -0600
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-05 22:48 +0200
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 15:02 -0600
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-06 00:02 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-05 19:49 -0300
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-06 02:28 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-06 07:24 -0300
Re: "Program to an interface" - When to break a design pattern Patricia Shanahan <pats@acm.org> - 2011-05-06 07:03 -0700
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-06 17:30 -0300
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-06 18:56 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-06 17:50 -0300
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-06 23:37 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-06 19:43 -0300
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 17:17 -0600
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-06 02:28 +0200
Re: "Program to an interface" - When to break a design pattern Zapanaz <http://joecosby.com/code/mail.pl@foo.com> - 2011-05-05 23:25 -0700
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-06 18:25 +0200
Re: "Program to an interface" - When to break a design pattern Zapanaz <http://joecosby.com/code/mail.pl@foo.com> - 2011-05-07 16:26 -0700
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-08 03:28 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-08 00:05 -0300
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-08 16:15 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-08 14:20 -0300
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-08 19:48 +0200
Re: "Program to an interface" - When to break a design pattern markspace <-@.> - 2011-05-10 07:36 -0700
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-10 13:04 -0600
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-10 21:31 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-10 20:01 -0300
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-11 19:14 +0200
Re: "Program to an interface" - When to break a design pattern Patricia Shanahan <pats@acm.org> - 2011-05-11 10:41 -0700
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-11 19:55 +0200
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-11 16:42 -0400
Re: "Program to an interface" - When to break a design pattern Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2011-05-11 23:34 +0200
Re: "Program to an interface" - When to break a design pattern "John B. Matthews" <nospam@nospam.invalid> - 2011-05-12 00:51 -0400
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-12 00:58 -0400
Re: "Program to an interface" - When to break a design pattern Tom Anderson <twic@urchin.earth.li> - 2011-05-12 20:08 +0100
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-15 13:25 -0300
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-05 17:24 -0400
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 16:00 -0600
Re: "Program to an interface" - When to break a design pattern Jukka Lahtinen <jtfjdehf@hotmail.com.invalid> - 2011-05-06 15:01 +0300
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-06 12:17 -0400
Re: "Program to an interface" - When to break a design pattern Zapanaz <http://joecosby.com/code/mail.pl@foo.com> - 2011-05-07 16:28 -0700
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-05 17:21 -0400
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 15:58 -0600
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-05 18:18 -0400
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-05 19:20 -0300
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-05 18:23 -0400
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-05 20:17 -0300
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-05 18:26 -0300
Re: "Program to an interface" - When to break a design pattern Steven Simpson <ss@domain.invalid> - 2011-05-05 22:57 +0100
Re: "Program to an interface" - When to break a design pattern Tom Anderson <twic@urchin.earth.li> - 2011-05-05 23:29 +0100
Re: "Program to an interface" - When to break a design pattern Steven Simpson <ss@domain.invalid> - 2011-05-06 13:30 +0100
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-06 12:19 -0400
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 16:41 -0600
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-05 20:47 -0300
Re: "Program to an interface" - When to break a design pattern Roedy Green <see_website@mindprod.com.invalid> - 2011-05-05 16:41 -0700
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-05 22:47 -0600
Re: "Program to an interface" - When to break a design pattern Zapanaz <http://joecosby.com/code/mail.pl@foo.com> - 2011-05-05 23:28 -0700
Re: "Program to an interface" - When to break a design pattern Michal Kleczek <kleku75@gmail.com> - 2011-05-06 17:15 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-06 20:53 -0300
Re: "Program to an interface" - When to break a design pattern Lew <noone@lewscanon.com> - 2011-05-06 21:39 -0400
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-07 00:56 -0300
Re: "Program to an interface" - When to break a design pattern Michal Kleczek <kleku75@gmail.com> - 2011-05-08 12:24 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-08 13:42 -0300
Re: "Program to an interface" - When to break a design pattern Michal Kleczek <kleku75@gmail.com> - 2011-05-09 11:04 +0200
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-09 19:33 -0300
Re: "Program to an interface" - When to break a design pattern Michal Kleczek <kleku75@gmail.com> - 2011-05-10 15:51 +0200
Re: "Program to an interface" - When to break a design pattern Jim Janney <jjanney@shell.xmission.com> - 2011-05-10 13:15 -0600
Re: "Program to an interface" - When to break a design pattern Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-05-10 19:40 -0300
Page 4 of 4 — ← Prev page 1 2 3 [4]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2011-05-05 20:47 -0300 |
| Message-ID | <ZFGwp.9374$h%4.4784@newsfe22.iad> |
| In reply to | #3617 |
On 11-05-05 07:41 PM, Jim Janney wrote: > Steven Simpson <ss@domain.invalid> writes: [ SNIP ] >> OTOH, this sort of thing is already done, with Set and Collection. Set >> extends Collection, but doesn't actually define any new methods. (It >> does take advantage of 'overriding' the documentation, though.) Is it >> worth having Set if: >> >> * you can implement Set without actually having set semantics? >> * you can implement set semantics with just Collection? >> >> So, if you're prepared to trust that an implementation of Set or >> InsertionOrderedMap follows the documented rules that can't be >> compiler-enforced, perhaps it's as well do away with those interfaces, >> and just put the documentation on methods like getSortedMap, and trust >> that they are implemented accordingly. > > That may be the best overall approach. The Javadoc for java.util.Map > explicitly notes that different implementations can provide different > behavior here. > Which is actually the case for a bunch of collections. Of relevance to this thread, LinkedHashMap provides 4 new method implementations, but 3 of them are overrides of methods in concrete class HashMap. Those 3 in turn are overrides of method implementations in AbstractMap. The two instantiable classes have different behaviour, though, so if I decide that it's really LinkedHashMap that I need, another Map will not do. So why refer to it as a Map? With Java collections, one may pass around a Map or a Set or a List, with reasonable trust that whatever is being shuttled around has high-level map/set/bag semantics, but many/most Java programmers also care a fair bit about the actual implementations used, because it matters. They behave differently. They may all be Maps or Sets or Lists, but they're not the same. It frequently is not acceptable to pass around just any Map or Set or List, so why is "program to the interface" so highly touted here? Beats me. My 2 cents worth. And I'm being a bit of non-conformist and shit disturber here. :-) And rather than rely only on documentation, what's wrong with using the language? I've picked ConcurrentHashMap, say, because I damned well need ConcurrentHashMap, and I want and require getAppropriateMap() to return a ConcurrentHashMap, so perhaps it is the proper thing to have getMap() return ConcurrentHashMap. Just a thought. I hearken back to your earlier observation, that: "The point of programming to the interface is to make it easier to substitute a different implementation, which implies that any reasonable implementation can be used. If this is not true, if the code that uses the object relies on behavior only found in one implementation, then there is no benefit to using the interface, and you make it more inviting for someone to break things later on." This is absolutely true. And the Java Collections API is rife with possibilities for where "programming to the interface" is undesirable and counterproductive. AHS
[toc] | [prev] | [next] | [standalone]
| From | Roedy Green <see_website@mindprod.com.invalid> |
|---|---|
| Date | 2011-05-05 16:41 -0700 |
| Message-ID | <v3d6s6li6rgq2u28pversmjl1l913fjf0i@4ax.com> |
| In reply to | #3578 |
On Thu, 05 May 2011 12:21:55 -0700, Zapanaz <http://joecosby.com/code/mail.pl@foo.com> wrote, quoted or indirectly quoted someone who said : >The problem is, where I'm creating sortedMap above, I need the map to >retain the insertion order. If what's returned actually is a Map, >rather than a LinkedHashMap, then the results the user actually sees >are going to be in the wrong order. Making things worse, in this case, >nothing would actually break, only the end user would notice anything >was actually wrong. The idea of an interface is you should be able to substitute some other implementation and all should work unmodified. That is not the case with the interface you chose. You need to either find or create an interface that nails down all the desired behaviour, or use the original actual implementation. I am not a big fan of this pattern for the following reasons: 1. it slows down access. 2. it obfuscates just what the code is using NOW for the implementation. 3. It is more verbose, giving you one more thing you have to eyeball carefully and make dance through the genericity hoops. That makes for buggier code. The main place it would pay off is if you plan to later do some fine tuning, and want to leave open the option of easily substituting your own tuned collection classes. -- Roedy Green Canadian Mind Products http://mindprod.com Politicians complain that Kindles and iBooks are killing jobs by destroying the paper book industry. I see it that they have create a way to produce books for less than a third the cost without destroying forests and emitting greenhouse gases in the process. They have created wealth. They are encouraging literacy and cutting the costs of education.
[toc] | [prev] | [next] | [standalone]
| From | Jim Janney <jjanney@shell.xmission.com> |
|---|---|
| Date | 2011-05-05 22:47 -0600 |
| Message-ID | <2pr58co2pb.fsf@shell.xmission.com> |
| In reply to | #3622 |
Roedy Green <see_website@mindprod.com.invalid> writes: > On Thu, 05 May 2011 12:21:55 -0700, Zapanaz > <http://joecosby.com/code/mail.pl@foo.com> wrote, quoted or indirectly > quoted someone who said : > >>The problem is, where I'm creating sortedMap above, I need the map to >>retain the insertion order. If what's returned actually is a Map, >>rather than a LinkedHashMap, then the results the user actually sees >>are going to be in the wrong order. Making things worse, in this case, >>nothing would actually break, only the end user would notice anything >>was actually wrong. > > The idea of an interface is you should be able to substitute some > other implementation and all should work unmodified. That is not the > case with the interface you chose. You need to either find or create > an interface that nails down all the desired behaviour, or use the > original actual implementation. > > I am not a big fan of this pattern for the following reasons: > 1. it slows down access. > 2. it obfuscates just what the code is using NOW for the > implementation. > 3. It is more verbose, giving you one more thing you have to eyeball > carefully and make dance through the genericity hoops. That makes for > buggier code. > > The main place it would pay off is if you plan to later do some fine > tuning, and want to leave open the option of easily substituting your > own tuned collection classes. Wandering off the original topic, this might interest you if you haven't already seen it, on the subject of deciding when to break rules: http://www.miller-mccune.com/culture-society/triumph-of-the-cyborg-composer-8507 -- Jim Janney
[toc] | [prev] | [next] | [standalone]
| From | Zapanaz <http://joecosby.com/code/mail.pl@foo.com> |
|---|---|
| Date | 2011-05-05 23:28 -0700 |
| Message-ID | <b757s6ltvk2nld4t6nkfsgkb91grccn0er@4ax.com> |
| In reply to | #3622 |
On Thu, 05 May 2011 16:41:33 -0700, Roedy Green <see_website@mindprod.com.invalid> wrote: >On Thu, 05 May 2011 12:21:55 -0700, Zapanaz ><http://joecosby.com/code/mail.pl@foo.com> wrote, quoted or indirectly >quoted someone who said : > >>The problem is, where I'm creating sortedMap above, I need the map to >>retain the insertion order. If what's returned actually is a Map, >>rather than a LinkedHashMap, then the results the user actually sees >>are going to be in the wrong order. Making things worse, in this case, >>nothing would actually break, only the end user would notice anything >>was actually wrong. > >The idea of an interface is you should be able to substitute some >other implementation and all should work unmodified. That is not the >case with the interface you chose. You need to either find or create >an interface that nails down all the desired behaviour, or use the >original actual implementation. > >I am not a big fan of this pattern for the following reasons: >1. it slows down access. >2. it obfuscates just what the code is using NOW for the >implementation. >3. It is more verbose, giving you one more thing you have to eyeball >carefully and make dance through the genericity hoops. That makes for >buggier code. > >The main place it would pay off is if you plan to later do some fine >tuning, and want to leave open the option of easily substituting your >own tuned collection classes. Thanks Roedy. Your web page was a lot of help to me when I was learning Java years ago, thanks for that too. -- Zapanaz International Satanic Conspiracy Customer Support Specialist http://joecosby.com/ Isn't round the funny side that never ends? :: Currently listening to For His Namesake, by Amboy Dukes/Ted Nugent, from "Journey to the Center of the Mind"
[toc] | [prev] | [next] | [standalone]
| From | Michal Kleczek <kleku75@gmail.com> |
|---|---|
| Date | 2011-05-06 17:15 +0200 |
| Message-ID | <iq139v$feg$1@news.onet.pl> |
| In reply to | #3578 |
wrote:
>
> I've seen this design pattern before
>
> http://witte-consulting.com/documents/design-principles/
>
> and, in general, I see the point of it.
>
> But say we've got something like this
>
> LinkedHashMap<String, Integer> sortedMap = this.getSortedMap();
>
> So you have the method
>
> public LinkedHashMap<String, Integer> getSortedMap() {
> //do stuff
> }
>
> (not necessarily public)
>
> Now the design principle says, the method signature should instead be
>
> public Map<String, Integer> getSortedMap() {
> //do stuff
> }
>
> The problem is, where I'm creating sortedMap above, I need the map to
> retain the insertion order. If what's returned actually is a Map,
> rather than a LinkedHashMap, then the results the user actually sees
> are going to be in the wrong order. Making things worse, in this case,
> nothing would actually break, only the end user would notice anything
> was actually wrong.
>
> So in this case, it seems to me, that using LinkedHashMap in the
> method signature makes sense. The fact that the return retains the
> insertion order is an integral part of what the method does.
>
> If nothing else, it's going to save Fred Developer down the line from
> looking at the code around this
>
> Map<String, Integer> sortedMap = this.getSortedMap();
>
> and thinking "wait, how do I know getSortedMap() is going to return a
> result with the right ordering?", and having to waste time digging
> into that method.
>
> ***
>
> Opinions? Angry mob with torches and pitchforks? The Spanish
> Inquisition?
>
>
Stick to the principle and specify return type as java.util.Map.
The decision on what Map implementation to use has to obey DRY principle -
if the place to decide is getSortedMap() then the rest of the program should
assume getSortedMap() does the right thing.
Imagine the requirements change and from now on the map has to retain
reverse insertion order. Do you want to rewrite your clients?
--
Michal
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2011-05-06 20:53 -0300 |
| Message-ID | <GR%wp.68076$yp3.20908@newsfe09.iad> |
| In reply to | #3689 |
On 11-05-06 12:15 PM, Michal Kleczek wrote:
> wrote:
>
>>
>> I've seen this design pattern before
>>
>> http://witte-consulting.com/documents/design-principles/
>>
>> and, in general, I see the point of it.
>>
>> But say we've got something like this
>>
>> LinkedHashMap<String, Integer> sortedMap = this.getSortedMap();
>>
>> So you have the method
>>
>> public LinkedHashMap<String, Integer> getSortedMap() {
>> //do stuff
>> }
>>
>> (not necessarily public)
>>
>> Now the design principle says, the method signature should instead be
>>
>> public Map<String, Integer> getSortedMap() {
>> //do stuff
>> }
>>
>> The problem is, where I'm creating sortedMap above, I need the map to
>> retain the insertion order. If what's returned actually is a Map,
>> rather than a LinkedHashMap, then the results the user actually sees
>> are going to be in the wrong order. Making things worse, in this case,
>> nothing would actually break, only the end user would notice anything
>> was actually wrong.
>>
>> So in this case, it seems to me, that using LinkedHashMap in the
>> method signature makes sense. The fact that the return retains the
>> insertion order is an integral part of what the method does.
>>
>> If nothing else, it's going to save Fred Developer down the line from
>> looking at the code around this
>>
>> Map<String, Integer> sortedMap = this.getSortedMap();
>>
>> and thinking "wait, how do I know getSortedMap() is going to return a
>> result with the right ordering?", and having to waste time digging
>> into that method.
>>
>> ***
>>
>> Opinions? Angry mob with torches and pitchforks? The Spanish
>> Inquisition?
>
> Stick to the principle and specify return type as java.util.Map.
It's best to understand that principle before urging it on people. No
less an authority than Erich Gamma has made it clear - albeit not widely
enough nor early enough - that when GOF said "program to an interface",
they did *NOT* mean only Java "interface" as in a construct with the
"interface" keyword. What they actually meant was the OOP interface that
*every* class has, coupled with a judicious choice of which interface of
this type to pick in the type hierarchy.
What the principle really means - and you don't have to take my word for
it, you can look up discussions by OOP authorities - is that given that
the object you need is in a type hierarchy - classes, abstract classes,
interfaces - that you pick that level in the type hierarchy to work
with, which is as high up as possible while still meeting requirements.
The highest interface that fits the bill might actually be the interface
of a concrete class, or the interface of an abstract class. In fact
abstract classes are frequently better as interfaces than actual Java
"interfaces".
Bear in mind - and this is not invented by me; you can find this if you
keep up on OOP literature - that there is a reasonably well-known
distinction also between public and published interfaces (look up
"Fowler", "public", "published", and continue to keep in mind that
"interface" doesn't mean the Java keyword). If an interface is published
then it's not a bad thing to use it. LinkedHashMap has a published
interface *and* it has behaviour that other maps do not have - it is a
correct decision to stop in the type hierarchy with LinkedHashMap if
that's the behaviour you need.
Further note: behaviour isn't just a list of method signatures. It's
also what the abstract class or concrete class actually does. Not *how*
it does it - that's implementation - but what it does - that's
contractual _behaviour_. Keeping insertion order for iterators is
_behaviour_...using a doubly-linked list to accomplish that is
implementation.
> The decision on what Map implementation to use has to obey DRY principle -
> if the place to decide is getSortedMap() then the rest of the program should
> assume getSortedMap() does the right thing.
Good luck with that one. That's what a lot of Java code ends up hoping
for, because people misunderstood "program to an interface" and forced
the use of the highest possible level Java-keyword interfaces everywhere
possible. There are a bunch of problems that come about then:
downcasting all over the place, brittle code because now everything that
relied on interface X (including the 10 classes you wrote that
implemented it) has to be changed because you need to add a method to
interface X (or modify a method signature in interface X), calling code
unaware that it really ended up depending on that Map actually being a
LinkedHashMap and only finding out when some other provider of the
method gets swapped in...the list goes on and on.
> Imagine the requirements change and from now on the map has to retain
> reverse insertion order. Do you want to rewrite your clients?
>
Bad example in my opinion. The first time this happened I'd take it on
the chin and accept that the client code doesn't know what it
wants...seeing as how it's the client code that forces a change like
this. And rather than be screwed twice I'd probably write an abstract
class, or Java-keyword interface, that would let me cope with poor
design by the other team.
Be clear on this - you could have used a high-level Java "interface", as
in the keyword type of interface. And the requirements change and now
you need to modify the interface - you're just as hosed then, Michal.
AHS
[toc] | [prev] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2011-05-06 21:39 -0400 |
| Message-ID | <iq27rs$ehs$1@news.albasani.net> |
| In reply to | #3727 |
On 05/06/2011 07:53 PM, Arved Sandstrom wrote:
> On 11-05-06 12:15 PM, Michal Kleczek wrote:
>> wrote:
>>
>>>
>>> I've seen this design pattern before
>>>
>>> http://witte-consulting.com/documents/design-principles/
>>>
>>> and, in general, I see the point of it.
>>>
>>> But say we've got something like this
>>>
>>> LinkedHashMap<String, Integer> sortedMap = this.getSortedMap();
>>>
>>> So you have the method
>>>
>>> public LinkedHashMap<String, Integer> getSortedMap() {
>>> //do stuff
>>> }
>>>
>>> (not necessarily public)
>>>
>>> Now the design principle says, the method signature should instead be
>>>
>>> public Map<String, Integer> getSortedMap() {
>>> //do stuff
>>> }
>>>
>>> The problem is, where I'm creating sortedMap above, I need the map to
>>> retain the insertion order. If what's returned actually is a Map,
>>> rather than a LinkedHashMap, then the results the user actually sees
>>> are going to be in the wrong order. Making things worse, in this case,
>>> nothing would actually break, only the end user would notice anything
>>> was actually wrong.
>>>
>>> So in this case, it seems to me, that using LinkedHashMap in the
>>> method signature makes sense. The fact that the return retains the
>>> insertion order is an integral part of what the method does.
>>>
>>> If nothing else, it's going to save Fred Developer down the line from
>>> looking at the code around this
>>>
>>> Map<String, Integer> sortedMap = this.getSortedMap();
>>>
>>> and thinking "wait, how do I know getSortedMap() is going to return a
>>> result with the right ordering?", and having to waste time digging
>>> into that method.
>>>
>>> ***
>>>
>>> Opinions? Angry mob with torches and pitchforks? The Spanish
>>> Inquisition?
>>
>> Stick to the principle and specify return type as java.util.Map.
>
> It's best to understand that principle before urging it on people. No
> less an authority than Erich Gamma has made it clear - albeit not widely
> enough nor early enough - that when GOF said "program to an interface",
> they did *NOT* mean only Java "interface" as in a construct with the
> "interface" keyword. What they actually meant was the OOP interface that
> *every* class has, coupled with a judicious choice of which interface of
> this type to pick in the type hierarchy.
>
> What the principle really means - and you don't have to take my word for
> it, you can look up discussions by OOP authorities - is that given that
> the object you need is in a type hierarchy - classes, abstract classes,
> interfaces - that you pick that level in the type hierarchy to work
> with, which is as high up as possible while still meeting requirements.
>
> The highest interface that fits the bill might actually be the interface
> of a concrete class, or the interface of an abstract class. In fact
> abstract classes are frequently better as interfaces than actual Java
> "interfaces".
>
> Bear in mind - and this is not invented by me; you can find this if you
> keep up on OOP literature - that there is a reasonably well-known
> distinction also between public and published interfaces (look up
> "Fowler", "public", "published", and continue to keep in mind that
> "interface" doesn't mean the Java keyword). If an interface is published
> then it's not a bad thing to use it. LinkedHashMap has a published
> interface *and* it has behaviour that other maps do not have - it is a
> correct decision to stop in the type hierarchy with LinkedHashMap if
> that's the behaviour you need.
>
> Further note: behaviour isn't just a list of method signatures. It's
> also what the abstract class or concrete class actually does. Not *how*
> it does it - that's implementation - but what it does - that's
> contractual _behaviour_. Keeping insertion order for iterators is
> _behaviour_...using a doubly-linked list to accomplish that is
> implementation.
>
>> The decision on what Map implementation to use has to obey DRY principle -
>> if the place to decide is getSortedMap() then the rest of the program should
>> assume getSortedMap() does the right thing.
>
> Good luck with that one. That's what a lot of Java code ends up hoping
> for, because people misunderstood "program to an interface" and forced
> the use of the highest possible level Java-keyword interfaces everywhere
> possible. There are a bunch of problems that come about then:
> downcasting all over the place, brittle code because now everything that
> relied on interface X (including the 10 classes you wrote that
> implemented it) has to be changed because you need to add a method to
> interface X (or modify a method signature in interface X), calling code
> unaware that it really ended up depending on that Map actually being a
> LinkedHashMap and only finding out when some other provider of the
> method gets swapped in...the list goes on and on.
>
>> Imagine the requirements change and from now on the map has to retain
>> reverse insertion order. Do you want to rewrite your clients?
>>
> Bad example in my opinion. The first time this happened I'd take it on
> the chin and accept that the client code doesn't know what it
> wants...seeing as how it's the client code that forces a change like
> this. And rather than be screwed twice I'd probably write an abstract
> class, or Java-keyword interface, that would let me cope with poor
> design by the other team.
>
> Be clear on this - you could have used a high-level Java "interface", as
> in the keyword type of interface. And the requirements change and now
> you need to modify the interface - you're just as hosed then, Michal.
Here are the relevant chapter titles from /Effective Java/, by Joshua Bloch:
Item 18: Prefer interfaces to abstract classes
Item 19: Use interfaces only to define types
Item 52: Refer to objects by their interfaces
Item 53: Prefer interfaces to reflection
Here he refers to the Java 'interface', not the more general term you just
discussed.
Note that in the details of Item 52, Mr. Bloch covers using the more specific
types when the contract (the GoF sense of "interface") calls for it:
"If appropriate interface types exist, then ... your program will be more
flexible if you use the interface to refer to the object; if not, just use the
least specific class in the class hierarchy that provides the required
functionality."
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2011-05-07 00:56 -0300 |
| Message-ID | <Ep3xp.13901$Du7.6572@newsfe04.iad> |
| In reply to | #3735 |
On 11-05-06 10:39 PM, Lew wrote: > On 05/06/2011 07:53 PM, Arved Sandstrom wrote: [ SNIP ] > Here are the relevant chapter titles from /Effective Java/, by Joshua > Bloch: > Item 18: Prefer interfaces to abstract classes > Item 19: Use interfaces only to define types > Item 52: Refer to objects by their interfaces > Item 53: Prefer interfaces to reflection > > Here he refers to the Java 'interface', not the more general term you > just discussed. > > Note that in the details of Item 52, Mr. Bloch covers using the more > specific types when the contract (the GoF sense of "interface") calls > for it: > > "If appropriate interface types exist, then ... your program will be > more flexible if you use the interface to refer to the object; if not, > just use the least specific class in the class hierarchy that provides > the required functionality." Fair enough. As far as Item 52 goes, I think that's what everyone is saying, given that elaboration you quoted. Item 19, no argument from me. Item 53, I won't argue about that either. Item 18, "prefer interfaces to abstract classes" is a short & sweet recommendation that more often than not is a good one to follow. Particularly in Java, where language limitations, as Bloch himself points out, seriously limit the use of abstract classes as type definitions. However, the use of the word "prefer" means to me that available interfaces are used over available abstract classes when consideration shows that it's the best choice, not just because a single-sentence principle says so. One important thing needs to be pointed out here, and it's mentioned in Item 18 by Bloch: " Any class that defines all of the required methods and obeys the general contract is permitted to implement an interface". The sticking point in this thread is the _general contract_ - there is no interface, Map or otherwise, that has the contract required by the OP. Short of defining a PredictableIterationOrderMap interface and having a subclass of LinkedHashMap implement that, one may as well use LinkedHashMap. Per Bloch's Item 52 - there is no appropriate interface type available here. To rephrase that, we should be choosing types - interfaces, abstract classes, or concrete classes - whose contracts match the requirements. And a bag of method signatures is not a contract (except between the code and the compiler). Behaviour specified in the API Javadocs (in the case of maps, starting right with java.util.Map) is the actual contract. The practise of using a Java interface at all costs, and the most general interface at that, with little or no attention paid to the fact that the general type you are passing around does not have a required contract, is so prevalent in the industry that these days, if you try to point out the intent of the design principle, people often have no clue what you are trying to express. It's a losing battle. There's certainly no shortage of folks who think that that "bag of method signatures" _is_ the contract, that's for sure. AHS
[toc] | [prev] | [next] | [standalone]
| From | Michal Kleczek <kleku75@gmail.com> |
|---|---|
| Date | 2011-05-08 12:24 +0200 |
| Message-ID | <iq5r0f$il6$1@news.onet.pl> |
| In reply to | #3727 |
Arved Sandstrom wrote: > > Further note: behaviour isn't just a list of method signatures. It's > also what the abstract class or concrete class actually does. Not *how* > it does it - that's implementation - but what it does - that's > contractual _behaviour_. Keeping insertion order for iterators is > _behaviour_...using a doubly-linked list to accomplish that is > implementation. > I think this is the real point of the discussion - Java interfaces are just too weak to express contracts. Note that there are many other aspects beside iteration ordering that are important to the overall solution but still not expressed (and not expressable) by interfaces: concurrency guarantees, performance and memory usage characteristics etc. Picking one aspect and trying to express it using Java types just does not make sense. One could actually argue if java.util.Set interface is really needed at all. Additionally - the mere fact that in the overall solution the choice of the map implementation having a particular characteristic is important is not enough to justify that _all_ code should depend on it. >> The decision on what Map implementation to use has to obey DRY principle >> - if the place to decide is getSortedMap() then the rest of the program >> should assume getSortedMap() does the right thing. > > Good luck with that one. That's what a lot of Java code ends up hoping > for, because people misunderstood "program to an interface" and forced > the use of the highest possible level Java-keyword interfaces everywheres > possible. There are a bunch of problems that come about then: > downcasting all over the place, If downcasting is needed it means the wrong type was choosen. It is not the case here since OP is not going to use any methods not defined in java.util.Map. -- Michal
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2011-05-08 13:42 -0300 |
| Message-ID | <JJzxp.21021$uh5.14366@newsfe02.iad> |
| In reply to | #3800 |
On 11-05-08 07:24 AM, Michal Kleczek wrote: > Arved Sandstrom wrote: > >> Further note: behaviour isn't just a list of method signatures. It's >> also what the abstract class or concrete class actually does. Not *how* >> it does it - that's implementation - but what it does - that's >> contractual _behaviour_. Keeping insertion order for iterators is >> _behaviour_...using a doubly-linked list to accomplish that is >> implementation. > > I think this is the real point of the discussion - Java interfaces are just > too weak to express contracts. Note that there are many other aspects beside > iteration ordering that are important to the overall solution but still not > expressed (and not expressable) by interfaces: concurrency guarantees, > performance and memory usage characteristics etc. > Picking one aspect and trying to express it using Java types just does not > make sense. Agreed, partly. It can't be done with Java interfaces at all. It can - obviously - be done with the published API of abstract or concrete Java classes. What we're really arguing about here is whether it's desirable to bind client code to provider contracts. It's clear that Map cannot enforce a behavioural contract, and that LinkedHashMap does. Rather than beat that to death, let's acknowledge that we have one camp that argues that we don't want to tie the caller to a behavioural provider contract, and another camp (me) that says that sometimes you do want and need to do this. > One could actually argue if java.util.Set interface is really needed at all. This is one of the main points, I agree. It's also been highlighted in this thread precisely because most of the time the calling code genuinely doesn't care what implementation it gets. Most of the time the calling code requires simply that it gets a Map, List, Set etc, and the provider of the Map or List or Set has the responsibility for enforcing the contract...assuming one exists. In this case I believe a credible case can be made that the calling code does care about what the specific contract is: the OP said so, and provided a good use case. One thing I do know, based on experience, is that if you return a generic map from that method, that when developers move on to different projects and different employers, and the documentation (if it ever existed) fails to be maintained, and refactorings change the relationship of the Map provider code to the calling code, that sooner or later that client code is no longer going to get a LinkedHashMap. If the code never gets touched again after Version 1.0, then you were just _lucky_. I don't pretend to be infallible when it comes to answers for this kind of thing. But I do know that a knee-jerk 100% adherence to "program to a Java 'interface'", and highest-level interfaces at that, can be wrong. Absolutely, Java interfaces, *as language constructs* that are enforced by the compiler, are too weak to express many forms of contracts. All they can do is ensure that subtypes that implement an interface have a certain set of methods. Period. > Additionally - the mere fact that in the overall solution the choice of the > map implementation having a particular characteristic is important is not > enough to justify that _all_ code should depend on it. I'd honestly need to see more of the OP's problem before I definitely recommended returning LinkedHashMap. Mainly what got my hackles up was everyone piling in on the "program to the interface" principle without any obvious thought being put into it. Fact of the matter is that you _could_ return Map in the OP's scenario, and get away with it, provided that both the code that constructed and provided that map, and the code that used it, were one monolithic piece. It's when you separate the two that wishful thinking enters the picture. We don't in this case know enough about the relationship of the provider of the map and the user of the map to say, one way or the other, whether Map or LinkedHashMap is the best way to go. >>> The decision on what Map implementation to use has to obey DRY principle >>> - if the place to decide is getSortedMap() then the rest of the program >>> should assume getSortedMap() does the right thing. >> >> Good luck with that one. That's what a lot of Java code ends up hoping >> for, because people misunderstood "program to an interface" and forced >> the use of the highest possible level Java-keyword interfaces everywheres >> possible. There are a bunch of problems that come about then: >> downcasting all over the place, > > If downcasting is needed it means the wrong type was choosen. It is not the > case here since OP is not going to use any methods not defined in > java.util.Map. > With Java collections - Map and Collection mainly - you normally don't have to downcast, just for the reason you stated. All the subinterfaces and classes that extend/implement Map and Collection rarely significantly change the actual set of method signatures, with a few notable exceptions like queues. But if you "program to an interface" at all costs in many other type hierarchies then it can happen. As a conclusion, I think a few of us have at least agreed that there is no good mechanism in Java for defining and enforcing a large swathe of contractual behaviour. We rely on good Javadocs, and meticulous reading of same, and very good adherence to design and implementation best practices - all those things that all Java programmers are so very good at - to save us. AHS
[toc] | [prev] | [next] | [standalone]
| From | Michal Kleczek <kleku75@gmail.com> |
|---|---|
| Date | 2011-05-09 11:04 +0200 |
| Message-ID | <iq8an1$ssl$1@news.onet.pl> |
| In reply to | #3816 |
Arved Sandstrom wrote: > On 11-05-08 07:24 AM, Michal Kleczek wrote: >> Arved Sandstrom wrote: >> >>> Further note: behaviour isn't just a list of method signatures. It's >>> also what the abstract class or concrete class actually does. Not *how* >>> it does it - that's implementation - but what it does - that's >>> contractual _behaviour_. Keeping insertion order for iterators is >>> _behaviour_...using a doubly-linked list to accomplish that is >>> implementation. >> >> I think this is the real point of the discussion - Java interfaces are >> just too weak to express contracts. Note that there are many other >> aspects beside iteration ordering that are important to the overall >> solution but still not expressed (and not expressable) by interfaces: >> concurrency guarantees, performance and memory usage characteristics etc. >> Picking one aspect and trying to express it using Java types just does >> not make sense. > > Agreed, partly. It can't be done with Java interfaces at all. It can - > obviously - be done with the published API of abstract or concrete Java > classes. Then it would be not "what" but "how". > > What we're really arguing about here is whether it's desirable to bind > client code to provider contracts. It's clear that Map cannot enforce a > behavioural contract, and that LinkedHashMap does. Rather than beat that > to death, let's acknowledge that we have one camp that argues that we > don't want to tie the caller to a behavioural provider contract, and > another camp (me) that says that sometimes you do want and need to do > this. I think you are missing the fact that the client is _already_ tied to a contract by calling getSortedMap() to get the map (since the contract of getSortedMap() is "return a map implementation that provides such and such iteration order". The question is rather - do we need to specify this contract as a Java type? I would rather say: since the compiler cannot enforce/check the contract anyway then it is useless - the contract specified as documentation of getSortedMap() is enough. -- Michal
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2011-05-09 19:33 -0300 |
| Message-ID | <sZZxp.15218$Du7.4644@newsfe04.iad> |
| In reply to | #3846 |
On 11-05-09 06:04 AM, Michal Kleczek wrote: > Arved Sandstrom wrote: > >> On 11-05-08 07:24 AM, Michal Kleczek wrote: >>> Arved Sandstrom wrote: >>> >>>> Further note: behaviour isn't just a list of method signatures. It's >>>> also what the abstract class or concrete class actually does. Not *how* >>>> it does it - that's implementation - but what it does - that's >>>> contractual _behaviour_. Keeping insertion order for iterators is >>>> _behaviour_...using a doubly-linked list to accomplish that is >>>> implementation. >>> >>> I think this is the real point of the discussion - Java interfaces are >>> just too weak to express contracts. Note that there are many other >>> aspects beside iteration ordering that are important to the overall >>> solution but still not expressed (and not expressable) by interfaces: >>> concurrency guarantees, performance and memory usage characteristics etc. >>> Picking one aspect and trying to express it using Java types just does >>> not make sense. >> >> Agreed, partly. It can't be done with Java interfaces at all. It can - >> obviously - be done with the published API of abstract or concrete Java >> classes. > > Then it would be not "what" but "how". No, that's not necessarily so. Abstract classes and concrete classes provide both a "what" - an interface (as in contract, not Java keyword) - and an implementation. An abstract class with no method implementations actually ought to be a Java interface, but assuming we have one, it's 100% "what" and 0% "how". An abstract class may trend quite high, 70 or 80 or 90 percent, in "how", but it's still 100% in "what", assuming that we consider all the public methods to be part of a published API. Even a concrete class - again assuming that all of its public methods are part of a published API - is 100% in "what", and now 100% on "how" as well. An implemented published method in a concrete class is as much part of a contractual interface as a method signature in a Java interface. >> What we're really arguing about here is whether it's desirable to bind >> client code to provider contracts. It's clear that Map cannot enforce a >> behavioural contract, and that LinkedHashMap does. Rather than beat that >> to death, let's acknowledge that we have one camp that argues that we >> don't want to tie the caller to a behavioural provider contract, and >> another camp (me) that says that sometimes you do want and need to do >> this. > > I think you are missing the fact that the client is _already_ tied to a > contract by calling getSortedMap() to get the map (since the contract of > getSortedMap() is "return a map implementation that provides such and such > iteration order". > The question is rather - do we need to specify this contract as a Java type? > I would rather say: since the compiler cannot enforce/check the contract > anyway then it is useless - the contract specified as documentation of > getSortedMap() is enough. > I agree that the compiler cannot enforce the contract unless both the provider of the LinkedHashMap and the calling code are written cooperatively to use LinkedHashMap explicitly, thereby locking in the requirement. This is the scenario I've been positing. As I believe I mentioned in another post, you could get away with documentation, but I believe you'd have to document not just the method, but also all the call sites. If you're going to rely on documentation then perhaps your biggest win would be to change the name of the method - getMap() would be an atrocious choice. IMO the only defensible choice is Map getPredictableIterationOrderMap() Now *this* stands out when you're using it. AHS
[toc] | [prev] | [next] | [standalone]
| From | Michal Kleczek <kleku75@gmail.com> |
|---|---|
| Date | 2011-05-10 15:51 +0200 |
| Message-ID | <iqbfs5$3u7$1@news.onet.pl> |
| In reply to | #3879 |
Arved Sandstrom wrote:
> On 11-05-09 06:04 AM, Michal Kleczek wrote:
>> I think you are missing the fact that the client is _already_ tied to a
>> contract by calling getSortedMap() to get the map (since the contract of
>> getSortedMap() is "return a map implementation that provides such and
>> such iteration order".
>> The question is rather - do we need to specify this contract as a Java
>> type? I would rather say: since the compiler cannot enforce/check the
>> contract anyway then it is useless - the contract specified as
>> documentation of getSortedMap() is enough.
>>
> I agree that the compiler cannot enforce the contract unless both the
> provider of the LinkedHashMap and the calling code are written
> cooperatively to use LinkedHashMap explicitly, thereby locking in the
> requirement. This is the scenario I've been positing.
>
> As I believe I mentioned in another post, you could get away with
> documentation, but I believe you'd have to document not just the method,
> but also all the call sites. If you're going to rely on documentation
> then perhaps your biggest win would be to change the name of the method
> - getMap() would be an atrocious choice. IMO the only defensible choice is
>
> Map getPredictableIterationOrderMap()
>
> Now *this* stands out when you're using it.
Sure - naming of functions is one of the most important aspects of defining
them.
Anyway.
Somehow I got lost in discussion and forgot the most important thing IMHO:
the fact that iteration order is important to the overall solution does not
imply it is important to the client code. Take an example:
//the program is supposed to print hashcodes of strings provided as
//arguments in the order that the user gave them
//forget that the map is not needed here
public void PrintHashes {
public static void main(String[] args) {
final Map<String, Integer> mapOfHashes = new LinkedHashMap<>();
calculateHashes(Arrays.asList(args), mapOfHashes);
printMap(mapOfHashes, System.out);
}
private static <T> void calculateHashes(
Iterable<? extends T> objects,
Map<? super T, ? super Integer> hashes) {
for (final Object object : objects) {
hashes.put(object, object.hashCode());
}
}
private static void printMap(Map<?, ?> map, PrintStream out) {
for (final Map.Entry<?, ?> entry : map.entrySet()) {
out.println("Key: " + entry.getKey() + " Value: " + entry.getValue());
}
}
}
According to your logic all references to Map<whatever> should be replaced
by LinkedHashMap<String, Integer> which - sorry to say that - sounds insane
:)
--
Michal
[toc] | [prev] | [next] | [standalone]
| From | Jim Janney <jjanney@shell.xmission.com> |
|---|---|
| Date | 2011-05-10 13:15 -0600 |
| Message-ID | <2p62pimko2.fsf@shell.xmission.com> |
| In reply to | #3913 |
Michal Kleczek <kleku75@gmail.com> writes: > Arved Sandstrom wrote: > >> On 11-05-09 06:04 AM, Michal Kleczek wrote: >>> I think you are missing the fact that the client is _already_ tied to a >>> contract by calling getSortedMap() to get the map (since the contract of >>> getSortedMap() is "return a map implementation that provides such and >>> such iteration order". >>> The question is rather - do we need to specify this contract as a Java >>> type? I would rather say: since the compiler cannot enforce/check the >>> contract anyway then it is useless - the contract specified as >>> documentation of getSortedMap() is enough. >>> >> I agree that the compiler cannot enforce the contract unless both the >> provider of the LinkedHashMap and the calling code are written >> cooperatively to use LinkedHashMap explicitly, thereby locking in the >> requirement. This is the scenario I've been positing. >> >> As I believe I mentioned in another post, you could get away with >> documentation, but I believe you'd have to document not just the method, >> but also all the call sites. If you're going to rely on documentation >> then perhaps your biggest win would be to change the name of the method >> - getMap() would be an atrocious choice. IMO the only defensible choice is >> >> Map getPredictableIterationOrderMap() >> >> Now *this* stands out when you're using it. > > Sure - naming of functions is one of the most important aspects of defining > them. > Anyway. > Somehow I got lost in discussion and forgot the most important thing IMHO: > the fact that iteration order is important to the overall solution does not > imply it is important to the client code. Take an example: Agreed. Neither does it imply that it is *not* important. We don't have enough information to determine that one way or the other. -- Jim Janney
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2011-05-10 19:40 -0300 |
| Message-ID | <K9jyp.25$RT2.19@newsfe02.iad> |
| In reply to | #3913 |
On 11-05-10 10:51 AM, Michal Kleczek wrote:
> Arved Sandstrom wrote:
>
>> On 11-05-09 06:04 AM, Michal Kleczek wrote:
>>> I think you are missing the fact that the client is _already_ tied to a
>>> contract by calling getSortedMap() to get the map (since the contract of
>>> getSortedMap() is "return a map implementation that provides such and
>>> such iteration order".
>>> The question is rather - do we need to specify this contract as a Java
>>> type? I would rather say: since the compiler cannot enforce/check the
>>> contract anyway then it is useless - the contract specified as
>>> documentation of getSortedMap() is enough.
>>>
>> I agree that the compiler cannot enforce the contract unless both the
>> provider of the LinkedHashMap and the calling code are written
>> cooperatively to use LinkedHashMap explicitly, thereby locking in the
>> requirement. This is the scenario I've been positing.
>>
>> As I believe I mentioned in another post, you could get away with
>> documentation, but I believe you'd have to document not just the method,
>> but also all the call sites. If you're going to rely on documentation
>> then perhaps your biggest win would be to change the name of the method
>> - getMap() would be an atrocious choice. IMO the only defensible choice is
>>
>> Map getPredictableIterationOrderMap()
>>
>> Now *this* stands out when you're using it.
>
> Sure - naming of functions is one of the most important aspects of defining
> them.
> Anyway.
> Somehow I got lost in discussion and forgot the most important thing IMHO:
> the fact that iteration order is important to the overall solution does not
> imply it is important to the client code. Take an example:
>
> //the program is supposed to print hashcodes of strings provided as
> //arguments in the order that the user gave them
> //forget that the map is not needed here
> public void PrintHashes {
>
> public static void main(String[] args) {
> final Map<String, Integer> mapOfHashes = new LinkedHashMap<>();
> calculateHashes(Arrays.asList(args), mapOfHashes);
> printMap(mapOfHashes, System.out);
> }
>
> private static <T> void calculateHashes(
> Iterable<? extends T> objects,
> Map<? super T, ? super Integer> hashes) {
> for (final Object object : objects) {
> hashes.put(object, object.hashCode());
> }
> }
>
> private static void printMap(Map<?, ?> map, PrintStream out) {
> for (final Map.Entry<?, ?> entry : map.entrySet()) {
> out.println("Key: " + entry.getKey() + " Value: " + entry.getValue());
> }
> }
>
> }
>
> According to your logic all references to Map<whatever> should be replaced
> by LinkedHashMap<String, Integer> which - sorry to say that - sounds insane
> :)
_That_ is not _my_ logic. My logic is that in the example provided by
the OP, there are sets of circumstances that make explicit use of
LinkedHashMap reasonable. These sets of circumstances may include both
the providing and calling code being non-published (that is, both of
them are involved in implementation details), and also the desire of the
designer/implementer to absolutely lock in this choice of Map
implementation in that non-published code.
Fact is, we don't know how public/published the OP intends that
map-producing method to be. Since we don't know, I've repeatedly tried
to more clearly explain the specific circumstances where I believe that
not using Map won't offend against the "program to the interface"
religion. I'm getting that there is quite a large group out there that
doesn't countenance *ever* breaking "program to the interface". So be it.
AHS
[toc] | [prev] | [standalone]
Page 4 of 4 — ← Prev page 1 2 3 [4]
Back to top | Article view | comp.lang.java.programmer
csiph-web