Topic: APLX Help : Help on APL language : APL Fundamentals : Mixins
[ Previous | Next | Contents | Index | APL Home ]

www.microapl.co.uk

Mixins


What are Mixins?

As we saw in the previous sections, classes which you write in APLX can inherit from other classes; this means that the methods and properties of the parent class (or classes) are available in the child class.

Although the concept of inheritance is very powerful, there are some circumstances where more flexibility is required. In APLX, a class cannot inherit from multiple different classes, only from one parent class (although that might itself inherit from its parent, and so on). Nor can a class inherit from an external class; for example, you cannot write an APL class which directly inherits from a Java class.

'Mixins' address both of these requirements. They allow you to extend your user-defined classes so that, at run-time, they dynamically 'mix in' functionality (i.e. methods and properties, and perhaps events) from one or more other classes; these can be internal (user-defined, and written in APL), or external (.Net, Java, Ruby etc, or a built-in APLX system class).

Because mixins are attached dynamically at runtime, they are very flexible. For example, in a commercial application you might have an Invoice class (which perhaps inherits from an AccountingDocument class). If you wanted to add functionality which would allow the Invoice class to be faxed or e-mailed to the client, you could dynamically (at run time) mix-in a Fax or EMail class to handle the transmission of the document. This is similar to multiple inheritance as implemented in some other languages, but more flexible because you don't need to know in advance which mixin will be required; different instances of the same class can, if appropriate, mix-in different classes.

When you 'mix-in' another class, what effectively happens is that a new object of the mixed-in class is created, and merged into the original object. The public properties and methods of the mixed-in class now become available in the original object, very much as though they were defined in the original class.

You can mix-in as many other classes as you like; you can even mix in classes from multiple different architectures. For example, you could write (in APL) a FinancialClock class to display the time in London, New York and Singapore. It could mix-in the System Class Window for the display, and the Java class timeZone to handle the different time-zone information.

Using Mixins

To use mix-ins, you first create an object (i.e., an instance of your APL class) in the normal way using ⎕NEW. You then use the System Method ⎕MIXIN to mix another class into the object. ⎕MIXIN has a similar syntax to ⎕NEW; the right argument is the class reference (or name, as a text vector), followed by any arguments to the constructor for the class you are mixing-in. The left argument can be omitted if you are mixing-in an APL class, otherwise it defines the architecture for the mix-in. For example, if you have a class called Invoice, and another class called Fax, you can mix the Fax class into an Invoice object as follows:

Create an instance of Invoice:

      inv←⎕new 'Invoice'
      ⍝ Properties:
      inv.⎕nl 2
customer
invoice_number
lines
order_number
      ⍝ Methods:
      inv.⎕nl 3
SetStatus

Mix class Fax into the Invoice object:

      inv.⎕mixin 'Fax'

      ⍝ Properties and methods now include those of Fax class:
      inv.⎕nl 2
cover_page         ⍝ <--- From Fax class
customer
fax_number         ⍝ <--- From Fax class
invoice_number
lines
order_number

      inv.⎕nl 3
Send               ⍝ <--- From Fax class
SetStatus

You can mix-in further classes in the same way.

Although in this example we have mixed-in the Fax class (using dot notation) after creating the original object, in many cases the natural place to do this will be in the Constructor of the original class. If you do that, the mix-in facility effectively becomes like multiple inheritance in some other languages.

Mixing-in an external class

You can mix an external class (.Net. Java, Ruby, or a built-in APLX system class) in to your APL class in the same way. In this case, you need to provide a left argument to ⎕MIXIN to specify the architecture, in the same way as you would with ⎕NEW. For example, we could add a second mixin, based on a Java class, to the Invoice class shown in the example above. All the properties and methods of the Java class then become available in the object:

      'java' inv.⎕mixin 'java.util.Date'
      ⎕box inv.⎕nl 3
Send SetStatus UTC after before clone compareTo equals getClass getDate getDay 
      getHours getMinutes getMonth getSeconds getTime getTimezoneOffset getYear 
      hashCode notify notifyAll parse setDate setHours setMinutes setMonth 
      setSeconds setTime setYear toGMTString toLocaleString toString wait

      inv.toLocaleString
20-Mar-2009 11:43:03

Referencing the mixed-in object directly

Sometimes you may need to access the underlying object which has been merged into your APL object. For this, you need a reference to the underlying object. You can get this in two ways:

(1) ⎕MIXIN actually returns as an explicit result the underlying object reference (but with display potential switched off, as a 'shy' result). So you can assign this to a variable or property of your APL class, and use this to call the underlying object directly:

      jd←'java' inv.⎕mixin 'java.util.Date'
      jd.⎕classname
java:java.util.Date

(2) You can use the system method ⎕MIXINS to get a vector of references to the mixins:

      my_mixins←inv.⎕mixins
      my_mixins
[Fax] [java:Date]
      my_mixins[2].⎕classname
java:java.util.Date

Search order and over-riding a method

When a member of the class is referenced (either using dot notation, or as unadorned symbols when running methods of the class), APLX will use the following search order to find the named symbol:

  • First it will search the original class, (and its parent classes, if any)
  • Then it will search in the first mixin (and its parent classes, if any)
  • If there are further mixins, it will search these in the order in which they were mixed-in.

It follows from this that you can 'over-ride' a property or method from a mixed-in class; if your own APL class defines a member of the same name as a member of the mixed-in class, the APL version will be the one which is accessed; the mixed-in version will be hidden.

However, you can still call the mixed-in version by accessing it directly using the object reference returned either when it is created (explicit result of ⎕MIXIN), or from ⎕MIXINS. In our example, you could define a method toString, which overrides the Java version, but calls it to get the date as text:

      ∇r←toString
[1]   ⍝ String representing invoice
[2]   r←'Invoice number ',(⍕invoice_number),' dated ',inv.⎕mixins[2].toString
[3]   ∇

      ⍝ Insert toString as a method into class Invoice:
      'Invoice' ⎕ic 'toString'     
1
      inv.toString
Invoice number 11345301 dated Fri Mar 20 11:57:32 GMT 2009

Removing mixins from an object

The System Method ⎕UNMIX can be used to remove one or more mixins from an object. It takes a right argument which is a scalar or vector list of mixin-references to delete, and returns a binary vector with 1 for each mixin removed, and 0 if the mixin reference could not be found:

      inv.⎕mixins
[Fax] [java:Date]
      inv.⎕unmix inv.⎕mixins
1 1
      inv.⎕mixins
     
      inv.⎕nl 3
SetStatus
toString

Note that you don't normally need to do this; the mixins will be deleted automatically when the object which owns them is deleted.


Topic: APLX Help : Help on APL language : APL Fundamentals : Mixins
[ Previous | Next | Contents | Index | APL Home ]