incubator-clerezza-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Reto Bachmann-Gmür ...@farewellutopia.com>
Subject Re: [jira] [Commented] (CLEREZZA-603) EzMGraph fails when working with more than one instance
Date Tue, 19 Jul 2011 09:43:13 GMT
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) <jira@apache.org> 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
>
>
>

Mime
View raw message