On 19 Jul 2011, at 11:43, Reto Bachmann-Gmür wrote:

> I think it's important to identify anti-pattern. Post a link here if
> you document the anti-pattern you think you've discovered on the scala
> mailing list.

I asked the question on the Scala mailing list, here:

  https://groups.google.com/d/topic/scala-user/IsJ1yXjd2lw/discussion

There seems to be unanimous agreement that this is an ant-pattern. But I am 
trying
to make sure that your name is associated with it since you have been so 
insistent
on this point. Currently I am favoring the name"Pimpin Reto". Perhaps it will 
take on.


> As for the copying around triples I think we should work with unions
> and not copying around triples, changing this might have some impact
> on the api so I disagree in having the copy solution in trunk.
> 
> The example you describe as error-prone is unnecessarily calling
> methods on an explicit instance (see my comment on the issue:
> https://issues.apache.org/jira/browse/CLEREZZA-603?focusedCommentId=13063414&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13063414)
> this makes it verbose an error prone:
> 
> import ez1._
> //here we are working on the MGraph ez1
> b_("reto") -- FOAF.homepage --> "http://bblfish.net/".uri
> 
> import ez2._
> //here we are working on the MGraph ez2
> b_("hjs") -- FOAF.homepage --> "http://bblfish.net/".uri
> 
> Remeber that when we change bnode and b_ to return a GraphNode we need
> to add a dynamic conversion from GraphNode to Node to keep the
> existing functionality.
> 
> Reto
> 
> 
> On Tue, Jul 19, 2011 at 11:27 AM, Henry Story (JIRA) <[email protected]> wrote:
>> 
>>    [ 
>> https://issues.apache.org/jira/browse/CLEREZZA-603?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13067591#comment-13067591
>>  ]
>> 
>> Henry Story commented on CLEREZZA-603:
>> --------------------------------------
>> 
>> In that discussion I ended up explaining in detail why the current problem 
>> exists. But in order
>> to understant the problem one has to first understand what is on in 
>> constructs such as the following:
>> 
>>  reto.a(FOAF.Person)
>>          -- FOAF.knows --> (
>>                "http://bblfish.net/#hjs".uri.a(FOAF.Person)
>>                        -- FOAF.name --> "Henry Story"
>>                        -- FOAF.currentProject --> "http://webid.info/".uri
>>               )
>> 
>>  Starting from the center, let us see how implicits are getting used here:
>> 
>>  1.  "http://bblfish.net/#hjs".uri.a(FOAF.Person)
>> 
>>  a)   gets transformed into
>> 
>>        new URIRef("http://bblfish.net/#hjs";)
>> 
>>     because the .uri method is defined on EzLiteral and there is the
>>     implicit def string2lit(str: String) = new EzLiteral(str)
>> 
>>  b)  then it gets transformed into a RichGraphNode - let's call it 
>> anon_rgn_hjs - because the method a(..) is defined there and because of the 
>> implicit (call it IMP)
>> 
>>      implicit def toRichGraphNode(resource: Resource) = {
>>                new RichGraphNode(new GraphNode(resource, baseTc))
>>        }
>> 
>>  2. Then the RichGraphNode anon_rgn_hjs is filled out with the FOAF.name and 
>> FOAF.currentProject relations
>> 
>>  3. reto - a rich graph node - is then related by foaf knows to 
>> anon_rgn_hjs.resource
>>       by the following function
>> 
>>                def -->(sub: GraphNode): RichGraphNode = {
>>                        //RichGraphNode.this + sub
>>                        -->(sub.getNode)
>>                }
>> 
>> 
>>   QUESTION: what happens to the graph of anon_rgn_hjs ? How does it get 
>> added to the graph of reto?
>>   --------
>> 
>>  Well this occurs because of the implicit IMP  which this whole issue is 
>> questioning the wisdom of,
>> 
>> 
>>     implicit def toRichGraphNode(resource: Resource) = {
>>                new RichGraphNode(new GraphNode(resource, baseTc))
>>     }
>> 
>>   Notice that the implicit created a new GraphNode, whose graph is called 
>> "baseTc". But where does baseTc come from?
>> Ahah. IMP is part of a trait:
>> 
>> protected trait TcDependentConversions extends TcIndependentConversions {
>> 
>>        def baseTc: TripleCollection
>> 
>>        implicit def toRichGraphNode(resource: Resource) = {
>>                new RichGraphNode(new GraphNode(resource, baseTc))
>>        }
>> }
>> 
>> And  EzMGraph is defined as extending that trait.
>> 
>>    class EzMGraph(val baseTc: MGraph) extends AbstractMGraph with 
>> TcDependentConversions
>> 
>> 
>> putting it together:
>> -------------------
>> 
>> When you create a new EzMGraph - call it ez - you create an object with the 
>> toRichGraphNode() implicit, whose baseTc set to that Graph's tc collection. 
>> The you
>> 
>>  import ez._
>> 
>> to import that implicit so that it becomes available for usage. Of course 
>> that implicit is tightly tied to ez.
>> So this explains then how anon_rgn_hjs gets added to ez. It's because when 
>> in 1b above when
>> new URIRef("http://bblfish.net/#hjs";) was transformed into a RichGraphNode 
>> using the IMP implicit, the
>> graph of ez was added as its backing store.
>> 
>> Ok so all that is really clever! But just a bit too clever by half, sadly.
>> 
>> Remember that the point of this patch is to fix the real problem with the 
>> current framework, which is that
>> currently if you have two graphs you need to keep writing the import 
>> statements every time you wish to
>> change graph. Like this:
>> 
>>  import ez1._
>>  ez1.b_("reto") -- FOAF.homepage --> "http://bblfish.net/".uri
>> 
>>  import ez2._
>>  ez2.b_("hjs") -- FOAF.homepage --> "http://bblfish.net/".uri
>> 
>>  import ez1._
>>  ez1.b_("reto") -- FOAF.currentProject --> "http://clerezza.org/".uri
>> 
>> 
>> This is very error prone it seems to me.
>> 
>> And the reason we have that error, is because of the an implicit that is tied
>> to a hidden variable. This is very clearly a Scala anti-pattern.
>> 
>> 
>>> EzMGraph fails when working with more than one instance
>>> -------------------------------------------------------
>>> 
>>>                 Key: CLEREZZA-603
>>>                 URL: https://issues.apache.org/jira/browse/CLEREZZA-603
>>>             Project: Clerezza
>>>          Issue Type: Bug
>>>            Reporter: Henry Story
>>>            Priority: Critical
>>>         Attachments: 
>>> 0001-CLEREZZA-603-EzMGraph.bnode-now-returns-a-RichGraphN.patch
>>> 
>>>   Original Estimate: 1h
>>>  Remaining Estimate: 1h
>>> 
>>> All the EzMGraph test cases currently assume that there is only one ez 
>>> graph available per method.
>>> When one adds two EzMGraphs together in some code one gets a failure as the 
>>> following test case shows when run in EzMGraphTest class:
>>>       @Test
>>>       def twographs {
>>>               val ez1 = new EzMGraph() {(
>>>                       b_("reto") -- FOAF.name --> "Reto 
>>> Bachman-Gmür".lang("rm")
>>>               )}
>>>               Assert.assertEquals("the two graphs should be 
>>> equal",1,ez1.size)
>>>               import ez1._
>>>               ez1.b_("reto") -- FOAF.homepage --> "http://bblfish.net/".uri
>>>               Assert.assertEquals("ez1 has grown by one",2,ez1.size)
>>>               //now a second graph
>>>               val ez2 = new EzMGraph() {(
>>>                       b_("hjs") -- FOAF.name --> "Henry Story"
>>>               )}
>>>               ez2.b_("hjs") -- FOAF.homepage --> "http://bblfish.net/".uri
>>>                //both of these tests fail
>>>               Assert.assertEquals("ez1 is the same size as it used to 
>>> be",2,ez1.size)
>>>               Assert.assertEquals("ez2 has grown by one",2,ez2.size)
>>>       }
>>> This is caused by a bit too much implicit magic.  EzMGraph extends 
>>> TcDependentConversions which is defined as
>>> protected trait TcDependentConversions {
>>> 
>>>       def baseTc: TripleCollection
>>> 
>>>       implicit def toRichGraphNode(resource: Resource) = {
>>>               new RichGraphNode(new GraphNode(resource, baseTc))
>>>       }
>>> }
>>> So when developing this one has to import the toRichGraphNode method for 
>>> the TripleCollection one is using.
>>> Hence you will see the first
>>>               import ez1._
>>> above. The errors can be avoided if one enters a new import for ez2._ just 
>>> before code using ez2 . The problem is that this will never be picked up by 
>>> the compiler and the error will only be found at runtime. But then code 
>>> would look like this
>>>               import ez1._
>>>               ez1.b_("reto") -- FOAF.homepage --> "http://bblfish.net/".uri
>>>                 import ez2._
>>>               ez2.b_("hjs") -- FOAF.homepage --> "http://bblfish.net/".uri
>>>               import ez1._
>>>                       ez1.b_("reto") -- FOAF.currentProject --> 
>>> "http://clerezza.org/".uri
>>> The answer to this problem is simply to have the ez1.b_ method return a 
>>> RichGraphNode directly containing the EzGraphNode from which it was called.
>>> It makes more sense anyway to have a Graph return a GraphNode when one asks 
>>> for a node from it. Certainly a BNode outside of the context of a graph 
>>> makes very little sense.
>>> 
>> 
>> --
>> This message is automatically generated by JIRA.
>> For more information on JIRA, see: http://www.atlassian.com/software/jira
>> 
>> 
>> 

Social Web Architect
http://bblfish.net/

Reply via email to