text: 1. If you have a Wrapper instance, the instance rather than the wrappered value is compared. I would have thought that wrapper == whatever is equivalent to wrapper.unwrap() == whatever.
  2. Along the same lines, the short circuit check for null value on the left and right side doesn't seem right. It makes sense for the left side, however if the left side is an object, and the right side is null, the object should make the determination. This would fix #1 as well.
  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
  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.
  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.
  If you think of these paths as URIs, a.b doesn't have to exist for a.b.c to return a value.
  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