Hi,
I have two instances of a DataGridView each bound to the same callbacks within Lisp. The callbacks each have two parameters, the first of which is a C# object. This object corresponds to the DataGridView that initiated the event.
When I create the two DataGridViews I put them both into a list and when a callback is called I look through my list to match up the first parameter with one of the references in my list. However this is failing.
How do I compare references to C# objects using RDNZL?
I've noticed that there is an enum-to-int function which allows enums to be compared in Lisp. I may need something like this to compare the identity of objects in Lisp.
Another approach would be to write a function in C# to compare object identity but I don't want to include a dll in my little example.
Any help would be appreciated.
Regards,
Matthew
On Fri, 14 Mar 2008 23:02:22 +1100, "Matthew O Connor" matthew.oconnor@calyptech.com wrote:
How do I compare references to C# objects using RDNZL?
If you don't mind using unexported functionality, with two RDNZL containers C1 and C2 you'd do something like (untested)
(fli:pointer-eq (rdnzl::pointer c1) (rdnzl::pointer c2))
on LispWorks. I'm not sure if this The Right Thing[TM] to do, but if it is (comments welcome), we should probably export a portable version of this.
Edi,
I tried out the code you gave me but it doesn't do the trick. I've created some test code to illustrate my problem a bit better. It is listed below.
There are two parts to it. You have to build a simple dll which contains a class that simply stores a reference passed to it as an "object". The lisp code simply instantiates a ReferenceComparisonTest object, passes it a reference to itself and then later compares what it passed in with what it got back to see if they are the same thing.
They should be the same but clearly aren't. I think this is the crux of my problem.
Here is the code:
// C#
using System;
namespace ReferenceComparisonTest
{
public class ReferenceComparisonTest
{
private object _reference = null;
public ReferenceComparisonTest()
{
_reference = this;
}
public object reference
{
get { return _reference; }
set { _reference = value; }
}
}
}
;; LISP
(load "../RDNZL/rdnzl-0.12.0/load.lisp")
(rdnzl:enable-rdnzl-syntax)
(rdnzl:import-types "ReferenceComparisonTest" "ReferenceComparisonTest")
(rdnzl:use-namespace "ReferenceComparisonTest")
(defun pointers-equal (a b)
(fli::pointer-eq (rdnzl::pointer a) (rdnzl::pointer b)))
(defun main ()
(let ((x (rdnzl::new "ReferenceComparisonTest")))
;; Make x store a reference to itself.
(setf [%reference x] x)
;; Compare x with what was stored in x. These should be the same.
(if (pointers-equal x [%reference x])
(format t "Excellent! The references are the same as expected.")
(format t "Error! The references were different but should have been the same."))))
(main)
Regards,
Matthew
On Sat, 15 Mar 2008 11:32:55 +1100, "Matthew O Connor" matthew.oconnor@calyptech.com wrote:
I tried out the code you gave me but it doesn't do the trick. I've created some test code to illustrate my problem a bit better. It is listed below.
There are two parts to it. You have to build a simple dll which contains a class that simply stores a reference passed to it as an "object". The lisp code simply instantiates a ReferenceComparisonTest object, passes it a reference to itself and then later compares what it passed in with what it got back to see if they are the same thing.
They should be the same but clearly aren't. I think this is the crux of my problem.
Yes, I see now. I misunderstood your original question. What you want is a bit more complicated but certainly doable (I think) and would probably also be worthwhile to have as a part of RDNZL. You need to add new C++ code for this, though.
Look at the DotNetContainer.h and DotNetReference.h files. A container has a public function getContainerObject which returns the object it wraps. You want to add a C++ function which accepts two DotNetContainer objects and compares the objects they wrap. This function can then be called from Lisp code via the FFI.
I can add that, but it'll take be some time as I'm busy with other things right now, so feel free to play with this yourself.
Edi,
I will have a look at the files you mention and see if I can come up with new function that will do the comparison.
I don't have C++ on my laptop yet. Once I have this I'll give it a go.
Cheers,
Matthew
Sorry for coming back to this a bit late. I'll probably add the code you submitted to RDNZL anyway as it might turn out to be useful in specific cases, but note that there's a "portable" way to solve your problem. Simply replace this line
(if (pointers-equal x [%reference x])
with
(if [Equals x [%reference x]]
That should do the trick.
Cheers, Edi.
On Tue, 25 Mar 2008 17:38:40 +0100, Edi Weitz edi@agharta.de wrote:
I'll probably add the code you submitted to RDNZL anyway as it might turn out to be useful in specific cases
But wait. Looking at this more closely, I see that you're instantiating the objects (which you could do directly from DotNetContainer without going through DotNetReference, BTW) and then comparing them with ==. Is that the right way to do it?
That's not a rhetorical question. I don't know the right answer, so I'd like to discuss it here. Does == have different semantics from Equals?
Would it make sense to directly compare the pointers? (As we already have Equals "for free", I'm thinking of something like Common Lisp's EQ - a function which is usually not what you want but which might be useful if you know what you're doing.)
Comments welcome.
I am just beginning to discover the numerous different types of equals within Common Lisp so I can't comment on them. I can probably comment on the C# ones however.
I think that by default '==' will default to the 'Equals' function. In C# however you can overload the '==' operator and make it work differently. An example of this might be an primary key comparison on objects stored in a database table. So you make '==' look at the key slot and return true or false based on this equality.
So I think the short answer is for the default behaviour they are exactly the same but you can overload the operator at which point they will be different.
Cheers,
Matthew
Edi,
I've got a solution for this. I can't claim to completely understand what is happening with all of RDNZL but I was able to copy some other functionality and get what I thought was the correct implementation.
What is the best way to have this reviewed, edited and possibly included in the distribution?
Is there a regression suite for RDNZL? I haven't run any exhaustive tests.
Regards,
Matthew
On Tue, 18 Mar 2008 23:13:01 +0000, Matthew O'Connor matthew.oconnor@calyptech.com wrote:
I've got a solution for this. I can't claim to completely understand what is happening with all of RDNZL but I was able to copy some other functionality and get what I thought was the correct implementation.
What is the best way to have this reviewed, edited and possibly included in the distribution?
Just send it to the list and we'll look at it... :)
Is there a regression suite for RDNZL? I haven't run any exhaustive tests.
No, no regression suite. Just the examples so far.
Thanks, Edi.
Edi,
I've attached the files I touched along with a little test application.
I basically added a function to the ffi.lisp file call same-objects that takes two C# references from lisp and returns true if they are the same underlying C# object.
I added the respective code to DotNetReference and DotNetContainer as suggested.
I don't know if what I did fits with the overall architecture. Please modify it to match any guidelines that you have.
Let me know if there are any problems.
Regards,
Matthew