Tag Archives: self

Self type and pinned spiral

It is amazing how different ideas can all of the sudden click and create one coherent blueprint for a cool feature. Yes, I know, I should be doing generator — but this is exactly where the problem began.

Here is how it went — I was implementing rich `Iterable` interface and stumbled on `concat` method. On the first glance it is obvious — it takes another `Iterable` and also returns `Iterable`, no problem. But think about using it — when you have some arbitrary `Iterable` it works as expected, but if you have for example `String`… Do you really expect to concatenate two strings and get some `Iterable` in result?

OK, so let’s make a correction ¹ — the outcome should be `Self`. It will work perfectly with `String`, we can also define `prepend` and `append`. But… wait a second, `Set` is `Iterable` as well, right? How can you prepend anything to a set and get a set back? If you don’t see a problem — you can add something to set, but not concatenate sets, or append anything to it, because except for one special case, set is not a sequence (there is no order in a set).

I found a solution, it waits right now for implementation (I needed a break from coding, thus this post) — `Set` is not an `Iterable`, it can be treated as one (thanks to implicit conversion) — subtle difference, but making things consistent. You can call `append` on `String` and get back a `String` and at the same time you can `append` on `Set` and get an `Iterable`, because it will be silently converted to this type on call.

Implicit conversions were easy — they are just a parameterless methods overloaded on result type. In Skila with “have to read the result of the function” feature it simply fitted right in.

One thing was still missing — how can you ensure that regular method returns `Self` type? You can track whether the returned value is really pure `Self`, but sometimes you don’t work with `Self` type in the first place. The only alternative would be relying on the fact that every descendant type will override such method and produce its own type, making effectively given method a factory of `Self`. And this concept was already present in Skila — `pinned` regular methods waited long for such cause, but now it is done. So either you write one general method with `Self` or you will guarantee with `pinned` every type will have its own implementation.


¹ If I am not mistaken, Scala solves similar kind of problems with what-can-build-what types. This part seems too convoluted for me so I even didn’t dig deeper.

Advertisement
Tagged , , , ,

SELF — one factory to rule them all

Another promise fulfilled — having pinned constructors in hand I could add “SELF” which behaves like implicit generics. Or you can think of it as virtual static feature.

Probably the best way to present it is using factory pattern:

struct Foo
  // constructor
  def pinned init() Foo 
  do
    return self // "this" in C++ family
  end

  def static Create() SELF
  do
    return new SELF();
  end
end

struct Bar : Foo
  def pinned init() Bar
  do
    return self 
  end
end  

The “SELF” which interests us sits in “Create” method. When you call it as “Foo.Create” you will get instance of “Foo”, but when you call it as “Bar.Create” you will get “Bar” object. Please note that such call does not cause an error:

var obj Bar = Bar.Create();

The above snippet would be erroneous if “Create” was defined differently, namely:

  ...
  def static Create() Foo
  do
    return new SELF();
  end

forcing you to write:

var obj Foo = Bar.Create(); 
// Bar is created nevertheless

But since it was defined with result type as “SELF”, the actual result type changes from call to call and compiler knows about it.

To summarize — “self” is a polymorphic reference to an object, “SELF” is a polymorphic reference to a type. You can create new instances using “SELF” as long as the used constructor is marked as pinned.

Tagged , , , ,

All the noise about static

Who would thought that adding “SELF” can cause so much fuss — obviously I needed “static” notion in Skila, which I hadn’t have and when I added it appeared NLT parser is not suitable for new set of parsing rules.

The last problem came as no surprise — so far NLT forking parser executed all user actions, even in multiple branches. This had to lead to problems and hit me this weekend. So instead of doing fancy stuff with pinned constructors, I sat down and changed executing user actions into logging parser actions. On successful parse, all commands are played back and then user actions are executed.

No rocket science, nevertheless I was one day short, and after adding exposing field’s methods feature plus fixing PHP backend a bit I ran out of time. I plan to squeeze error reporting on static misuse into workdays so I will be able to come fresh to implementing pinned constructor and “SELF” next weekend.

Tagged , , , ,

Implicit generics and pinned constructors

It is preliminary step of enhanced generics we know from C# and I hope all things finally clicked in for implementing this feature. Consider such code:

public class ClassModifier : TreeNode
{
  public bool IsAbstract { get; private set; }
  public bool IsVirtual { get; private set; }
  public bool IsStatic { get; private set; }

  private ClassModifier(NodeCoords coords)
    : base(coords)
  {
  }

  public static ClassModifier Abstract(NodeCoords coords)
  {
    return new ClassModifier(coords) 
      { IsAbstract = true };
  }
  ...

and

public class MethodModifier : TreeNode
{
  public bool IsAbstract { get; private set; }
  public bool IsVirtual { get; private set; }
  public bool IsStatic { get; private set; }
  public bool IsNew { get; private set; }
  public bool IsOverride { get; private set; }

  private MethodModifier(NodeCoords coords)
    : base(coords)
  {
  }

  public static MethodModifier Abstract(NodeCoords coords)
  {
    return new MethodModifier(coords) 
      { IsAbstract = true };
  }
...

Factory methods as usual, nothing special except the code is highly redundant. In PHP it can be expressed nicely because it has static constructor with late binding — it works like static polymorphism. It can be shortened in C# too, but with ugly twists.

However Skila is meant to be expressive and compiled language.

So I came up with idea of pinned constructor for the beginning. Once added to any class such constructor has to be overridden in every descendant class (or automatically upgraded). Secondly special keyword to express static polymorphism is needed — “SELF” sounds just right. With those two enhancements the code becomes much shorter (it is not Skila yet):

public class ClassModifier : TreeNode
{
  public bool IsAbstract { get; protected set; }
  public bool IsVirtual { get; protected set; }
  public bool IsStatic { get; protected set; }

  protected pinned ClassModifier(NodeCoords coords)
    : base(coords)
  {
  }

  public static SELF Abstract(NodeCoords coords)
  {
    return new SELF(coords) 
      { IsAbstract = true };
  }
  ...

public class MethodModifier : ClassModifier
{
  public bool IsNew { get; private set; }
  public bool IsOverride { get; private set; }
  ...
}

Thanks to pinned constructor it is safe to write “new SELF(coords)” — every class has to support such call. And because “SELF” works as implicit generics when I call “MethodModifier.Abstract()” I will get “MethodModifier”, not “ClassModifier” despite the fact the method is static and it is defined in “ClassModifier” class.

Tagged , , , , , , ,

First step into covariant world

It is interesting how given concepts of programming languages made their way into the mainstream — I was able to observe how functions from “uhm, do we really need them?” perspective became first class citizens (“what, you cannot pass a function to a function?”).

The next thing on my watch list is covariance and contravariance — they were finally introduced in C#, but sadly, only partially.

Since I am working back and forth now on improving support of functions in Skila it was a hard to miss an opportunity to finally make this happen:

struct Foo 
  def virtual get() Foo = new Foo();
end

struct Bar : Foo
  def override get() Bar = new Bar();
end

You don’t have to mark those methods in any special way, compiler knows you are overriding the method, so you can return a derived type in a derived class. That’s it — done!

Adding this/self (self reference to current type instance) and THIS/SELF (per analogy, current type) is right behind the corner. In a way it will be a return to one of the COOL features, yet with more flexibility.

Tagged , , , , , ,