Re: "Program to an interface" - When to break a design pattern

Discussion in 'Java' started by Jim Janney, May 5, 2011.

  1. Jim Janney

    Jim Janney Guest

    Zapanaz <http://joecosby.com/code/> writes:

    > 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?


    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. So in this case, no,
    programming to the interface would be the wrong thing to do. The point
    of design principles is to make you think before you break them :)

    --
    Jim Janney
    Jim Janney, May 5, 2011
    #1
    1. Advertising

  2. On 05/05/2011 22:14, Jim Janney allegedly wrote:
    > 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. So
    > in this case, no, programming to the interface would be the wrong
    > thing to do. The point of design principles is to make you think
    > before you break them :)


    Entirely disagreed. The code shown did not contain any justification for
    breaking the pattern in question, and on the opposite, it contained all
    the reasons to think more about encapsulation, which is the true
    underlying rationale for coding to interfaces -- not polymorphism per se.

    --
    DF.
    An escaped convict once said to me:
    "Alcatraz is the place to be"
    Daniele Futtorovic, May 5, 2011
    #2
    1. Advertising

  3. Jim Janney

    Jim Janney Guest

    Daniele Futtorovic <> writes:

    > On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >> 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. So
    >> in this case, no, programming to the interface would be the wrong
    >> thing to do. The point of design principles is to make you think
    >> before you break them :)

    >
    > Entirely disagreed. The code shown did not contain any justification for
    > breaking the pattern in question, and on the opposite, it contained all
    > the reasons to think more about encapsulation, which is the true
    > underlying rationale for coding to interfaces -- not polymorphism per se.


    The justification is not in the code shown, but in the accompanying
    remark "I need the map to retain the insertion order." There's no
    interface in the JRE that promises this, and only one class that
    provides it, which makes encapsulation, shall we say, difficult.

    --
    Jim Janney
    Jim Janney, May 5, 2011
    #3
  4. On 05/05/2011 22:42, Jim Janney allegedly wrote:
    > Daniele Futtorovic<> writes:
    >
    >> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>> 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. So
    >>> in this case, no, programming to the interface would be the wrong
    >>> thing to do. The point of design principles is to make you think
    >>> before you break them :)

    >>
    >> Entirely disagreed. The code shown did not contain any justification for
    >> breaking the pattern in question, and on the opposite, it contained all
    >> the reasons to think more about encapsulation, which is the true
    >> underlying rationale for coding to interfaces -- not polymorphism per se.

    >
    > The justification is not in the code shown, but in the accompanying
    > remark "I need the map to retain the insertion order." There's no
    > interface in the JRE that promises this, and only one class that
    > provides it, which makes encapsulation, shall we say, difficult.


    That's not the point! Yes, you need a LinkedHashMap to retain insertion
    order in a Map. But retaining insertion order is relevant... only when
    inserting.

    In the code shown, the insertion happens in getSortedMap() (presumably).
    So yes, there a LinkedHashMap would be needed. But the code that *calls*
    getSortedMap() doesn't have to care about whether or not it's a
    LinkedHashMap. Hence the return type of getSortedMap() does not need to
    be LinkedHashMap. Qed.

    --
    DF.
    An escaped convict once said to me:
    "Alcatraz is the place to be"
    Daniele Futtorovic, May 5, 2011
    #4
  5. Jim Janney

    Jim Janney Guest

    Daniele Futtorovic <> writes:

    > On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >> Daniele Futtorovic<> writes:
    >>
    >>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>> 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. So
    >>>> in this case, no, programming to the interface would be the wrong
    >>>> thing to do. The point of design principles is to make you think
    >>>> before you break them :)
    >>>
    >>> Entirely disagreed. The code shown did not contain any justification for
    >>> breaking the pattern in question, and on the opposite, it contained all
    >>> the reasons to think more about encapsulation, which is the true
    >>> underlying rationale for coding to interfaces -- not polymorphism per se.

    >>
    >> The justification is not in the code shown, but in the accompanying
    >> remark "I need the map to retain the insertion order." There's no
    >> interface in the JRE that promises this, and only one class that
    >> provides it, which makes encapsulation, shall we say, difficult.

    >
    > That's not the point! Yes, you need a LinkedHashMap to retain
    > insertion order in a Map. But retaining insertion order is
    > relevant... only when inserting.


    Think a minute. When does retaining insertion order actually matter?
    When you build the map, or some time later when you iterate over it?
    Hint: if you never iterate over it, the order doesn't matter at all.

    --
    Jim Janney
    Jim Janney, May 5, 2011
    #5
  6. Jim Janney

    Lew Guest

    On 05/05/2011 04:14 PM, Jim Janney wrote:
    > Zapanaz<http://joecosby.com/code/> writes:
    >
    >> 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.


    'SortedMap', as so many have said. Apparently you need to practice study of
    the API docs much, much more. We all should know the essential collections
    types. Get studying!

    > 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. So in this case, no,
    > programming to the interface would be the wrong thing to do. The point
    > of design principles is to make you think before you break them :)


    Actually, in this case programming to the interface is the /right/ thing to
    do. Please don't mislead the OP.

    --
    Lew
    Honi soit qui mal y pense.
    http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
    Lew, May 5, 2011
    #6
  7. Jim Janney

    Lew Guest

    Jim Janney wrote:
    > The justification is not in the code shown, but in the accompanying
    > remark "I need the map to retain the insertion order." There's no
    > interface in the JRE that promises this,


    other than
    <http://download.oracle.com/javase/6/docs/api/java/util/SortedMap.html>
    you mean.

    > and only one class that provides it, which makes encapsulation, shall we say, difficult.


    Oh, really?

    Two are listed in the API docs for that "nonexistent" interface, and neither
    one is 'LinkedHashMap'.

    Knowing the collections API is a prerequisite for effective Java programming.

    --
    Lew
    Honi soit qui mal y pense.
    http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
    Lew, May 5, 2011
    #7
  8. Jim Janney

    Jim Janney Guest

    Lew <> writes:

    > On 05/05/2011 04:14 PM, Jim Janney wrote:
    >> Zapanaz<http://joecosby.com/code/> writes:
    >>
    >>> 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.

    >
    > 'SortedMap', as so many have said. Apparently you need to practice
    > study of the API docs much, much more. We all should know the
    > essential collections types. Get studying!


    But that would be wrong, because a SortedMap does something entirely
    different from a LinkedHashMap. Take your own advice before dispensing
    it to others.

    --
    Jim Janney
    Jim Janney, May 5, 2011
    #8
  9. Jim Janney

    Jim Janney Guest

    Lew <> writes:

    > Jim Janney wrote:
    >> The justification is not in the code shown, but in the accompanying
    >> remark "I need the map to retain the insertion order." There's no
    >> interface in the JRE that promises this,

    >
    > other than
    > <http://download.oracle.com/javase/6/docs/api/java/util/SortedMap.html>
    > you mean.
    >
    >> and only one class that provides it, which makes encapsulation, shall we say, difficult.

    >
    > Oh, really?
    >
    > Two are listed in the API docs for that "nonexistent" interface, and
    > neither one is 'LinkedHashMap'.
    >
    > Knowing the collections API is a prerequisite for effective Java programming.


    The original poster said very plainly, "I need the map to retain the
    insertion order." A SortedMap does not do this.

    --
    Jim Janney
    Jim Janney, May 5, 2011
    #9
  10. On 05/05/2011 23:02, Jim Janney allegedly wrote:
    > Daniele Futtorovic<> writes:
    >
    >> On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >>> Daniele Futtorovic<> writes:
    >>>
    >>>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>>> 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. So
    >>>>> in this case, no, programming to the interface would be the wrong
    >>>>> thing to do. The point of design principles is to make you think
    >>>>> before you break them :)
    >>>>
    >>>> Entirely disagreed. The code shown did not contain any justification for
    >>>> breaking the pattern in question, and on the opposite, it contained all
    >>>> the reasons to think more about encapsulation, which is the true
    >>>> underlying rationale for coding to interfaces -- not polymorphism per se.
    >>>
    >>> The justification is not in the code shown, but in the accompanying
    >>> remark "I need the map to retain the insertion order." There's no
    >>> interface in the JRE that promises this, and only one class that
    >>> provides it, which makes encapsulation, shall we say, difficult.

    >>
    >> That's not the point! Yes, you need a LinkedHashMap to retain
    >> insertion order in a Map. But retaining insertion order is
    >> relevant... only when inserting.

    >
    > Think a minute. When does retaining insertion order actually matter?
    > When you build the map, or some time later when you iterate over it?
    > Hint: if you never iterate over it, the order doesn't matter at all.


    I don't need a full minute to see that this is even further beside the
    point.
    Daniele Futtorovic, May 5, 2011
    #10
  11. Jim Janney

    Lew Guest

    Lew, May 5, 2011
    #11
  12. On 11-05-05 06:21 PM, Lew wrote:
    > On 05/05/2011 04:14 PM, Jim Janney wrote:

    [ SNIP ]

    >> 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. So in this case, no,
    >> programming to the interface would be the wrong thing to do. The point
    >> of design principles is to make you think before you break them :)

    >
    > Actually, in this case programming to the interface is the /right/ thing
    > to do. Please don't mislead the OP.
    >

    Well, no. The OP has stated that he needs the map to obey the contract
    of LinkedHashMap: "where I'm creating sortedMap above, I need the map to
    retain the insertion order". This is the normal behaviour of
    LinkedHashMap, that its predictable iteration ordering is
    insertion-order. If he wants a map that has this iterator ordering, he
    wants LinkedHashMap (and possibly no other maps qualify actually; I am
    not 100% certain on this).

    It would be a mistake for the OP to write an API method that returns a
    Map when just any Map won't pass muster. It's not that _his_ method
    won't do the right thing, but that the client code that gets a Map will
    be written to Map, and eventually at some point some other Map
    implementation will get used instead.

    As it happens this example highlights one main thing that interfaces
    don't do, which is to prescribe implementation contracts. Classes do
    that; interfaces can't. And in this particular case there is not even an
    available superclass that also satisfies the implementation contracts.
    So LinkedHashMap is appropriate.

    AHS
    Arved Sandstrom, May 5, 2011
    #12
  13. Jim Janney

    Lew Guest

    Arved Sandstrom wrote:
    > Lew wrote:
    >> Actually, in this case programming to the interface is the /right/ thing
    >> to do. Please don't mislead the OP.
    >>

    > Well, no. The OP has stated that he needs the map to obey the contract
    > of LinkedHashMap: "where I'm creating sortedMap above, I need the map to
    > retain the insertion order". This is the normal behaviour of
    > LinkedHashMap, that its predictable iteration ordering is
    > insertion-order. If he wants a map that has this iterator ordering, he
    > wants LinkedHashMap (and possibly no other maps qualify actually; I am
    > not 100% certain on this).


    Yes, Jim Janney already corrected me on this.

    Mea culpa.

    --
    Lew
    Honi soit qui mal y pense.
    http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
    Lew, May 5, 2011
    #13
  14. On 11-05-05 07:02 PM, Daniele Futtorovic wrote:
    > On 05/05/2011 23:02, Jim Janney allegedly wrote:
    >> Daniele Futtorovic<> writes:
    >>
    >>> On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >>>> Daniele Futtorovic<> writes:
    >>>>
    >>>>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>>>> 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. So
    >>>>>> in this case, no, programming to the interface would be the wrong
    >>>>>> thing to do. The point of design principles is to make you think
    >>>>>> before you break them :)
    >>>>>
    >>>>> Entirely disagreed. The code shown did not contain any
    >>>>> justification for
    >>>>> breaking the pattern in question, and on the opposite, it contained
    >>>>> all
    >>>>> the reasons to think more about encapsulation, which is the true
    >>>>> underlying rationale for coding to interfaces -- not polymorphism
    >>>>> per se.
    >>>>
    >>>> The justification is not in the code shown, but in the accompanying
    >>>> remark "I need the map to retain the insertion order." There's no
    >>>> interface in the JRE that promises this, and only one class that
    >>>> provides it, which makes encapsulation, shall we say, difficult.
    >>>
    >>> That's not the point! Yes, you need a LinkedHashMap to retain
    >>> insertion order in a Map. But retaining insertion order is
    >>> relevant... only when inserting.

    >>
    >> Think a minute. When does retaining insertion order actually matter?
    >> When you build the map, or some time later when you iterate over it?
    >> Hint: if you never iterate over it, the order doesn't matter at all.

    >
    > I don't need a full minute to see that this is even further beside the
    > point.


    Yeah, as in, your argument is incorrect, and Jim is right.

    You see this bit from the LinkedHashMap API?:

    "This implementation spares its clients from the unspecified, generally
    chaotic ordering provided by HashMap (and Hashtable), without incurring
    the increased cost associated with TreeMap. It can be used to produce a
    copy of a map that has the same order as the original, regardless of the
    original map's implementation."

    "Spares its _clients_". You provide this implementation for the
    _clients_. Just any Map won't do, Daniele. And if you "program to the
    interface" blindly, and return a Map from this method, then as long as
    the OP's _unchanged_ code is used to implement

    public Map<String, Integer> getSortedMap()

    then we'll get a LinkedHashMap and obey the desired contract. But down
    the road - since we've failed to specify the requirement - things could
    change, and the original implementation requirement be violated. In fact
    a maintainer will look at the method's return type, and the
    (unfortunate) name of te method, and in the absence of design
    documentation decide maybe to use a SortedMap implementation instead.
    *Which would be a mistake*...but your recommended approach would
    encourage him to do it.

    Don't get all blinded by design principles like "program to the
    interface". Most of the things you access in a real-world complex
    application are exposed through classes, not interfaces.

    AHS
    Arved Sandstrom, May 5, 2011
    #14
  15. On 11-05-05 07:23 PM, Lew wrote:
    > Arved Sandstrom wrote:
    >> Lew wrote:
    >>> Actually, in this case programming to the interface is the /right/ thing
    >>> to do. Please don't mislead the OP.
    >>>

    >> Well, no. The OP has stated that he needs the map to obey the contract
    >> of LinkedHashMap: "where I'm creating sortedMap above, I need the map to
    >> retain the insertion order". This is the normal behaviour of
    >> LinkedHashMap, that its predictable iteration ordering is
    >> insertion-order. If he wants a map that has this iterator ordering, he
    >> wants LinkedHashMap (and possibly no other maps qualify actually; I am
    >> not 100% certain on this).

    >
    > Yes, Jim Janney already corrected me on this.
    >
    > Mea culpa.
    >

    Having had "program to the interface" pounded into my head so
    thoroughly, I was originally going to set the OP straight myself. :)
    But then in the course of researching the API Javadocs and re-reading
    the original post, I twigged to that detail.

    Like I said prior, there is a large area of contracts that cannot be
    specified simply with interfaces. I misspoke when I suggested that it's
    only implementation contracts that interfaces can't handle; in fact this
    "predictable iteration order" is also a behavioural contract that
    interfaces cannot specify. When all is said and done, all that
    interfaces can do in Java is prescribe a group of method signatures.

    Some languages permit more expressibility when composing implementation
    (Scala traits, for example), but ultimately what interfaces don't give
    you in Java, abstract classes do (or in very specific cases like this
    one, one actual concrete class). I _like_ abstract classes; I think the
    pendulum has swung too far now in the "program to interfaces" direction.
    Back in the day inheritance was all the rage; post-GOF it became
    (rightfully so) a somewhat deprecated thing to do, but IMHO there is no
    good reasopn to eschew abstract classes completely.

    In this specific case we have run across the common circumstance where
    only one class fits the bill. And so we may as well use it. :)

    AHS
    Arved Sandstrom, May 6, 2011
    #15
  16. Jim Janney

    Jim Janney Guest

    Daniele Futtorovic <> writes:

    > On 05/05/2011 23:02, Jim Janney allegedly wrote:
    >> Daniele Futtorovic<> writes:
    >>
    >>> On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >>>> Daniele Futtorovic<> writes:
    >>>>
    >>>>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>>>> 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. So
    >>>>>> in this case, no, programming to the interface would be the wrong
    >>>>>> thing to do. The point of design principles is to make you think
    >>>>>> before you break them :)
    >>>>>
    >>>>> Entirely disagreed. The code shown did not contain any justification for
    >>>>> breaking the pattern in question, and on the opposite, it contained all
    >>>>> the reasons to think more about encapsulation, which is the true
    >>>>> underlying rationale for coding to interfaces -- not polymorphism per se.
    >>>>
    >>>> The justification is not in the code shown, but in the accompanying
    >>>> remark "I need the map to retain the insertion order." There's no
    >>>> interface in the JRE that promises this, and only one class that
    >>>> provides it, which makes encapsulation, shall we say, difficult.
    >>>
    >>> That's not the point! Yes, you need a LinkedHashMap to retain
    >>> insertion order in a Map. But retaining insertion order is
    >>> relevant... only when inserting.

    >>
    >> Think a minute. When does retaining insertion order actually matter?
    >> When you build the map, or some time later when you iterate over it?
    >> Hint: if you never iterate over it, the order doesn't matter at all.

    >
    > I don't need a full minute to see that this is even further beside the
    > point.


    In the absence of more code, we have to take the original poster's
    word that callers to getSortedMap() actually depend on the insertion
    order. But there's no reason to suppose they don't: the effects are in
    no way limited to map creation.

    --
    Jim Janney
    Jim Janney, May 6, 2011
    #16
  17. On 06/05/2011 00:49, Arved Sandstrom allegedly wrote:
    > On 11-05-05 07:02 PM, Daniele Futtorovic wrote:
    >> On 05/05/2011 23:02, Jim Janney allegedly wrote:
    >>> Daniele Futtorovic<> writes:
    >>>
    >>>> On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >>>>> Daniele Futtorovic<> writes:
    >>>>>
    >>>>>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>>>>> 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. So
    >>>>>>> in this case, no, programming to the interface would be the wrong
    >>>>>>> thing to do. The point of design principles is to make you think
    >>>>>>> before you break them :)
    >>>>>>
    >>>>>> Entirely disagreed. The code shown did not contain any
    >>>>>> justification for
    >>>>>> breaking the pattern in question, and on the opposite, it contained
    >>>>>> all
    >>>>>> the reasons to think more about encapsulation, which is the true
    >>>>>> underlying rationale for coding to interfaces -- not polymorphism
    >>>>>> per se.
    >>>>>
    >>>>> The justification is not in the code shown, but in the accompanying
    >>>>> remark "I need the map to retain the insertion order." There's no
    >>>>> interface in the JRE that promises this, and only one class that
    >>>>> provides it, which makes encapsulation, shall we say, difficult.
    >>>>
    >>>> That's not the point! Yes, you need a LinkedHashMap to retain
    >>>> insertion order in a Map. But retaining insertion order is
    >>>> relevant... only when inserting.
    >>>
    >>> Think a minute. When does retaining insertion order actually matter?
    >>> When you build the map, or some time later when you iterate over it?
    >>> Hint: if you never iterate over it, the order doesn't matter at all.

    >>
    >> I don't need a full minute to see that this is even further beside the
    >> point.

    >
    > Yeah, as in, your argument is incorrect, and Jim is right.
    >
    > You see this bit from the LinkedHashMap API?:
    >
    > "This implementation spares its clients from the unspecified, generally
    > chaotic ordering provided by HashMap (and Hashtable), without incurring
    > the increased cost associated with TreeMap. It can be used to produce a
    > copy of a map that has the same order as the original, regardless of the
    > original map's implementation."
    >
    > "Spares its _clients_". You provide this implementation for the
    > _clients_. Just any Map won't do, Daniele. And if you "program to the
    > interface" blindly, and return a Map from this method, then as long as
    > the OP's _unchanged_ code is used to implement
    >
    > public Map<String, Integer> getSortedMap()
    >
    > then we'll get a LinkedHashMap and obey the desired contract. But down
    > the road - since we've failed to specify the requirement - things could
    > change, and the original implementation requirement be violated. In fact
    > a maintainer will look at the method's return type, and the
    > (unfortunate) name of te method, and in the absence of design
    > documentation decide maybe to use a SortedMap implementation instead.
    > *Which would be a mistake*...but your recommended approach would
    > encourage him to do it.
    >
    > Don't get all blinded by design principles like "program to the
    > interface". Most of the things you access in a real-world complex
    > application are exposed through classes, not interfaces.


    I can't say I take too kindly to your assertion that I intervened as I
    did for the sake of blindly following anything.

    Neither do I agree with your interpretation of the bit of Javadoc you
    quoted. No, you do not provide a LinkedHashMap to clients. You provide a
    Map with the same iteration order as another. Nuance.

    The return type being a LinkedHashMap, itself, doesn't tell you
    _anything_ about its iteration order. Take the following code:

    ################################################
    interface Function<K, V> {
    V f( K k );
    }

    static <T> LinkedHashMap<T, V> map( Map<T, U> input, Function f ){
    Map<T, V> ret = new HashMap<T, V>();
    for( Map.Entry<T, U> entry: input.entrySet() ){
    ret.put( entry.getKey(), f.f( entry.getValue() ) );
    }
    return new LinkedHashMap<T, V>( ret );
    }

    Q: What does the return type tell you about the iteration order of the
    returned instance?
    ################################################

    Like it or not, only the method's *contract*, if anything, can guarantee
    you that the returned instance will iterate in the same order as the input.

    And all this has squat to do with my calling Jim's last reply beside the
    point.

    Jim correctly quoted the OP saying: "I need the map to retain the
    insertion order". Given that constraint, it is irrelevant to question in
    which cases retaining insertion order matters or not. Which he did
    afterwards. In reply to which I said it was beside the point.

    --
    DF.
    An escaped convict once said to me:
    "Alcatraz is the place to be"
    Daniele Futtorovic, May 6, 2011
    #17
  18. On 06/05/2011 01:17, Jim Janney allegedly wrote:
    > Daniele Futtorovic<> writes:
    >
    >> On 05/05/2011 23:02, Jim Janney allegedly wrote:
    >>> Daniele Futtorovic<> writes:
    >>>
    >>>> On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >>>>> Daniele Futtorovic<> writes:
    >>>>>
    >>>>>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>>>>> 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. So
    >>>>>>> in this case, no, programming to the interface would be the wrong
    >>>>>>> thing to do. The point of design principles is to make you think
    >>>>>>> before you break them :)
    >>>>>>
    >>>>>> Entirely disagreed. The code shown did not contain any justification for
    >>>>>> breaking the pattern in question, and on the opposite, it contained all
    >>>>>> the reasons to think more about encapsulation, which is the true
    >>>>>> underlying rationale for coding to interfaces -- not polymorphism per se.
    >>>>>
    >>>>> The justification is not in the code shown, but in the accompanying
    >>>>> remark "I need the map to retain the insertion order." There's no
    >>>>> interface in the JRE that promises this, and only one class that
    >>>>> provides it, which makes encapsulation, shall we say, difficult.
    >>>>
    >>>> That's not the point! Yes, you need a LinkedHashMap to retain
    >>>> insertion order in a Map. But retaining insertion order is
    >>>> relevant... only when inserting.
    >>>
    >>> Think a minute. When does retaining insertion order actually matter?
    >>> When you build the map, or some time later when you iterate over it?
    >>> Hint: if you never iterate over it, the order doesn't matter at all.

    >>
    >> I don't need a full minute to see that this is even further beside the
    >> point.

    >
    > In the absence of more code, we have to take the original poster's
    > word that callers to getSortedMap() actually depend on the insertion
    > order. But there's no reason to suppose they don't: the effects are in
    > no way limited to map creation.
    >


    Actually, he doesn't exactly say that /callers/ depend on insertion
    order. He said:
    > where I'm creating sortedMap above, I need the map to
    > retain the insertion order


    I interpret "where I'm creating the map" as being in the getSortedMap()
    method. Perhaps he really meant the code that calls getSortedMap(), in
    which case this method would be a factory method. But I assumed it
    wasn't, because of the getter-like name, and also because of what he
    said further below.
    If it were a factory method -- then yes, by all means. If it's a factory
    method that creates a map retaining insertion order, then its return
    type should be LinkedHashMap.
    But that's actually the only exception I can think of. I cannot fathom
    any other, normal OO case where LinkedHashMap would make sense as the
    type of a parameter to, or the return type of any method.

    --
    DF.
    An escaped convict once said to me:
    "Alcatraz is the place to be"
    Daniele Futtorovic, May 6, 2011
    #18
  19. On 11-05-05 09:28 PM, Daniele Futtorovic wrote:
    > On 06/05/2011 00:49, Arved Sandstrom allegedly wrote:
    >> On 11-05-05 07:02 PM, Daniele Futtorovic wrote:
    >>> On 05/05/2011 23:02, Jim Janney allegedly wrote:
    >>>> Daniele Futtorovic<> writes:
    >>>>
    >>>>> On 05/05/2011 22:42, Jim Janney allegedly wrote:
    >>>>>> Daniele Futtorovic<> writes:
    >>>>>>
    >>>>>>> On 05/05/2011 22:14, Jim Janney allegedly wrote:
    >>>>>>>> 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. So
    >>>>>>>> in this case, no, programming to the interface would be the wrong
    >>>>>>>> thing to do. The point of design principles is to make you think
    >>>>>>>> before you break them :)
    >>>>>>>
    >>>>>>> Entirely disagreed. The code shown did not contain any
    >>>>>>> justification for
    >>>>>>> breaking the pattern in question, and on the opposite, it contained
    >>>>>>> all
    >>>>>>> the reasons to think more about encapsulation, which is the true
    >>>>>>> underlying rationale for coding to interfaces -- not polymorphism
    >>>>>>> per se.
    >>>>>>
    >>>>>> The justification is not in the code shown, but in the accompanying
    >>>>>> remark "I need the map to retain the insertion order." There's no
    >>>>>> interface in the JRE that promises this, and only one class that
    >>>>>> provides it, which makes encapsulation, shall we say, difficult.
    >>>>>
    >>>>> That's not the point! Yes, you need a LinkedHashMap to retain
    >>>>> insertion order in a Map. But retaining insertion order is
    >>>>> relevant... only when inserting.
    >>>>
    >>>> Think a minute. When does retaining insertion order actually matter?
    >>>> When you build the map, or some time later when you iterate over it?
    >>>> Hint: if you never iterate over it, the order doesn't matter at all.
    >>>
    >>> I don't need a full minute to see that this is even further beside the
    >>> point.

    >>
    >> Yeah, as in, your argument is incorrect, and Jim is right.
    >>
    >> You see this bit from the LinkedHashMap API?:
    >>
    >> "This implementation spares its clients from the unspecified, generally
    >> chaotic ordering provided by HashMap (and Hashtable), without incurring
    >> the increased cost associated with TreeMap. It can be used to produce a
    >> copy of a map that has the same order as the original, regardless of the
    >> original map's implementation."
    >>
    >> "Spares its _clients_". You provide this implementation for the
    >> _clients_. Just any Map won't do, Daniele. And if you "program to the
    >> interface" blindly, and return a Map from this method, then as long as
    >> the OP's _unchanged_ code is used to implement
    >>
    >> public Map<String, Integer> getSortedMap()
    >>
    >> then we'll get a LinkedHashMap and obey the desired contract. But down
    >> the road - since we've failed to specify the requirement - things could
    >> change, and the original implementation requirement be violated. In fact
    >> a maintainer will look at the method's return type, and the
    >> (unfortunate) name of te method, and in the absence of design
    >> documentation decide maybe to use a SortedMap implementation instead.
    >> *Which would be a mistake*...but your recommended approach would
    >> encourage him to do it.
    >>
    >> Don't get all blinded by design principles like "program to the
    >> interface". Most of the things you access in a real-world complex
    >> application are exposed through classes, not interfaces.

    >
    > I can't say I take too kindly to your assertion that I intervened as I
    > did for the sake of blindly following anything.


    OK, I'll retract the word "blind". I see you arguing strenuously for the
    use of Map, and in this case I believe you're wrong. How's that?

    > Neither do I agree with your interpretation of the bit of Javadoc you
    > quoted. No, you do not provide a LinkedHashMap to clients. You provide a
    > Map with the same iteration order as another. Nuance.


    It's not about providing a Map with the same iteration order as
    "another". There might be no "other". In the case of a stock
    LinkedHashMap we know that the predictable iteration order is insertion
    order. But mainly the contract we're after is predictable iteration
    order, regardless of how the map was loaded. That is what the Javadoc says.

    As far as your nuance is concerned, I'm interested (the _OP_ is
    interested) in providing a map with predictable insertion order. Map
    does not satisfy that; LinkedHashMap does. If I return Map then I am
    making a mistake.

    > The return type being a LinkedHashMap, itself, doesn't tell you
    > _anything_ about its iteration order.


    ??? It tells me that it has a predictable iteration order (which happens
    to be insertion order). It's the _predictable_ bit that is important.
    That it happens to be insertion order is a bonus but not the key point.

    > Take the following code:
    >
    > ################################################
    > interface Function<K, V> {
    > V f( K k );
    > }
    >
    > static <T> LinkedHashMap<T, V> map( Map<T, U> input, Function f ){
    > Map<T, V> ret = new HashMap<T, V>();
    > for( Map.Entry<T, U> entry: input.entrySet() ){
    > ret.put( entry.getKey(), f.f( entry.getValue() ) );
    > }
    > return new LinkedHashMap<T, V>( ret );
    > }
    >
    > Q: What does the return type tell you about the iteration order of the
    > returned instance?
    > ################################################
    >
    > Like it or not, only the method's *contract*, if anything, can guarantee
    > you that the returned instance will iterate in the same order as the input.


    Input? Did you see the OP's method signature? Why not stick to that? As
    it happens _your_ method does something different: it takes its input,
    preprocesses it, and _only then_ does anything with LinkedHashMap.
    Ironically the

    return new LinkedHashMap<T, V>( ret );

    retains the insertion order of the "ret" pre-processed map, and does
    what LinkedHashMap is supposed to do.

    All that fancy cruft you have prior is irrelevant and belongs in your
    concocted method...which is not the original method signature. If you're
    going to highlight method contracts, kindly use the same one as is being
    discussed.

    > And all this has squat to do with my calling Jim's last reply beside the
    > point.
    >
    > Jim correctly quoted the OP saying: "I need the map to retain the
    > insertion order". Given that constraint, it is irrelevant to question in
    > which cases retaining insertion order matters or not. Which he did
    > afterwards. In reply to which I said it was beside the point.
    >

    In the original post, did you see an _input_ Map to getSortedMap()?

    AHS
    Arved Sandstrom, May 6, 2011
    #19
  20. Lew <> writes:
    > Jim Janney wrote:
    >> The justification is not in the code shown, but in the accompanying
    >> remark "I need the map to retain the insertion order." There's no
    >> interface in the JRE that promises this,


    > other than
    > <http://download.oracle.com/javase/6/docs/api/java/util/SortedMap.html>
    > you mean.


    But I'm looking at the SortedMap and LinkedHashMap javadocs, and it
    seems to me that LinkedHashMap doesn't implement the SortedMap
    interface.
    So, defining the return value as SortedMap you'd have to change the
    actual implementation class.

    --
    Jukka Lahtinen
    Jukka Lahtinen, May 6, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steven Simpson
    Replies:
    5
    Views:
    343
  2. Roedy Green
    Replies:
    1
    Views:
    315
    Jim Janney
    May 6, 2011
  3. Michal Kleczek
    Replies:
    10
    Views:
    532
    Arved Sandstrom
    May 10, 2011
  4. Pallav singh
    Replies:
    0
    Views:
    358
    Pallav singh
    Jan 22, 2012
  5. Pallav singh
    Replies:
    0
    Views:
    399
    Pallav singh
    Jan 22, 2012
Loading...

Share This Page