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.

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

Reply via email to