I recently put together a system that I layered on top of RDNZL, in order to experiment with some alternative ways of interacting with CLR/.NET code. I'm hoping that some of the ideas could be incorporated into RDNZL. Edi's too busy to look it over right now, and he suggested that I offer for perusal here on the mailing list.
Aside from making type lookup a little easier, this system tries to make your .NET-using Lisp code a bit more Lisp-like. Performance is shabby because of the layering over RDNZL; much, if not all of this, could eventually be fixed. Nonetheless, I've been using this system successfully for the past few weeks as a vehicle for exploring Direct3D programming on a WinXP system, using the LispWorks trial edition of Lisp. In order to get reasonable performance, I had to use CL-CLR:DEFINE-CLR-CALL (a thin veneer over DEFINE-RDNZL-CALL) for most calls in the rendering loop.
This system *should* work with any Lisp that is supported by RDNZL.
The package includes several of Microsoft's Direct3D Tutorial programs, translated to Lisp. If you have ASDF, RDNZL, and Direct3D installed, you ought to be able to run the examples with a minimum of fuss.
You can download it from here: http:\..................\cl-clr.zip
Comments are welcome. You are also encouraged to laugh at the excessively long TODO.txt file.
Hmm, that didn't work quite right. Looks like Sneakemail censored my Web server's DNS name. Here's the download location again in slightly mangled form:
http://spookydistance-dot-com/cl-clr.zip
Dan Muller s8ctxw402-at-sneakemail.com |RDNZL-devel/via Sneakemail| wrote:
I recently put together a system that I layered on top of RDNZL, in order to experiment with some alternative ways of interacting with CLR/.NET code. I'm hoping that some of the ideas could be incorporated into RDNZL. Edi's too busy to look it over right now, and he suggested that I offer for perusal here on the mailing list.
Aside from making type lookup a little easier, this system tries to make your .NET-using Lisp code a bit more Lisp-like. Performance is shabby because of the layering over RDNZL; much, if not all of this, could eventually be fixed. Nonetheless, I've been using this system successfully for the past few weeks as a vehicle for exploring Direct3D programming on a WinXP system, using the LispWorks trial edition of Lisp. In order to get reasonable performance, I had to use CL-CLR:DEFINE-CLR-CALL (a thin veneer over DEFINE-RDNZL-CALL) for most calls in the rendering loop.
This system *should* work with any Lisp that is supported by RDNZL.
The package includes several of Microsoft's Direct3D Tutorial programs, translated to Lisp. If you have ASDF, RDNZL, and Direct3D installed, you ought to be able to run the examples with a minimum of fuss.
You can download it from here: http:\..................\cl-clr.zip
Comments are welcome. You are also encouraged to laugh at the excessively long TODO.txt file.
-- Dan Muller
This message was sent using IMP, the Internet Messaging Program.
rdnzl-devel mailing list rdnzl-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/rdnzl-devel
Hi, it's just me talking to myself again.
I've discovered some shortcomings of System.Type.InvokeMember, which CL-CLR depends on, when it comes to passing null arguments. Also, there's a bug in CL-CLR with respect to ByRef types (which doesn't surprise me, since I hadn't looked at them in detail yet).
It will probably take me a few days to figure out how to work around them, while preserving some of the unique features of CL-CLR that I'm most interested in. If you do take a look at CL-CLR (and I still hope to get feedback on some of the ideas talked about in the README.txt file), be aware of these two problems:
- If you pass a null value as an argument, there is no type information for InvokeMember to use in resolving among overloaded members. If an ambiguity results, the call will fail.
- ByRef parameters (ref or out in C#) are not copied back out.
RDNZL containers carry quasi-static type information with them, and so a container representing a null object reference does, too. In CL-CLR, I'm experimenting with using the types derived from the object values, and it effectively ignores the types embedded in the containers. This has the interesting effect of making overloaded methods act much like Lisp methods (even more so than RDNZL already does), potentially run-time polymorphic on all parameters. And like Lisp methods, if you pass null (in analogy to NIL) for an argument, the only type it will really match is Object. But, interestingly, the default binding behavior in InvokeMember seems to allow a null argument to match anything at all, as long as there's no ambiguity -- in other words, as long as that particular parameter isn't overloaded.
RDNZL has some interesting problems of its own in handing ByRef parameters, mainly because REF modifies containers in-place. Assuming that some-type is a type object for SomeType, and MyStaticMethod returns a new value through its parameter:
(let* ((a (rdnzl:new some-type)) (b a)) (rdnzl:invoke "MyHandyClass" "MyStaticMethod" (ref a)) (print a) (print b))
After the call to INVOKE, both a *and* b will reference the new object. Other even stranger things can happen:
(let ((a (rdnzl:new some-type))) (invoke a "AnInstanceMethod" (ref a)))
This fails entirely, because a becomes temporarily of type SomeType&, and the lookup of AnInstanceMethod fails on that type.
A possible strategy for fixing this in RDNZL: Make REF a macro taking a SETF-able form. It expands to a form that creates an instance of a RDNZL REFERENCE class, containing a reference to the result of evaluating the form, and a closure that will SETF the original form when called with a new value. INVOKE et al must detect these parameters, arrange to *clone* the input continer (with a new GCHandle value!), and use the cloned container to receive the result. Finally, after the member call, pass the new value to the closure.
CL-CLR is still available here for now: http://64.91.250.185/cl-clr.zip
Hi Dan
I'm listening :)
Sadly I've not had anytime to devote to RDNZL stuff recently - but I'll certainly take a look and give you some feedback as soon as I get the opportunity.
I have an experimental local version of RDNZL with some performance oriented mods to reduce consing on the lisp and .NET sides - optimising the boxing/unboxing, specialisations for different numbers of arguments in event callbacks etc. I've been trying to get the performance up to a level where it is viable to use for high volumes of calls and events (the DataGridView in virtual mode is one example). This is still all rather hacked together and needs tidying up.
- Dominic
On Tue, 28 Mar 2006 21:31:41 -0500, "Dan Muller" s8ctxw402@sneakemail.com said:
Hi, it's just me talking to myself again.
I've discovered some shortcomings of System.Type.InvokeMember, which CL-CLR depends on, when it comes to passing null arguments. Also, there's a bug in CL-CLR with respect to ByRef types (which doesn't surprise me, since I hadn't looked at them in detail yet).
It will probably take me a few days to figure out how to work around them, while preserving some of the unique features of CL-CLR that I'm most interested in. If you do take a look at CL-CLR (and I still hope to get feedback on some of the ideas talked about in the README.txt file), be aware of these two problems:
If you pass a null value as an argument, there is no type information for InvokeMember to use in resolving among overloaded members. If an ambiguity results, the call will fail.
ByRef parameters (ref or out in C#) are not copied back out.
RDNZL containers carry quasi-static type information with them, and so a container representing a null object reference does, too. In CL-CLR, I'm experimenting with using the types derived from the object values, and it effectively ignores the types embedded in the containers. This has the interesting effect of making overloaded methods act much like Lisp methods (even more so than RDNZL already does), potentially run- time polymorphic on all parameters. And like Lisp methods, if you pass null (in analogy to NIL) for an argument, the only type it will really match is Object. But, interestingly, the default binding behavior in InvokeMember seems to allow a null argument to match anything at all, as long as there's no ambiguity -- in other words, as long as that particular parameter isn't overloaded.
RDNZL has some interesting problems of its own in handing ByRef parameters, mainly because REF modifies containers in-place. Assuming that some-type is a type object for SomeType, and MyStaticMethod returns a new value through its parameter:
(let* ((a (rdnzl:new some-type)) (b a)) (rdnzl:invoke "MyHandyClass" "MyStaticMethod" (ref a)) (print a) (print b))
After the call to INVOKE, both a *and* b will reference the new object. Other even stranger things can happen:
(let ((a (rdnzl:new some-type))) (invoke a "AnInstanceMethod" (ref a)))
This fails entirely, because a becomes temporarily of type SomeType&, and the lookup of AnInstanceMethod fails on that type.
A possible strategy for fixing this in RDNZL: Make REF a macro taking a SETF-able form. It expands to a form that creates an instance of a RDNZL REFERENCE class, containing a reference to the result of evaluating the form, and a closure that will SETF the original form when called with a new value. INVOKE et al must detect these parameters, arrange to *clone* the input continer (with a new GCHandle value!), and use the cloned container to receive the result. Finally, after the member call, pass the new value to the closure.
CL-CLR is still available here for now: http://64.91.250.185/cl-clr.zip
-- Dan Muller
This message was sent using IMP, the Internet Messaging Program.
rdnzl-devel mailing list rdnzl-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/rdnzl-devel