Wednesday, June 27, 2012

Modules (how things you ignore bite you in the ass)

Unfortunately, since my last bit of progress I realized that something I wanted to do was broken. One thing Tangent should be able to do is if you have some serialization library:

serializable => abstract class {
  serialize (this) => string;

// ... 

Which requires its serializable types to implement some basic function to take an instance and return a string. Now assume you have some type T in a different library and need to glue them together:

serialize (instance: T) => string { ... };

You should be able to just specify an implementation and since T now satisfies the interface, it should be considered serializable. Well it would; sometimes. Since T and the method could exist in different namespaces (and likely exist in different DLLs) it wouldn't always... 

And honestly, it would be one of those largely horrible bugs to track down about why a type is sometimes a sub-type and sometimes not. Further, since that relation isn't constant it restricts how much caching can be done.

I largely ignored namespaces, simplifying my view of things to be one big flat scope to track less things. Once again "those hairy things that are best thought about later" (tm) turn out to cause problems. They usually do.

So after doing some research, I'm aiming to provide a module system for Tangent. It will be similar to some of the more modern implementations like Scala's. Modules take the place of namespaces, but are not static. In Tangent, they will behave almost identically to classes. You can create separate instances of them (likely useful for giving threads their own sandbox). You can supply parameters to them (configs, DI, parameterization on type). You can use them as parameters (DI, runtime behaviors). You can, and likely will mix them together (fill in partial behaviors, provide specialization). The only difference is that modules are effectively partial, which will likely lead to a few limitations due to composition order issues.

I expect that I'm missing a lot of the nuance with these systems having not used one myself. I expect that a few of these features are grand ideas that suck (or are not viable) in practice. 

This also requires a slight syntax change. The declaration arrow (=>) is now used only for methods (since there's no way to distinguish abstract methods from type declarations if the syntax can have both in the same place (which modules allow). So type declarations now use a type declaration symbol (::) between the phrase and the implementation. Modules themselves will be declared like classes, except with module rather than class (for now).

I hope to have the specification fixed to account for these changes, and then fix the parser and tests in the near future. Stay tuned.

No comments:

Post a Comment