Friday, January 29, 2010

Tart status update

Recent changes:
  • Type solver now correctly solves nested array literals: let x = [[1, 2, 3], [1, 2, 3]];
  • The EntryPoint module now converts argc / argv into a String[] array and catches any stray exceptions.
    • Still needs work to run static constructors.
  • Started work on tart.io.StringReader, unit tests in progress.
  • "package-level" reflection implemented - this is the ability to iterate over all modules in a single package. (This is the first example of a data structure that is synthesized by the linker - there will be others to follow, I am sure.)
One issue that I am mulling over is the relationship between default constructors and reflection. Constructing a type via reflection is much easier if the type has a no-arg constructor. Otherwise, you have to know what values to pass to the constructor. Like most languages, Tart creates a default constructor if no constructor is defined by the programmer. However, unlike most languages, Tart's default constructor is not a no-arg constructor. Rather, the default constructor contains a parameter for each public member field, with a default value for that parameter which is the default for that field.

For example, given a simple type:

struct Point {
   var x:int;
   var y:int;
}

You can construct an instance of this type using any of the following:

var p0 = Point();
var p1 = Point(10, 10);
var p2 = Point(x=10, y=10);

In the first example, it appears as if no arguments are being passed, but that's not the case. Rather, the way default arguments work is that whenever a parameter is missing, the default value is passed in its place. So "Point()" is really equivalent to "Point(0, 0)".

But the default parameter mechanism isn't used when a method is called via reflection. The filling-in of default parameters is done by the compiler at compile time at the calling site. If you call "Point()" via some other mechanism, such as via a function pointer or reflection, then all of the arguments must be supplied, including the ones with default values.

While it is possible for a caller to inspect the type signature of the reflected function and figure out what parameters to supply, in practice this is quite difficult.

I ran into this problem while trying to write unit tests. Say I have a test class:

class MyTest : Test {
   var testClass:FooBar;
}

Since I didn't declare a constructor, the compiler will create one for me, with a parameter "testClass:FooBar". But the unit test framework doesn't know how to build a FooBar, so it can't construct the test class without knowing a lot more about the argument.

What I really want, in this case, is just to be able to construct an instance of MyTest without worrying about what constructor parameters are required.

It sounds like what I need to do is generate a no-arg constructor as well as the default constructor (assuming that the default construct has arguments to begin with.)

No comments:

Post a Comment