Skip to content
July 26, 2009 / Abe Pralle

Automatic Properties, In-Line Classes, Delegate Properties, and caseNext

For the last couple of weeks I’ve been trying to come up with a good semi-automatic resource-loading framework for Plasmacore.  For each revision I added a new feature or two to Slag; I ended up not truly needing most of them but they’re good features nonetheless.  Here’s a quick overview of the new features – mostly by example.

Automatic Properties

First we have automatic properties that can be used when you have a single init method that stores each of its arguments into a property you’ve just defined.  Here’s an example of old code:

  class Person
    PROPERTIES
      name : String
      age : Int32

    METHODS
      method init( name, age ):
  endClass

Here’s the same code with automatic properties:

  class Person( String name, Int32 age )
  endClass

or even just:

  class Person( String name, Int32 age );

You can add additional properties and methods as you like.

In-Line Classes

Slag now supports in-line classes that work pretty much just like Java’s anonymous classes.  In addition, “METHODS” is now the default member category (so you can omit it if you start a class definition with a method), which makes in-line method definitions easier.  An example:

  class Operator
    method init:
    method apply( Real64 lhs, Real64 rhs ).Real64: abstract
  endClass
  ...
  method test( Real64 left, Operator op, Real64 right ):
    println( op.apply(left,right) )
  ...
  local Operator plus = Operator() with
        method apply( Real64 lhs, Real64 rhs ).Real64: return lhs + rhs
      endWith

  local Operator minus = Operator() with
        method apply( Real64 lhs, Real64 rhs ).Real64: return lhs - rhs
      endWith

  test( 5, plus, 3 )  # prints: 8
  test( 5, minus, 3 ) # prints: 2
  test( 5, Operator() with
        method apply( Real64 lhs, Real64 rhs ).Real64: return lhs * rhs
      endWith, 3 )  # prints: 15

Delegate Properties

Delegate properties allow you to specify that any unresolved method calls or property accesses be forwarded to one property in particular.  This is of particular use when you want to make one object that is essentially a proxy for another.  Example:

  class String
    PROPERTIES
      data : delegate Array<<Char>>
      hash_code : Int32
    ...
  endClass
  ...
  local String mesg = "Delegate *this*!"
  println( mesg.count )  # same as saying "mesg.data.count" - prints: 16

Only one property can be defined as a delegate.  Underneath the mechanism is very simple: at compile time failed member accesses are reevaluated with the delegate property.

caseNext

caseNext is handy in a which where you want to do something different every time based on a counter but you don’t really care what the case values are.  It just takes the previous case value (literal integer required), adds one to it, and makes that the new case.  For example, to load a different graphic (my plan is revealed!) each time a method is called:

  method load_next.Logical:
    load_index++
    which (load_index)
      caseNext: img_alpha = Image("alpha.png")
      caseNext: img_beta = Image("beta.png")
      caseNext: img_gamma = Image("gamma.png")
      caseNext: return false
    endWhich
    return true

If you started with “case 5:” then the first caseNext would be a shorthand for “case 6:”.  If you start with caseNext (as above) then it resolves to “case 1:”.

2 Comments

Leave a Comment
  1. Timothy Goya / Aug 6 2009 7:34 am

    For empty base classes like Operator, could you do something like:
    class Operator()
    method apply( Real64 lhs, Real64 rhs ).Real64: abstract
    endClass

    Also, that “Operator” is the example for inline classes screams language support for lambda functions.

    Can you override the failed member access function yourself like Ruby? Well, I guess not since it’s compile time, but it would be rather cool…

    The whole delegate property thing feels a lot like inheritance minus that pesky Liskov Substitution Principle. That is, a delegate property behaves exactly like an inherited base class, except the type checker won’t let you pass the derived class to methods that expect the base class.

  2. Abe Pralle / Aug 6 2009 9:45 am

    Saying Operator() instead of putting an empty init() method in there: in theory yes; good thing you mentioned that ’cause it crashed my compiler when I tried it. 🙂 It’s fixed now though!

    I started out wanting to *just* add lambda functions (or inline function definitions I called ’em). I was attempting to use a syntax that was totally new to Slag:

    calculate( x, Fn(Real64 a,Real64 b).Real64 { return a+b }, y );

    method calculate( Real64 a, Fn(Real64,Real64).Real64 op, Real64 b ): println( op.call(a,b) )

    It ended up being really hard to implement (especially trying to correctly substitute template placeholder types at the right time) and much less versatile than the inline classes, so I scrapped it and went with inline classes instead!

Leave a comment