In a reply to Reto's post, which did not make it to the Clerezza list,
but which is available here
https://groups.google.com/d/msg/scala-user/IsJ1yXjd2lw/cdAsYsPc4-EJ

Rex Kerr wrote

> Is Clerezza intended to be used primarily on its console?  If yes, then 
> interactive usability is more important than maintainability of large blocks 
> of code, since you don't typically have large blocks of code, but you have 
> lots of interaction.  Otherwise, you can take advantage of the fact that you 
> have some control over the console, unlike raw Scala source code.  You can 
> have a modal console that wraps everything in a new context(x) { } line by 
> line, or a context character like : that indicates that the following stuff 
> is in the context of the current graph (which can be a signal for the 
> wrapping).
> 
>   --Rex

I agree with Rex there, there are other ways around the problem of the
console.

Henry


On 22 Jul 2011, at 16:45, Reto Bachmann-Gmür wrote:

> I think the issue boils down to a design recommendation for code using
> the clerezza rdf library.
> 
> Importing the members of an EzGraph as context makes perfectly sense
> on the clerezza console. The "coding" there is imperative, one want to
> see the results ideally after each line. Creating a block scoped to
> graph is clearly much less user-friendly [1]. Also having the content
> graph as default is very useful and shouldn't be sacrificed for
> enforcing good design in another context. Opening and being in the
> context you most often want to be is not only handy for rapid queries,
> the shell is a triple sink where new triples can be added to the
> clerezza instance simply by writing them down in a syntax similar to
> the turtle or the n-triples rdf format. Not having to call a method on
> some nodes on the graph makes a big difference in terms of usability.
> In program code that as opposed to the commands on the shell is
> deigned to last and which isn't executed while you type it is better
> design practice to instantiate an anonymous subclass of EzGraph (which
> could be renamed or aliased as context as in your examples) rather
> than importing the members (methods and implicts) of an instance.
> 
> Your anti-pattern example shows horrible code that you can write using
> the library, you could very well write a similar example using the
> java transaction api. The clerezza API however supports better coding
> practices and the documentation shall focus on these, changing the api
> to enforce these better practice would be at high costs for those
> using the api interactively on the shell or in scripts.
> 
> Reto
> 
> 
> 1. the clerezza faq entry on how to reset the password shows an
> example real-life usecase for switching graph-context on the console
> 
> On Fri, Jul 22, 2011 at 10:12 AM, Henry Story <[email protected]> wrote:
>> 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/
>> 

Social Web Architect
http://bblfish.net/

Reply via email to