www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - === No Damn Good

reply teqDruid <me teqdruid.com> writes:
I'm relatively sure that this code should run...
interface I {
        I parent();
        void parent(I i);
        void addChild(I i);
}
interface J : I {}
class A : I {
        private I myParent;
        void addChild(I i) {
                i.parent = this;
        }
        I parent() { return myParent; }
        void parent(I parent) { myParent = parent;}
}
class B : A, J {}
                                                                                
void main() {
        J a = new B;
        J b = new B;
        a.addChild(b);
	assert(cast(J)b.parent === a); // This works
        assert(b.parent === a);	// So this one should too.. it doesn't
}

This one took me a LONG time to boil down to this, and affects me in a
pretty HUGE way... Walter, I'd appreciate it if this one is resolved soon.

I'm running DMD 0.110 on Linux.

John
Jan 12 2005
next sibling parent reply Thomas Kuehne <thomas-dloop kuehne.thisisspam.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Added to DStress as
http://dstress.kuehne.cn/run/opIdentity_01.d
http://dstress.kuehne.cn/run/opIdentity_02.d

Thomas

teqDruid schrieb am Wed, 12 Jan 2005 08:20:54 -0500:
 I'm relatively sure that this code should run...
 interface I {
         I parent();
         void parent(I i);
         void addChild(I i);
 }
 interface J : I {}
 class A : I {
         private I myParent;
         void addChild(I i) {
                 i.parent = this;
         }
         I parent() { return myParent; }
         void parent(I parent) { myParent = parent;}
 }
 class B : A, J {}
                                                                               
 
 void main() {
         J a = new B;
         J b = new B;
         a.addChild(b);
 	assert(cast(J)b.parent === a); // This works
         assert(b.parent === a);	// So this one should too.. it doesn't
 }

 This one took me a LONG time to boil down to this, and affects me in a
 pretty HUGE way... Walter, I'd appreciate it if this one is resolved soon.

 I'm running DMD 0.110 on Linux.

 John

-----BEGIN PGP SIGNATURE----- iD8DBQFB5TBq3w+/yD4P9tIRAoHNAJ9aBDuCqnVpj4GQHnRTT694EzvQRgCePYhg SuJbe6p9ydxEDElgJuXb134= =mh8D -----END PGP SIGNATURE-----
Jan 12 2005
parent teqDruid <me teqdruid.com> writes:
Thanks. That was fast!  I just hope this doesn't become one of those tests
on there that hasn't been touched in awhile.  It basically prohibits my
DOM implementation from working correctly.

BTW, you've got a typo on the module identifier in the second one.

John

On Wed, 12 Jan 2005 15:12:59 +0100, Thomas Kuehne wrote:

 
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 Added to DStress as
 http://dstress.kuehne.cn/run/opIdentity_01.d
 http://dstress.kuehne.cn/run/opIdentity_02.d
 
 Thomas
 
 teqDruid schrieb am Wed, 12 Jan 2005 08:20:54 -0500:
 I'm relatively sure that this code should run...
 interface I {
         I parent();
         void parent(I i);
         void addChild(I i);
 }
 interface J : I {}
 class A : I {
         private I myParent;
         void addChild(I i) {
                 i.parent = this;
         }
         I parent() { return myParent; }
         void parent(I parent) { myParent = parent;}
 }
 class B : A, J {}
                                                                               
 
 void main() {
         J a = new B;
         J b = new B;
         a.addChild(b);
 	assert(cast(J)b.parent === a); // This works
         assert(b.parent === a);	// So this one should too.. it doesn't
 }

 This one took me a LONG time to boil down to this, and affects me in a
 pretty HUGE way... Walter, I'd appreciate it if this one is resolved soon.

 I'm running DMD 0.110 on Linux.

 John

-----BEGIN PGP SIGNATURE----- iD8DBQFB5TBq3w+/yD4P9tIRAoHNAJ9aBDuCqnVpj4GQHnRTT694EzvQRgCePYhg SuJbe6p9ydxEDElgJuXb134= =mh8D -----END PGP SIGNATURE-----

Jan 12 2005
prev sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
 assert(cast(J)b.parent === a); // This works
         assert(b.parent === a); // So this one should too.. it doesn't

As another work-around it looks like it works if you do I x = b.parent; assert(x === a); Why does it prohibit your DOM code form working? Can't you use one of the workarounds?
Jan 12 2005
next sibling parent "Ben Hinkle" <bhinkle mathworks.com> writes:
"Ben Hinkle" <bhinkle mathworks.com> wrote in message
news:cs3g39$2219$1 digitaldaemon.com...
 assert(cast(J)b.parent === a); // This works
         assert(b.parent === a); // So this one should too.. it doesn't

As another work-around it looks like it works if you do I x = b.parent; assert(x === a);

whoops - I read the wrong line number. My code above isn't a workaround.
Jan 12 2005
prev sibling parent reply teqDruid <me teqdruid.com> writes:
So here's the code that doesn't work properly:
	private Node[] list;
	ulong getPos(Node node) {
		foreach (int i, Node n; list)
			if (n === node)
				return i;
		return -1;
	}
In this case, Node is an interface analagous to I.  The problem is that
the pointer in the list isn't kosher for === comparisons to other Nodes,
so the function that adds it to the list has to be modified.  This
function, however, also uses the Node interface. The only way (I see) to
get around this bug is by forcing the programmer to interface with the
library in a bizarre manner... which I've been unsucessfully trying to do.
 I don't fully understand the bug, or why it is occurring...

John

On Wed, 12 Jan 2005 10:35:04 -0500, Ben Hinkle wrote:

 assert(cast(J)b.parent === a); // This works
         assert(b.parent === a); // So this one should too.. it doesn't

As another work-around it looks like it works if you do I x = b.parent; assert(x === a); Why does it prohibit your DOM code form working? Can't you use one of the workarounds?

Jan 12 2005
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"teqDruid" <me teqdruid.com> wrote in message
news:pan.2005.01.12.15.44.42.756023 teqdruid.com...
 So here's the code that doesn't work properly:
 private Node[] list;
 ulong getPos(Node node) {
 foreach (int i, Node n; list)
 if (n === node)
 return i;
 return -1;
 }

how about if (cast(Object)n === cast(Object)node)
Jan 12 2005
next sibling parent reply teqDruid <me teqdruid.com> writes:
D'uh... the worked.  There are still some other places in the library
where I can't do a cast, and the programmer interfacing with the library
will have to do it, but this does reduce the problem severity a bit.

Thanks,
John

On Wed, 12 Jan 2005 15:41:34 -0500, Ben Hinkle wrote:

 
 "teqDruid" <me teqdruid.com> wrote in message
 news:pan.2005.01.12.15.44.42.756023 teqdruid.com...
 So here's the code that doesn't work properly:
 private Node[] list;
 ulong getPos(Node node) {
 foreach (int i, Node n; list)
 if (n === node)
 return i;
 return -1;
 }

how about if (cast(Object)n === cast(Object)node)

Jan 12 2005
parent kris <fu bar.org> writes:
teqDruid wrote:
 D'uh... the worked.  There are still some other places in the library
 where I can't do a cast, and the programmer interfacing with the library
 will have to do it, but this does reduce the problem severity a bit.
 
 Thanks,
 John
 
 On Wed, 12 Jan 2005 15:41:34 -0500, Ben Hinkle wrote:
 
 
"teqDruid" <me teqdruid.com> wrote in message
news:pan.2005.01.12.15.44.42.756023 teqdruid.com...

So here's the code that doesn't work properly:
private Node[] list;
ulong getPos(Node node) {
foreach (int i, Node n; list)
if (n === node)
return i;
return -1;
}

how about if (cast(Object)n === cast(Object)node)


The problem with such casts is that they're of the dynamic variety. Based on prior experience, the dynamic cast will take ~5 times longer to execute than the rest of each loop pass (in this case), and there's two such casts required ... It's actually faster to dispatch to a class specific opEquals(), and do a single dynamic cast there instead. Of course, none of this is what one might call 'intuitive'
Jan 12 2005
prev sibling parent reply Burton Radons <burton-radons smocky.com> writes:
Ben Hinkle wrote:
 "teqDruid" <me teqdruid.com> wrote in message
 news:pan.2005.01.12.15.44.42.756023 teqdruid.com...
 
So here's the code that doesn't work properly:
private Node[] list;
ulong getPos(Node node) {
foreach (int i, Node n; list)
if (n === node)
return i;
return -1;
}

how about if (cast(Object)n === cast(Object)node)

An object supplied by a foreign-language DOM won't have an Object casting, so those casts will return null. A CORBA ORB which only works through networking should be safe, but one which interfaces with foreign-language ORBs through native bindings won't be. It's not the right hack-around. I'll illustrate what's happening. Take this tree: interface IA { void call (IA); } interface IB : IA { } class CA : IA { void call (IA) { ... } } class CB : CA, IB { } The layout of the classes looks somewhat like this: struct Object_layout { VTable *vtable; void *handle; } struct CA_layout { Object_layout Object_data; VTable *IA_vtable; } struct CB_layout { CA_layout CA_data; VTable *IA_vtable; VTable *IB_vtable; } So there are multiple pointers to the IA vtable within an instance of CB. Casting to a solid type, like Object, works because there's only one of those, but if you keep them as interfaces the runtime can get to either vtable depending upon which course it uses. What I did is add a hack method called "self" to Node which just returns "this". "Node.isSameNode" has this implementation: boolean isSameNode (Node other) { return this === other || (other !== null && this === other.self ()); } isSameNode should always be used by the user anyway because there might be multiple proxies to the same object. CORBA has a method in its Object class which tests for equivalent references, but unfortunately DOM is not as tightly bound to CORBA as would be preferable (hence the lack of use of the string type which allows the implementation to use any local encoding, and the stupid forcing of UTF-16). Regarding time cost, "===" is a costly operation anyway.
Jan 31 2005
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
 how about
  if (cast(Object)n === cast(Object)node)

An object supplied by a foreign-language DOM won't have an Object casting, so those casts will return null. A CORBA ORB which only works through networking should be safe, but one which interfaces with foreign-language ORBs through native bindings won't be. It's not the right hack-around.

What do DOMs and ORBs have to do with how D handles interfaces? I don't see the relevance. I thought one can cast any instance of a class to Object so I'm confused about when cast(Object)node can fail.
 I'll illustrate what's happening.  Take this tree:

     interface IA { void call (IA); }
     interface IB : IA { }
     class CA : IA { void call (IA) { ... } }
     class CB : CA, IB { }

 The layout of the classes looks somewhat like this:

     struct Object_layout
     {
         VTable *vtable;
         void *handle;
     }

     struct CA_layout
     {
         Object_layout Object_data;
         VTable *IA_vtable;
     }

     struct CB_layout
     {
         CA_layout CA_data;
         VTable *IA_vtable;
         VTable *IB_vtable;
     }

 So there are multiple pointers to the IA vtable within an instance of CB. 
 Casting to a solid type, like Object, works because there's only one of 
 those, but if you keep them as interfaces the runtime can get to either 
 vtable depending upon which course it uses.

I agree. That is why casting to Object provides a "unique id" so that === will work. It normalizes the different interface references to the object.
 What I did is add a hack method called "self" to Node which just returns 
 "this".  "Node.isSameNode" has this implementation:

     boolean isSameNode (Node other)
     {
         return this === other || (other !== null && this === other.self 
 ());
     }

 isSameNode should always be used by the user anyway because there might be 
 multiple proxies to the same object.  CORBA has a method in its Object 
 class which tests for equivalent references, but unfortunately DOM is not 
 as tightly bound to CORBA as would be preferable (hence the lack of use of 
 the string type which allows the implementation to use any local encoding, 
 and the stupid forcing of UTF-16).

sounds like isSameNode is what opEquals should do (except for the argument type being Object vs Node).
 Regarding time cost, "===" is a costly operation anyway.

=== is costly? It should be a pointer comparison.
Jan 31 2005
parent Burton Radons <burton-radons smocky.com> writes:
Ben Hinkle wrote:

how about
 if (cast(Object)n === cast(Object)node)

An object supplied by a foreign-language DOM won't have an Object casting, so those casts will return null. A CORBA ORB which only works through networking should be safe, but one which interfaces with foreign-language ORBs through native bindings won't be. It's not the right hack-around.

What do DOMs and ORBs have to do with how D handles interfaces? I don't see the relevance. I thought one can cast any instance of a class to Object so I'm confused about when cast(Object)node can fail.

Whoops, I assumed that you could cast a foreign language object reference (an object allocated by a foreign language), and I realise that's not very likely. More likely is that if you attempt to cast a foreign language object, either implicitly, explicitly, or by using === when the objects don't have the same first pointer in the vtable, it will always SIGSEGV, because casting requires use of ClassInfo which won't be the same. What a pain. But even if we could cast foreign language object references, you still won't be able to cast to Object, because foreign language objects won't have Object in their base. Object will be the root class of an object created by D only.
So there are multiple pointers to the IA vtable within an instance of CB. 
Casting to a solid type, like Object, works because there's only one of 
those, but if you keep them as interfaces the runtime can get to either 
vtable depending upon which course it uses.


Exploring the problem with RTTI, I think there's just a bug in ===; I don't see any trace of shadow interfaces. I was wrong about the source of the problem. It might be because using .classinfo when an object is posing as an interface produces the interface's ClassInfo rather than the real one. Here's an example: interface A { } class B : A { } void main () { B b = new B (); A a = b; printf ("%.*s %.*s\n", b.classinfo.name, a.classinfo.name); } This prints "B A", when it should be "B B". I think this is a bug, because if "A" is a class instead of an interface, it produces "B B" as it should.
Jan 31 2005