Monday, August 17, 2009

Introductions

I said that Mix is an object-oriented language after the tradition of C# and Java, which is true enough. There are classes, and the syntax is C-like, and the operational semantics of the language are exactly what the average C# or Java programmer might expect. So, sample code:

class SomeClass
{
  private var someMember;
  
  public new(anArg, anotherArg)
  {
    if(anArg)
    {
      this.someMember = anotherArg.M(anArg);
      anotherArg.N();
    }
    else
    {
      this.someMember = new List();
    }
  }
  
  public GetSomething()
  {
    for(var i = 0; i < 42; i++)
    {
      this.someMember += i / 6;
    }
    return this.someMember;
  };
};

This class really doesn't do anything; it's here to highlight that Mix code really looks like some code you might have written in a language like C#. It has if and for, members and methods, and all kinds of normal stuff; if you don't like that everyday stuff you're not going to like Mix's syntax, unfortunately. In my opinion it is a reasonably usable and certainly widely known syntax, so I went with it.

The only interesting bit is that there aren't any types in the usual places. That is, you normally expect, in a statically typed language (unless your boss let's you write in O'Caml, or F#, or some other language with inference) to have to write types all over the place. If it were Java we'd need them for each member, for each method (return and argument types), and each local variable. In C# these days you can drop the types on locals. But here we haven't any at all, unless you count SomeClass itself, which I won't: it's more like a prototype, in that we use it to create an object, but not to classify objects later on, as we'll see.

So, this is the language in which I am interested: no types on members, methods, or local variables, looks somewhat like your everyday object-oriented language, simple enough. I could compile this down to Python, say, or Javascript, easy as that (where "that" is snapping your fingers). But I don't only care about compiling and running Mix programs, I care about analysing them for correctness at compile time (and really, all I would have done was give a different syntax to a fragment of one of those languages; that's no fun). Now, you might be the sort of person that isn't interested in static analysis; you probably won't care for Mix, either, so you might want to hang out with the folks that left when I mentioned braces.

Still here? Ok, so, what do I mean by correctness? I'm taking the very simple criteria of "doesn't call methods on objects that don't support those methods" as meaning "correct" with respect to the type system. So, I don't want to call Append on an Int, for example. We'll (eventually) see how this criteria can be used in some interesting and (hopefully) powerful ways, but for now let's leave it (my "correctness" criteria) at that.

To see what I mean, let's look at a (very slightly) more reasonable example, with PETS! (I like pets, in particular my cat, Mortimer). Here we go:

class Cat
{
  public Speak() { return "meow!"; };
  public Pounce(target) { ... };
}

class Dog
{
  public Speak() { return "arff!"; };
  public SearchForBombs() { ... };
};

main()
{
  var pet = null;
  if(somethingOrAnother)
  {
    pet = new Cat();
  }
  else
  {
    pet = new Dog();
  }
  print(pet.Speak());
};

So, super simple example, but you probably already get the idea: pet could be either a Dog or a Cat, but because both of them can Speak, we're all good. What if the we tried to call Pounce on pet? According to Mix (that is, according to me), we'll treat it as an error: there is some path through main that leads to pet having an instance (of the class Dog in this case) that cannot Pounce. Even if the programmer knows, somehow, that somethingOrAnother is always true, the type system will treat this as an error.

One way to think of this, which I'll make more concrete in future posts, is that every target of an method invocation must always (syntactically, in the source) be an instance of a class that implements the method. So, in the above example, in the expression pet.Speak(), pet will, no matter what, be set to an instance of a class that implements Speak, and is therefore correct.

Anyway, that should give you a bit of the flavor of what's to come.

No comments:

Post a Comment