incubator-clerezza-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Henry Story <henry.st...@bblfish.net>
Subject Solution: taking context seriously was: A scala anti pattern -- looking for a name
Date Fri, 22 Jul 2011 08:12:17 GMT
Great I think I have the solution now.

This thread [1] has helped a lot to make clear the use of context, why imports that bring
behaviour with them
are confusing (they loose context) but  also why it was tempting to use them. It turns out
then that one has to take
context seriously, and rewrite the library in order not to have to use the confusing implicit
imports whilst making code 
as easy to read as if they were there (because they will be).  Ie: we can use those imports
but make them explicit, 
without ever writing them. If that sounds confusing, it turns out not to be in practice, as
the following code shows.

One can easily create two graph:

	val ez1 = new context {
		b_("reto") -- FOAF.name --> "Reto Bachman-Gmür".lang("rm")
                                -- FOAF.homepage --> "http://bblfish.net/".uri
	}.graph

	val ez2 = new context {
		b_("hjs") -- FOAF.name --> "Henry Story"

	}.graph

but one can then easily continue writing in each graph, in a layered way without confusion

	new context(ez1) {
	       b_("reto") -- FOAF.interest --> "scala"
	}

	new context(ez2) {
	       b_("hjs") -- FOAF.homepage --> "http://bblfish.net".uri
	}

The context protects the blank nodes in the context, so they can't jump from one context to
the other
(well they can because the framework at the top is leaky - but that is something for another
day),
the subject of the context is very clear too, and one can even add methods to this context.

The only thing that is odd from a technical perspective is that this will create a bunch of
classes on 
each "new". 

   So I must admit without the discussion I would not have walked down this path, which seems
like a good one.

Henry

The commit for this is here:
   https://github.com/bblfish/clerezza/commit/6c95c934f15b96c753e3e8eb091482ccaf1b5e32

The files to look at are the new context class
     
 https://github.com/bblfish/clerezza/blob/6c95c934f15b96c753e3e8eb091482ccaf1b5e32/parent/rdf.scala.utils/src/main/scala/org/apache/clerezza/rdf/scala/utils/context.scala

But especially the test class that has many examples of usage
  https://github.com/bblfish/clerezza/blob/6c95c934f15b96c753e3e8eb091482ccaf1b5e32/parent/rdf.scala.utils/src/test/scala/org/apache/clerezza/rdf/scala/utils/EzMGraphTest.scala

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

On 21 Jul 2011, at 21:32, Henry Story wrote:

> 
> On 21 Jul 2011, at 15:32, Rex Kerr wrote:
> 
>> But anyway, I am less concerned about the library than about standard use cases.
 Would anyone want to use different graphs?  If yes, selecting them based on sort-of-hidden
context is unwise.  Henry's example made it look like using different graphs was a pretty
reasonable thing to do.  And note that a one-character variable is a lot more informative
than a zero-variable character:
>> 
>>   graphContext(definitionsPreamble.currentGraph) { g =>
>>     whatever -- g(edgelabel) --> soandso
>>   }
>> 
>> Now you have, with a couple extra characters per call, documentation of what the
relevant context is.
> 
> 
> Thanks Rex. This discussion has helped me also see how it could have seemed so 
> attractive for Reto to want to use this import behaviour.
> 
> We start from something very nice and simple we can all agree on (pretty much)
> 
>    val g = new EzMGraph {
>          reto -- FOAF.knows --> ( bnode --FOAF.name --> "henry" )
>                 -- FOAF.knows -->  danny
>    }
> 
> This is both nice and readable, efficient and context bound. (And this was one of Reto's
early ideas.)
> So bnode above is a method that returns a GraphNode (as defined in [1])  using the graph
itself. Ie the above is equivalent
> to 
> 
>     val g = new EzMGraph {
>          node(reto) -- FOAF.knows --> ( this.bnode -- FOAF.name --> "henry" )
>                            -- FOAF.knows -->  danny
>      }
> 
> The good thing is that the result of ( this.bnode -- FOAF.name --> "henry" ) is a
GraphNode with the same
> backing graph as EzMGraph, so there is no copying of information from one graph to another
to do (which due
> to blank nodes in the semantic web, might end up being more complex than one may think)
> 
> Now if one wanted to fill the graph with information from another context, one would
want a notation
> more like
> 
>     val retoNd = g.node(reto)
> 
>     for (p <- people) {  retoNode -- FOAF.knows --> ( p -- FOAF.knows --> me
) }
> 
> ie for a list of people assert that Reto knows them and that they also know me .
> 
> But here if p were say a URI for a person, then one would be creating in the code
> 
>    ( p -- FOAF.knows --> me )
> 
> an new GraphNode each time backed by a different empty graph, because of the implicit
> 
>     implicit def  resource2graphNode(res: Resource) = new RichGraphNode(res, new SimpleMGraph())
> 
> This will feel wasteful, when compared to the import solution that Reto had proposed
where all
> resources end up being transformed to GraphNodes with the same backing graph.
> 
>    With the code as it stands now in [1] one can still do that. Then one would have
> 
>    import g.node
>    for (p <- people) {  retoNode -- FOAF.knows --> ( p -- FOAF.knows --> me
) }
> 
>    So now each p will be transformed into a GraphNode using the same store as g.
> 
> Of course, this is nothing more than one would have had one written
> 
>       for (p <- people) {  retoNode -- FOAF.knows --> ( g.node(p) -- FOAF.knows
--> me ) }
> 
> It is more repetitive, and will be even more so the longer the code. But I still prefer
it to the
> import above (for the moment). One feeds that something needs to be delimited more clearly.
> 
> So perhaps the subclassing solution is the good one again for this
> 
>     new EzMGraph(g) {
>           for (p <- people) {  retoNode -- FOAF.knows --> ( p -- FOAF.knows -->
me ) }
>     }
> 
>     is not that much more verbose that then import version, but it does make it clear
where the graph 
> is delimited. With an type alias one could even make that look like this:
> 
>    new graph(g) {
>           for (p <- people) {  retoNode -- FOAF.knows --> ( p -- FOAF.knows -->
me ) }
>    }
> 
>     Is that perhaps good enough?
> 
>    Henry
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> [1] https://github.com/bblfish/clerezza/blob/51be3b14a5488838d87094e81455ca806507b72b/parent/rdf.scala.utils/src/main/scala/org/apache/clerezza/rdf/scala/utils/EzMGraph.scala
> 
> Social Web Architect
> http://bblfish.net/
> 

Social Web Architect
http://bblfish.net/


Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message