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