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/
