Python Programming, news on the Voidspace Python Projects and all things techie.
Error'd: To help protect your computer...
I feel very protected...
Ironclad 0.3 Released (Use CPython Extensions from IronPython)
Ironclad is an open source project that aims to allow you to seamlessly use CPython C extensions from IronPython. It basically provides a reimplementation of the CPython API in C#, and maps the C extension (unmanaged code) to creating IronPython objects (managed objects) rather than CPython objects.
Ironclad targets IronPython 2 and Python 2.5.
The project is still in its infancy (only part of the C API is complete), but we have implemented sufficient for most of the CPython bz2 module to be used. Functions, types and their methods (including the file types ) can be used from this module. Class members and properties cannot yet be used and is the target of the next release (before we move onto getting Numpy working - the 'secret goal' of the project).
The major advancement in this release is that object lifetime is now handled basically correctly.
When you create a "managed object from an unmanaged type" (and we need a better way of saying that: when you use an object from a C extension basically), some 'unmanaged resources' (i.e. memory) are allocated.
Now, when the managed object is garbage collected this memory is correctly freed and the unmanaged destructor (tp_dealloc) for the type is called. This means that Ironclad doesn't leak [so much] memory and file descriptors owned by the unmanaged side are properly closed on garbage collection.
This is implemented with an interesting strategy. We basically maintain our own reference count for objects. When an object (a "managed object of unmanaged type") is created, we set its reference count to 1 (using a weak reference in the mapper so that the reference counting alone doesn't keep it alive on the managed side). Setting the reference count to 1 means that the destructor won't be called when the unmanaged side (the C extension) has finished with the object and is no longer holding any references to it.
The 'reference counting' for the unmanaged side, is simply a small block of memory storing an integer which corresponds to how many 'unmanaged references' there are to it. An unmanaged reference is not exactly the same as a managed reference (a possible cause of terminology confusion). This means that we are using real reference counting (in the same way as CPython) on the unmanaged side.
When there are no more references to it on the managed side (the IronPython world), the finalizer is called which checks the reference count in our mapping. If the reference count is more than 1 then we know that the extension itself still has a reference to the object and so the finalizer resurrects the object by storing a strong reference in the mapper.
We then regularly check (every time a managed object is finalized - but we may find a better strategy) if the reference count of any objects we have promoted to strong references have dropped back down to 1. If they have, we demote the strong reference back to a weak reference so that the object can be garbage collected.
In this way Ironclad mixes the reference counting that the C extensions use with the garbage collection of the .NET framework. The only downside is that if our "managed object of unmanaged type" itself has any references to managed objects, then their finalizers may have already been called at the point at which we resurrect it. Hopefully this is a pathological enough case that it won't bite us for a long time to come...
Currently Ironclad is only tested on Windows with .NET, but it deliberately uses the gcc compiler and a (theoretically) platform independent approach so that it can be ported to Mono with 'minimal' effort. Obviously the source distribution comes with full tests, and pretty good documentation.
|||Getting access to the 'real' file descriptor from a .NET stream is possible, but 'fun'.|
Programming with Silverlight: Bugs and Missing Features
I've spent the last week writing a chapter on programming Silverlight with IronPython (which is how I managed a whole week without blogging!).
Despite the title of this blog entry it's actually great fun. As Silverlight contains the 'core-clr' it has a wide range of powerful APIs built in. The example for the chapter is a Silverlight Twitter client. To parse the XML responses from the Twitter API I was able to reuse the XML DocumentReader I wrote for chapter chapter five of the book, where it was written for the example desktop application. I literally only had to change one line - to handle the XML declaration.
Whilst writing the chapter I have come across several bugs and quirks in Silverlight 2. Silverlight 2 is still in beta, so hopefully most of these problems will be addressed.
The SelectionLength on a TextBox is always 0 when you access it in subclasses of TextBox.
The HttpWebRequest asynchronous API is outstandingly odd. It can also throw errors that are impossible to catch (in between the async events) if the server is slow to respond.
When checking the boolean value on a CheckBox.IsChecked property, it can throw the following slightly amusing error:
ArgumentException: Cannot cast from 'System.Nullable`1[System.Boolean]' to 'System.Boolean'.
Comparing to True instead of doing a boolean test works, so it is a harmless bug.
Setting HyperlinkButton.TargetName = '_blank' causes the HyperlinkButton to stop working altogether on Safari on the Mac.
Because of a bug in Firefox, you can't use 'Chiron' (the development tool) with Firefox on the Mac. It works with Safari though.
Exception reporting can be very limited, especially for errors thrown inside dispatched functions. You can (apparently) remedy this on Windows with Visual Studio and the Silverlight SDK, but not for development on the Mac.
- No docking (and HorizontalAlignment.Stretch doesn't really work), meaning that I still have to use absolute sizes to layout user interfaces. I may be missing something with this though.
- No wrapping on the TextBox control.
- No password textbox (and because of the SelectionLength bug the one I implemented works, but can behave oddly).
- No selection (and therefore no copy and paste) from the TextBlock control.
- The ScrollViewer doesn't track the mouse scroll button, which is surprisingly annoying.
- No way of doing basic authentication (you can't set the Authorization header on HttpWebRequest objects). It might be possible to implement this yourself using the socket APIs of course...
- WebClient caches 'GET' requests, so if you use it to fetch data that might update then you're out of luck.
This work is licensed under a Creative Commons Attribution-Share Alike 2.0 License.