|
A little background would probably help.
We have a tree where every node has a name and potentially a value. We are trying to mask an explicit retrieval behavior. For example, a.b.c = d, would set the node /a/b/c to d, and f = a.b.c would retrieve the value of a.b.c and store it into f. We ran across Wrappers, which gave us the get() behavior we were looking for. By also implementing GroovyInterceptable, we were able to forward all methods to the value contained in the node. The only piece of the puzzle we haven't been able to solve is when == is used. In all other cases, unwrap is called as needed or we intercept the method call. == however assumes that there is no special rules for object equality. We are open to alternative suggestions. So I am right in thinking that you are using the wrappers outside by yourself? then you are most probably using the wrappers outside their scope. They are just for method invocations, not for properties. Instead of using th wrappers from org.codehaus.groovy.wrapper, you should use your own wrappers... if needed. I mean for storing d in a.b.c you don't need a wrapper. If you tell me in which cases it should give an exception, or if all possible paths are fine, then I can give you a different solution.
All paths "are" valid. The value returned may be null, so there is never an exception. The behavior of Wrappers we liked was the fact that when passed into a method, it was "unwrapped". We haven't found alternative that provides this get() behavior. On set you call setProperty which allows us to do the right thing. For get, there isn't really anything that tips us off to return the value stored at the path. This is the same problem with ==. When you do something like a.b.c == null, we want it to be equivalent to a.b.c.get() == null. But since == just looks at the left hand object, in our case it gets this PathObject rather than PathObject.get()
ok, so I assume you want the following:
def a = new DynamicTreeNode(value:"I am root") assert a.b == null assert a.b.c == null a.b.c = new DynamicTreeNode(value: "/b/c") assert a.b.c.value == "/b/c" something like that... the puzzling thing here for me is, that a.b == null, means for me that a.b.c should throw an NPE. On the other hand, what would be about: def a = new DynamicTreeNode(value:"I am root") assert a.b != null assert a.b.value == null assert a.b.c != null assert a.b.c.value == null a.b.c.value = "/b/c" assert a.b.c.value == "/b/c" assert a.b.value == null In this case a.b is not null, thus a.b.c will not throw an NPE. Of course this is a hand made wrapper, but this wrappers comes natural with the DynamicTreeNode class: class DynamicTreeNode {
private namedNodes = [:]
def value
void set(String name, value) {
namedNodes.put(name,value)
}
def get(String name) {
if (namedNodes.containsKey(name)) return namedNodes.get(name)
def node = new DynamicTreeNode()
set(name,node)
return node
}
String toString(){
"<$value ($namedNodes)>"
}
}
This is not good enough for you? Btw, get/set like here are called for missing properties. get/setProperty would be called before the properties are handled. This is conceptually exactly what we are doing except in a different way.
We are trying to avoid the a.b.c.value which would be a.b.c.get() in our model. We are trying to make it transparent. I realize it may not be possible. If you think of these paths as URIs, a.b doesn't have to exist for a.b.c to return a value. If I see it as URI, then I would expect, that if the URI a.b.c exists, the URI a.b does exist too. What I don't expect is that the content for the URI in a.b exists. You mix the path and the content of the path.. I mean we could for example also have something like
tree[a.b.c] that would be very easy to do.... but possibly a bit strange. So I guess there is no real way out of this.. I mean breaking the symmetry of == to make your code working is only a symptom of bigger problems that will follow in other parts... At last I would expect that. I suggest asking on the mailing list, maybe someone there has a better idea, but for now I suggest to close this issue as "Won't fix" if you agree |
||||||||||||||||||||||||||||||||||||||||||||
I guess you mean the wrapper defined in Groovy by the wrapper package... could you please post an running example showing this. You should not come into contact with a wrapper unless you write a MetaClass, and in that case it is your task to unwrap. These wrappers are no classic wrappers in the sense that other languages are using, they are not there to represent values of the runtime and to allow faster invocation paths or something like that. they are there to keep a static type during a method call, nothing more... They might become obsolete in 2.0
to 2)
if null==x is ok, then why is x==null not? shouldn't equals be symetric? And why would it fix #1?
I really need a test case to see what you are talking about