Tag Archives: pinned

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 , , , ,

What’s cooking — type generics and method’s zoo

I’ve just finished generics with type parameters, no surprise since I already implemented symbol generics. So far Skila does not have constraints, but I prefer to cover more ground in order to have working language in hand. Collections (and passing them around) is my next step.

Since this will take some time, I might make a break and add static virtual methods. You can say — “what? How a static method can be virtual”. Well, in C++/C# it cannot, because it was implemented that way. All it takes is one look from different perspective — take a regular virtual method and limit its access to static features only. Here you have it — static virtual method.

It is not a feature I will die for, but I too often bump into a problem which could be nicely solved having static virtual method and its cousin — pinned method (new concept), static or not. Pinned method is just like virtual one but it is erased with each new class in hierarchy, meaning once you add it somewhere you have to redefine it in each descendant class. This is pretty similar to pinned constructors (which are already implemented in Skila).

With such arsenal you can finally decide what is better for you, static factories or per instance, you can handle some traits of the class (type) with static methods. Nothing revolutionary, just more freedom and flexibility.

And since there is already so much variety why not add yet another one, with even more limited access — actually with no access at all. Function/method which relies only on its parameters with no side effects, pure function. We’ll see…

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 , , , ,

Pinned constructors — served as promised

Exactly as I wrote previously, I added pinned constructors feature into Skila. Let me show you the syntax:

struct ClassModifier 
  def pinned init(coords NodeCoords)
  do
    ...

The novelty is “pinned” keyword after “def” (“init” is Skila constructor).

Once you add pinned constructor you have to redefine it (or allow compiler to do it for you) in every descendant class. Compare this to regular methods — when you add one you know it will stay in every derived class. It is not true with constructors though, you can have elaborate constructor and it is only good for the class you define it for. So you can think of pinned constructors as an aid for bringing symmetry between methods and constructors.

If you don’t define any constructors compiler will redefine pinned constructors for you with simple field initialization and calling base constructor. Please note that unless parameterless constructor (the default one) is pinned in base class, it won’t be redefined by compiler along with pinned ones.

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 , , , , , , ,