User Tools

Site Tools


why_isn_t_it_dci_if_you_use_a_wrapper_object_to_represent_the_role

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

why_isn_t_it_dci_if_you_use_a_wrapper_object_to_represent_the_role [2014/01/14 22:20]
jcoplien created
why_isn_t_it_dci_if_you_use_a_wrapper_object_to_represent_the_role [2014/01/26 21:10] (current)
jcoplien
Line 1: Line 1:
-=== Why isn't it DCI if you use a wrapper object to represent the role? ===+====== Why isn't it DCI if you use a wrapper object to represent the Role======
  
 Explaining it kind of spoils the fun... There are several ways to explain this. Let me try this way. I'm winging it, and this won't pass for a published paper. And it's a difficult topic, and even more difficult to explain it to someone who doesn'​t already know it. I'll do my best. Explaining it kind of spoils the fun... There are several ways to explain this. Let me try this way. I'm winging it, and this won't pass for a published paper. And it's a difficult topic, and even more difficult to explain it to someone who doesn'​t already know it. I'll do my best.
Line 5: Line 5:
 Ruby convention embraces, among others, the following binary operators (see [[http://​kentreis.wordpress.com/​2007/​02/​08/​identity-and-equality-in-ruby-and-smalltalk/​|http://​kentreis.wordpress.com/​2007/​02/​08/​identity-and-equality-in-ruby-and-smalltalk/​]]):​ Ruby convention embraces, among others, the following binary operators (see [[http://​kentreis.wordpress.com/​2007/​02/​08/​identity-and-equality-in-ruby-and-smalltalk/​|http://​kentreis.wordpress.com/​2007/​02/​08/​identity-and-equality-in-ruby-and-smalltalk/​]]):​
  
-<​code>​puts "​Object 1 is == to object 2: #{object1 == object2}"​ +<​code ​ruby   puts "​Object 1 is == to object 2: #{object1 == object2}"​ 
-puts "​Object 1 is eql? to object 2: #​{object1.eql?​ object2}"​ +    puts "​Object 1 is eql? to object 2: #​{object1.eql?​ object2}"​ 
-puts "​Object 1 is equal? to object 2: #​{object1.equal?​ object2}"</​code>​+    puts "​Object 1 is equal? to object 2: #​{object1.equal?​ object2}"</​code>​
  
 Let me emphasize that these are all accessible to application programmers (i.e. they aren't just for platform, framework or compiler people), and that they mean different things. Usually ''​==''​ designates value equality. In Ruby it can be redefined. That means that even with a wrapper implementation you can fool clients into believing that two different objects are "​equal."​ The only exception here is ''​.equal?'',​ which you can't redefine without totally redefining what it means to be an object. (More on this below but, briefly, it's the identity operator and, by definition, an object has state, identity and behavior.) Let me emphasize that these are all accessible to application programmers (i.e. they aren't just for platform, framework or compiler people), and that they mean different things. Usually ''​==''​ designates value equality. In Ruby it can be redefined. That means that even with a wrapper implementation you can fool clients into believing that two different objects are "​equal."​ The only exception here is ''​.equal?'',​ which you can't redefine without totally redefining what it means to be an object. (More on this below but, briefly, it's the identity operator and, by definition, an object has state, identity and behavior.)
Line 17: Line 17:
 So let's say that you write an algorithm like Dijkstra'​s algorithm and you want to know if a give object is in the set of unvisited objects. Consider this code: So let's say that you write an algorithm like Dijkstra'​s algorithm and you want to know if a give object is in the set of unvisited objects. Consider this code:
  
-<​code>​unvisited.each_key { +<​code ​ruby   unvisited.each_key { 
-    |intersection| +        |intersection| 
-    if unvisited[intersection] +        if unvisited[intersection] 
-        if intersection.tentative_distance < min +            if intersection.tentative_distance < min 
-            min = intersection.tentative_distance +                min = intersection.tentative_distance 
-            selection = intersection+                selection = intersection 
 +            end
         end         end
-    ​end +    }</​code>​
-}</​code>​+
  
 The question is: How does ''​unvisited[intersection]''​ work? It's a hash lookup. It turns out that hash uses ''​==''​ (think of it as a loop going through an associative data structure doing comparison on the keys.) The question is: How does ''​unvisited[intersection]''​ work? It's a hash lookup. It turns out that hash uses ''​==''​ (think of it as a loop going through an associative data structure doing comparison on the keys.)
Line 35: Line 35:
 And in my [[http://​fulloo.info/​Examples/​RubyExamples/​Dijkstra/​DijkstraListing.html|Dijkstra example]], I have done exactly that. And in my [[http://​fulloo.info/​Examples/​RubyExamples/​Dijkstra/​DijkstraListing.html|Dijkstra example]], I have done exactly that.
  
-A fundamental problem arises in wrapped implementations. Let's say that I wrap domain class instance O with role wrapper south_neighbor. At some point the same object is wrapped with the role west_neighbor+A fundamental problem arises in wrapped implementations. Let's say that I wrap domain class instance O with role wrapper ​''​south_neighbor''​. At some point the same object is wrapped with the role ''​west_neighbor''​
 in another iteration (or recursion) of Dijkstra'​s algorithm. Which of these is true? in another iteration (or recursion) of Dijkstra'​s algorithm. Which of these is true?
  
-<​code> ​   west_neighbor == south_neighbor+<​code ​ruby>    west_neighbor == south_neighbor
     west_neighbor .eql? south_neighbor     west_neighbor .eql? south_neighbor
     west_neighbor .equal? south_neighbor</​code>​     west_neighbor .equal? south_neighbor</​code>​
  
-It depends. The wrapping people say you can "fake out" the ''​==''​ case because, after all, the object paradigm doesn'​t stipulate what value comparison means. But you can't fake out ''​.equal?''​ without violating object identity. In theory a wrapper could re-define .equal? but it's a real mess. What if the wrapped object were wrapped again? How many levels deep of fake-out does one need? How does one know whether to propagate the fake-out or to take the pointer directly? And how about other parts of application code that honestly depend on on .equal? meaning "​object identity"​ for real?+It depends. The wrapping people say you can "fake out" the ''​==''​ case because, after all, the object paradigm doesn'​t stipulate what value comparison means. But you can't fake out ''​.equal?''​ without violating object identity. In theory a wrapper could re-define ​''​.equal?'' ​but it's a real mess. What if the wrapped object were wrapped again? How many levels deep of fake-out does one need? How does one know whether to propagate the fake-out or to take the pointer directly? And how about other parts of application code that honestly depend on on .equal? meaning "​object identity"​ for real?
  
-The Dijkstra example is a no-win scimitar for wrapper aficionados. That'why, with wrappers, you can only *almostmakes it work. I hope you don't work for a company with the goal of delivering software to me that *almostworks... That's where the wrapper folks belong.+The Dijkstra example is a no-win scimitar for wrapper aficionados. That'why, with wrappers, you can only //almost// makes it work. I hope you don't work for a company with the goal of delivering software to me that //almost// works... That's where the wrapper folks belong.
  
 This was a nightmarish bug in the development of DCI. There is no way Trygve could get it to work in Smalltalk, particularly with return values from methods. It was hell to find the problem. This was a nightmarish bug in the development of DCI. There is no way Trygve could get it to work in Smalltalk, particularly with return values from methods. It was hell to find the problem.
  
-Some guys published a paper at SPLASH ​last year proving that you could hide all of this distinction behind a wrapper. I disproved the paper in a single program, and the record has been set straight in this year's SPLASH proceedings,​ demonstrating that the earlier paper was flawed.+Some guys published a paper at ECOOP last year ((Hermann, Stephan. Demystifyng object schizophrenia. MASPEGHI Workshop (MechAnisms for SPEcialization,​ Generali-zation and inHerItance),​ at ECOOP'​10,​ Maribor, Slovenia.)) ​proving that you could hide all of this distinction behind a wrapper. I disproved the paper in a single program, and the record has been set straight in this year's SPLASH proceedings,​ demonstrating that the earlier paper was flawed.
  
 This, at some level, lies at the core of what object-oriented programming is about. OOP has a different virtual machine model than with procedural programming. In C, variables are memory locations: there is no way to separate an identifier from an address. We simulate this in C using pointers, but the pointer itself is an object that, in a given scope instantiation,​ is indelibly bound to some memory location. In OOP identifiers and objects are two different things. True OO languages drive their memory management model from this fact: when the last label is unpeeled from an object, then the object is not reachable from anywhere in the program, and its memory may be reclaimed. This is sometimes called garbage collection. This, at some level, lies at the core of what object-oriented programming is about. OOP has a different virtual machine model than with procedural programming. In C, variables are memory locations: there is no way to separate an identifier from an address. We simulate this in C using pointers, but the pointer itself is an object that, in a given scope instantiation,​ is indelibly bound to some memory location. In OOP identifiers and objects are two different things. True OO languages drive their memory management model from this fact: when the last label is unpeeled from an object, then the object is not reachable from anywhere in the program, and its memory may be reclaimed. This is sometimes called garbage collection.
Line 59: Line 59:
  
 To not understand the fundamental failure of wrappers is to have only a shallow understanding of object-oriented programming. (And you have this straight from the guy who popularized PIMPLs ([[http://​c2.com/​cgi/​wiki?​PimplIdiom|http://​c2.com/​cgi/​wiki?​PimplIdiom]]).) To not understand the fundamental failure of wrappers is to have only a shallow understanding of object-oriented programming. (And you have this straight from the guy who popularized PIMPLs ([[http://​c2.com/​cgi/​wiki?​PimplIdiom|http://​c2.com/​cgi/​wiki?​PimplIdiom]]).)
 +
 +----
 +
 +
 +
why_isn_t_it_dci_if_you_use_a_wrapper_object_to_represent_the_role.1389738002.txt.gz · Last modified: 2014/01/14 22:20 by jcoplien