Armed with a text editor

mu's views on program and recipe! design

May 2006

C# Internationalization Limits Posted 2006.05.29 07:31 PDT

I need a trick. I want to build a plugin system in C# that supports internationalization. I want to be able to create various interfaces (called IPlugin here for simplicity) which classes in the plugins can implement so the framework knows how to load them. The framework must also able to get metadata from them in order to describe them to the user. What are my options?

Here's what I've come up with so far. I can create two interfaces, IPluginFactory and IPlugin when I only really want one. This is potentially useful anyway for a number of reasons so I might go with it. It would look something like this:

interface IPluginFactory
{
    string Name { get; }
    string Description { get; }
    IPlugin Load(string filename);
    IPlugin New(string filename);
    ...
}

interface IPlugin
{
    string PrettyName { get; }
    void Save();
    ...
}

Here IPluginFactory is implemented by a thin wrapper class which gives me data about the class implementing IPlugin which it knows how to manage. In the Name get method I can easly load and return Strings.MyString to retrieve a localized value. And all the meat can go into the IPlugin class. Thus it's cheap to instantiate all IPluginFactory classes, and put off instantiating a given IPlugin until I need it.

But isn't this sort of static metadata and creation needs exactly what attributes and static factory functions are for? Rather than having to implement two classes for every IPlugin, it would be nicer to just attribute one class.

[PluginInfo(Strings.PluginName, Strings.PluginDesc)]
class MyPlugin : IPlugin
{
    static MyPlugin Load(string filename) { ... }
    static MyPlugin New(string filename) { ... }
    
    string PrettyName { get { ... } }
    void Save() { ... }
}

But there are two problems with this approach:

  1. I can't create static methods in interfaces, and
  2. I can't use non-constant expressions in Attributes.

Between the two it means I can't easily enforce (compile-time) an implementation of the static methods, and I can't put localized strings into Attributes at all, as they all require runtime resource lookup. Because I can't put static properties in an interface, I also can't simply work around the second by putting the strings into static properties, although since unattributed classes aren't errors either, it's less of a compile time issue.

What ideas am I missing? I can use, but don't particularly like, the two interface approach. An inventive developer could probably implement both interfaces on one class, although it would only rarely be worth it, and would miss the point of having a thin wrapper class. I really like the look of the attributed single interface sample code. How close can I get?

(0 Comments ) (0 Trackbacks)

C# Internationalization Posted 2006.05.28 09:14 PDT

I've been playing with C# lately with an eye towards using it at work instead of the nasty legacy C++ codebase. And one of the pieces I'm still struggling with is internationalization. On unix we use the infamous gettext _() macro, which works in the source as a marker that its string needs to be translated, and at runtime as a function which looks up the translated string. In MFC we use numeric resources and utility functions like CString::LoadString(IDS_MYSTRING) or constructors like CString(MAKEINTRESOURCE(IDS_MYSTRING)). In C#, at least as presented in Visual Studio 2005, the idea is similar to the latter.

So I tried to use it. You create a resource file, add some strings to it, and then it's time to use them. You can try something like the following (which I'm not sure is correct):

ResourceManager rm = new ResourceManager();
string mystring = rm.GetString("MyString");

But there's one major quirk here. Unlike the unix or C++ methods, this is using a raw literal which is not a desired value. If you mess up the value passed to GetString(), you'll catch it at runtime. Clearly that's not the right way. You could make constants for these lookup strings, but that doubles the work. Turns out there's a better way.

Whatever you named your .resx resource file, there's an automatic type-safe class generated behind the scenes for you with static property accessors. So if I called it Strings.resx and had a string MyString, there's an accessor already set up so all I need is:

string mystring = Strings.MyString;

I'm new to C# in .NET 2.0, and the documentation isn't quite clear on this point, but I get the feeling this support is new to VS2005. It's definitely a nice experience for resource-style internationalization.

(0 Comments ) (0 Trackbacks) i18n

Puzzling Answers Posted 2006.05.18 07:02 PDT

So what does ''.join(chr(sum(((val >> i) & 1) << (7-i) for i in range(8))) for val in range(256)) do? If you run it on python2.4 you get an ugly string. Specifically it's a list of 256 bytes with their bits swapped in order of significance: 01 becomes 80 and so forth.

But why is this useful? Thanks to Joe's work it's now part of Mutagen, and is being used as part of a scheme to calculate the kind of CRC32 that the Ogg container (of Ogg Vorbis) requires. Why a scheme? Speed. As an interpreted language, python isn't well suited to small bit calculations on large sets of numbers. A standard reduce(lambda x, y: table[(x>>24) ^ y] ^ (x << 8), data, 0) scheme is too slow for comfort. However the table used in the existing C implementations zlib.crc32 and binascii.crc32 is from the bitwise reversed generator polynomial of the one used for Ogg.

Peter Johnson came to the rescue and figured out we could get the same effect by bitswapping each byte of the data and then bitswapping the final 32-bit result. Thanks to str.translate, we hoist most of the work into C, and the above puzzler code runs once at module import to generate the translation table.

And yes, Joe, it's good for confusing you at 1AM. :)

(0 Comments ) (0 Trackbacks) puzzle python

Puzzlers Posted 2006.05.17 06:51 PDT

What is the following useful for?

''.join(chr(sum(((val >> i) & 1) << (7-i) for i in range(8))) for val in range(256))
(1 Comments ) (0 Trackbacks) puzzle python

Summer of Code 2006 Posted 2006.05.14 09:38 PDT

I'm sure anyone reading this is aware of the Google sponsored Summer of Code, as an interesting opportunity for Free Software and Open Source Software projects to attract new contributions (and ideally contributors) through a summer stipend paid by Google. What's less well known is the process of choosing applicants.

I applied to mentor with the PSF, but now I'm torn. I think Google is doing a good thing, but the application process has me questioning my interest. Between limitations in the web site project ranking system, and dealing with unknowns (did this student submit applications to other groups, or more than one to us?) it runs like a bad interview puzzle question:

You have 30 chickens, 30 foxes, and 30 bags of corn, one canoe, and one river. You can only fit one with you in your canoe, and wish to take them all to the other side of the river. If you ever leave a chicken with corn, or a fox with a chicken, the latter will be eaten. A bandit might come by and steal up to one item per river crossing. In what order do you take items across to maximize the results of Google's sponsorship?

And I hear it's much better than last year...

(0 Comments ) (0 Trackbacks)