Tuesday, February 9, 2010

Structural Types: Multiple Methods and Type Aliasing

There are two more aspects related to structural typing that are useful to look at. Structural types with multiple methods and type aliases.

For background on this topic also look at:
Structural Types are not limited to defining a single method. In that regard they are very similar to interfaces without the binary incompatibility issues. However do not be fooled into thinking they are the same thing. For one reason reflection is used so performance can be an issue in certain cases and also interfaces/traits have semantics that structural types do not.
  1. /*
  2. Defining a types that has both a length and charAt method.  
  3. Just a warning.  If you leave off the () after length this will not work.  This is not a bug.  Martin kindly left a comment on why it is not.
  4. */
  5. scala> def foreach(t : {def length():Intdef charAt(i:Int):Char}, f : Char => Unit) = {
  6.      | 0 until t.length foreach {i => f(t.charAt(i))}  
  7.      | }
  8. foreach: (t: AnyRef{def length(): Intdef charAt(i: Int): Char},f: (Char) => Unit)Unit
  9. // A string matches the structural type
  10. scala> foreach ("hello", println _)
  11. h
  12. e
  13. l
  14. l
  15. o

Pretty unexpected I would say. A feature of Scala which complements Structural types are type aliases. They are useful in many situations and one is with use with Structural Types:
  1. /*
  2. With type aliasing you can assign a structural type a name
  3. */
  4. scala> type IChar = {def length():Int
  5.      |               def charAt(i:Int):Char}
  6. defined type alias IChar
  7. scala> def print( t : IChar) = 0 until t.length() foreach {i => println(t.charAt(i))}
  8. print: (t: IChar)Unit
  9. scala> print("gurk")
  10. g
  11. u
  12. r
  13. k

2 comments:

  1. that _ after println is unecessary - no need to create an anonymous function.

    Good article though :)

    ReplyDelete
  2. Because you asked: The fact that you need to write the () after length is not a bug. Structural matching distinguishes () methods and parameterless methods. And java.lang.String#length does take a () parameter list.

    The () can be elided only when calling length on a string; that's not the same as matching it as a member of a type.

    ReplyDelete