Sunday, September 7, 2008

Duck Typing in a Static Core

I was reading an interesting blog post that described duck typing and how it helps dynamic languages, and how it works in theory. I'm thinking of a few ways on how this might be feasible to implement, and I think I have one. I'm going to do a few whiteboards on the idea and post back when I get a chance.

The basic idea involves use of generics. The full idea will take some time to just map out, and to implement it might take a few months, and that's only after I get the code generator going full steam.

Since the entire project is about code generation, the idea involves dynamic mutability descriptors (classes) that help define the viability of a call to a method given the types for a call to that said method. There would also be a type-change lookup, with a running deviation gauge on the signature provided, if a type changed, structurally, since the last time the method was called, it would run the check again for that signature, and adopt a new method in place for the old one.

The issue with this lies in the fact that the CLI doesn't allow (generated) code to be disposed, except for entire app domains (to be unloaded). While I could encase all changes into their own app domain; management, and communication between them would be nightmarish at best, and not time, or performance worthy. A dynamic language that continually changed a type would yield gradually more and more junk in memory if it were to restructure itself on need. The solution to this would be to, obviously, try to reduce the need to continually change the type structure.

One thing that would allow this to go smoothly is enabling the system to look for the dynamic method descriptors first, thus ensuring that it locks onto the dynamic descriptor, which would take precedence (except for exact signature matches). The dynamic descriptors would be entirely generic, and would thus take any signature without the need to worry about deviations. Any change to a type through dynamic means would utilize a dynamic descriptor, and thus would not cause lookups to occur on types that changed, where the signature deviation on a specific call is greater than one. In plain English, this means that: if method A calls method on type X, method A has a dynamic descriptor, and the current signature on the call to method A did not deviate greater than 0 during deviation (dynamic descriptors don't deviate, since they accept any signature), then the method doesn't need to be regenerated, even if the type has changed since the last call to that method.

The complexity of each mutability descriptor will vary based upon how complex the method itself is. It will then utilize an IL generator to build dynamic variants of the method based upon the signature of the values provided. This will, in turn, cache the result. The reason for the descriptor's complexity is the need to go deeper than one level. It'll also utilize a secondary cache to help relate to certain kinds of linker-based relationships (does type X have method A with this exact signature, if not, look it up (full look-up), if that fails, find the next best alternative from cache, then the next best from the type (full lookup)). The worth of such a system is also debatable, and would likely only benefit dynamic languages, it'd (probably?) be faster than a fully dynamic system that handles the same thing.

The other reason for the concept above is I didn't really like the methods employed in Iron Python, using confusing, near undecipherable means to handle method calls, inheritance, and so forth. Though I'll admit, it works. I might find, in my research into this, that their method is favorable. Another thing I'll admit: the proposed solution would be incredibly irksome to build; however, I'm doing this because I find languages interesting.