Sunday, November 29, 2009

Turtle Tower

My good friend RT painted this the other day -- little did he know that today Infinite Turtle Theory would actually be relevant to what I want to talk about:

Anyway, here's the thing: in Mix I want every first class value to be an object. That is, instances of classes are objects, literals like 7 and true are really just instances (of Int and Bool, respectively) and so are objects. Functions are just objects with a method named op(). And methods are just functions that hold a reference to this -- recall this discussion on implementing methods. (This is a bit circular, I know; here be our first stack of turtles).

But, remember I said first class values; not everything you deal with in Mix is first class. Classes themselves (not their instances), control flow constructs (like if, for instance), and instance members are all examples of parts of Mix that are not first class. You can't pass a class around, modify it, and then create an instance from it. You can't pass a statement to a function (though it might be fun to try that out; I'll make a note of it). And you can't write the following code:

class Foo
{
  public var Bar = 7;
}

getField(o, f)
{
  return o.f;
}
Int main(String args)
{
  return getField(new Foo(), Bar);
}

Again, it might be interesting to allow that kind of first class status for member names in a statically typed language like Mix; I know other languages support such kinds of things.

Back on track, we want everything to be an object but this leaves us with a challenge: how do actually represent things like integers, reals, strings, and so on? For booleans we might try the following:

public Bool
{
  ToString()
  {
    if(this.IsTrue() is not null)
      return "true";
    else
      return "false";
  }
  
  operator==(other)
  {
    var t1 = this.IsTrue();
    var t2 = other.IsTrue();
    if(t1 is not null && t2 is not null)
      return new True();
    else if(t1 is null && t2 is null)
      return new True();
    return new False();
  }
}

class True : Bool
{
  IsTrue()
  {
    return this;
  }
  
  IsFalse()
  {
    return null;
  }
}

class False : Bool
{
  IsTrue()
  {
    return null;
  }
  
  IsFalse()
  {
    return this;
  }
}

Here we managed to define booleans in the language, though our technique seems a bit hackish; what about that "true" we left in there? Instead of trying to find a way of implementing each of these "ground types" with pure Mix, it would be nice if they were somehow "built-in" to the language. On the other hand, I'd rather not have to special case them all over the place, and it would be great if we could grow the set of built-ins easily. So, what is at the bottom of this stack of turtles (our second, for those of you who are counting).

Enter abstract classes. An abstract class is one whose purpose is to provide a "binding" to a built-in type (one that is likely implemented in C#). For instance, we could have an abstract class binding System.Int32, one binding System.String, and so on. The binding is like an interface between the C# implementation and the Mix type system. An abstract class generates no code when it is compiled; this "interfacing" is it's only role.

To see how it works, consider the following binding for System.String:

abstract class String
{
  operator==(o)
  {
    return null as Bool;
  }
  
  operator[](index)
  {
    index.ToInt() as Int;
    return null as Bool;
  }
  
  Join(s)
  {
    s.ToString() as String;
    return null as String;
  }
}

Lot's of code, all involving this new operator as. This operator isn't the same as the C# as operator (and therefore perhaps it should get a different name, though as you'll see it is somewhat fitting). It's behavior at compile time is that it checks that the left side argument has only exactly the type on the right; if so it returns a typeset consisting of a new instance of the type on the right. At runtime the as expression just returns its left side.

Given this description, let's consider the definition of operator[]. Type checking an invocation of this method with an argument index entails checking that index implements ToInt, and that the result of invoking ToInt is in fact an instance of type Int; if this is the case then the return type is Bool; otherwise an error is returned.

So, other than making it very easy to bind simple types, what do abstract classes get us? Well, consider binding an array:

class Array
{
  private var elements;
  
  new(index)
  {
    index.ToInt() as Int;
  }
  
  operator[](index)
  {
    index.ToInt() as Int;
    return this.elements;
  }
  
  operator[]=(index, value)
  {
    index.ToInt() as Int;
    this.elements = value;
    return;
  }
  
  // Etc.
}

What's nice about this binding is that we can use an instance variable to track the type of the array. So, if we have an array, and add a few items to it, we can verify that any object accessed from the array is used in the correct way; this of course restricts the array so that all elements are assumed to be of the same "type", so that we don't allow a particular operation on an element unless all elements can perform that operation (remember our definition of correctness).

Int main(String args)
{
  var a = new Array(10);  //Array starts out with null in each position.
  for(var i = 0; i < a.Length(); i++)
    a[i] = "Hello!";
  a[0] = 7;
  a[2] = true;
  
  foreach(var e in a)
    print(a.ToString());  //OK: Int, Bool, and String all implement ToString.
    
  a[6].ToLowerCase(); //Error: Int and Bool do not implement ToLowerCase.
}

So that's how the current incarnation handles the second infinite stack of turtles. We'll see how to deal with the first infinite turtle tower (namely, that a function is an object with a particular method, but a method is just a function -- which is an object with a particular method, but a method is just a function -- this is getting old already) next time.

Wednesday, November 25, 2009

And Now For Something...

...unrelated. It seems that, with Windows 7, the explorer does a really great job of forgetting where you left your windows. I'm the sort of person that likes to arrange commonly used windows "just so", so that they use the least amount of space, and so their layout makes some kind of sense (at least to me).

Windows 7 won't let me do that, at least I never figured out how, even after asking the internet. There were lots of suggestions that one use Window Manager by DeskSoft, which I tried. It seemed a bit flaky at times, but did more or less what I wanted, and then some.

However, I figured that the software was pretty simple, and I knew that if and when the shareware license expired I wouldn't be buying it (too unpolished, and really, it does something Windows should already do). So I thought, "Why not write an some free/Free/open-source/whatever-you-want-to-call-it software that does what I want?"

So I did. You can find an alpha version of WindowsWhere ("windows where you want them", if you follow me) hosted at Google Code. WindowsWhere is licensed under the GPL v3. Hopefully at least one other person has been annoyed by this, and hopefully I didn't just totally miss a "native" solution.

Thursday, November 5, 2009

Concrete Mix Alpha

For the past few days I have been working hard on getting Mix into a state where it can be released. It's slow going; I have been cutting out everything that isn't necessary for a "preview" (like integration with .NET, support for some level of nominal typing, and a few other things, all of which I intend to discuss at some point). So sorry about the dry spell, it will rain (if only lightly) soon enough.