Showing posts with label structural types. Show all posts
Showing posts with label structural types. Show all posts

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

Monday, February 8, 2010

Dynamic calls using Structural Types

Using reflection can be a real pain in Java since the API is a Java API and consists of many gets and searches through collections not to mention so many exceptions that need to be handled. In Scala there is a wonderful way to clean up a reflective call down to a single line (assuming you don't want to worry about handling exceptions.) Here structural typing can really be a pleasure.
  1. // I am assigning a string to an Any reference
  2. scala> val s:Any = "hello :D"
  3. s: Any = hello :D
  4. // Any does not have a length method
  5. scala> s.length
  6. < console>:6: error: value length is not a member of Any
  7.        s.length
  8.          ^
  9. /*
  10. But I can cast it to a structural type with a length method
  11. */
  12. scala> s.asInstanceOf[{def length:Int}].length
  13. res2: Int = 8

There are restrictions to this. For example implicits will not work:
  1. /*
  2. The method r is part of StringLike (or RichString in Scala 2.7) 
  3. and there is an implicit conversion from String to RichString/StringLike.
  4. The structural type does not try to apply the implicits because implicits are a
  5. compile time artifact and that information is not kept at run time.  Perhaps this
  6. will be added in the future but it is not present now.
  7. */
  8. scala> s.asInstanceOf[{def r:util.matching.Regex}].r
  9. java.lang.NoSuchMethodException: java.lang.String.r()

More examples:
  1. scala> val s:Any = "hello :D"
  2. s: Any = hello :D
  3. scala> s.asInstanceOf[{def charAt(x:Int):Char}].charAt(2)
  4. res9: Char = l
  5. /*
  6. This is interesting.  The actual method returns Char, but Char is
  7. compatible with Any so this cast works.
  8. */
  9. scala> s.asInstanceOf[{def charAt(x:Int):Any}].charAt(2) 
  10. res10: Any = l
  11. // Now lets test to see if that lenience is available for parameters:
  12. scala> class X 
  13. defined class X
  14. scala> class Y extends X
  15. defined class Y
  16. scala> class T {
  17.      | def x(x:X):Int = 1
  18.      | }
  19. defined class T
  20. scala> val a:Any = new T()
  21. a: Any = T@687c3b99
  22. scala> a.asInstanceOf[{def x(x:X):Any}].x(new Y())
  23. res11: Any = 1
  24. /*
  25. Ok so return values can be subclasses but not params
  26. */
  27. scala> a.asInstanceOf[{def x(x:Y):Any}].x(new Y())
  28. java.lang.NoSuchMethodException: T.x(Y)
  29. at java.lang.Class.getMethod(Class.ja

Use with care :-D

Friday, February 5, 2010

Introducing Structural Types

Structural types allows one to declare types based on the methods the type has. For example you could define a method that takes a class containing a close method. This is fairy analogous to duck-typing in dynamic languages. Except that it is statically enforced.

The main example used here was from a comment on the Code Monkeyism Blog. The commenter further explains that this example is in fact from Beginning Scala chapter 4 (which I would like to read but have not yet had the time.)
  1. /*
  2. A can be any object that has a close method.  
  3. This is statically typed which makes some restrictions which are explained later
  4. */
  5. scala> def using[A <: {def close(): Unit}, B](param: A)(f: A => B): B = 
  6.      | try {
  7.      |     f(param)
  8.      |   } finally {
  9.      |     try {
  10.      |        param.close()
  11.      |     } catch { case _ => () }
  12.      |   }
  13. using: [A <: AnyRef{def close(): Unit},B](param: => A)(f: (A) => B)B
  14. scala> using(new java.io.ByteArrayInputStream("hello world".getBytes)){ in => 
  15.      | io.Source.fromInputStream(in) foreach (print)                          
  16.      | }
  17. hello world
  18. scala> using(new java.io.ByteArrayInputStream("hello world".getBytes)){ in => 
  19.      | io.Source.fromInputStream(in) mkString ""                              
  20.      | }
  21. res8: String = hello world

That is extremely powerful and the consequences will be visited more in the future. But because structural typing is statically enforced it is not quite as flexible as dynamic language's version of duck typing. For example you cannot do:
  1. scala> val i:Any = new java.io.ByteArrayInputStream("hello world".getBytes)
  2. i: Any = java.io.ByteArrayInputStream@145a25f3
  3. /*
  4. This does not work because 'i' is defined as type Any.  Not a type that is closeable.  
  5. Casting can be used to get around this issue.  I will address that in its own post
  6. */
  7. scala> using(i){ in => 
  8.      | io.Source.fromInputStream(in) mkString ""
  9.      | }
  10. < console>:8: error: inferred type arguments [Any,B] do not conform to method using's type parameter bounds [A <: AnyRef{def close(): Unit},B]
  11.        using(i){ in =>

An alternative to the first using example is to use call by name to construct the closeable. The reason one might want to do that is because it allows currying of the method:
  1. scala> def using[A <: {def close(): Unit}, B](param: =>A)(f: A => B): B = 
  2.      | val closeable = param  // notice param is only referenced once
  3.      | try {
  4.      |     f(closeable)
  5.      |   } finally {
  6.      |     try {
  7.      |        closeable.close()
  8.      |     } catch { case _ => () }
  9.      |   }
  10. using: [A <: AnyRef{def close(): Unit},B](param: => A)(f: (A) => B)B
  11. /*
  12. if this was accessing a database a new connection would be made automatically each time this function was used
  13. */
  14. scala> val usingTheWorld = using[BStream,Int](new java.io.ByteArrayInputStream("hello world".getBytes))_
  15. usingTheWorld: ((java.io.ByteArrayInputStream) => Int) => Int = < function1>
  16. scala> usingTheWorld { s => io.Source.fromInputStream(s).length}  
  17. res3: Int = 11
  18. scala> usingTheWorld { s => io.Source.fromInputStream(s).getLines().length}
  19. res5: Int = 0

Tuesday, December 8, 2009

Labelled Multiple Returns

A cool idea I found at http://stackoverflow.com/questions/1827672/is-there-a-way-to-have-tuples-with-named-fields-in-scala-similar-to-anonymous-cl. A very simple idea but very useful.
To summarize, you want to return multiple values but want to assign names to the values rather than use a tuple which more or less assigns indices to the different values. Here are a couple of solutions:

Using structured types. Simplest solution with the least extra code.
  1. scala> def multipleReturns1 = {
  2.      | new { val first = 1; val second = 2 }
  3.      | }
  4. multipleReturns1: java.lang.Object{def first: Intdef second: Int}
  5. scala> multipleReturns1
  6. res0: java.lang.Object{def first: Intdef second: Int} = $anon$1@549b6976
  7. scala> res0.first
  8. res1: Int = 1
  9. scala> res0.second
  10. res2: Int = 2
  11. scala> import res0._
  12. import res0._
  13. scala> first
  14. res3: Int = 1
  15. scala> second
  16. res4: Int = 2

Using case classes. Returns a product which has properties that may be useful.
  1. scala> def moreReturns = {
  2.      | case class Returns (one:Int, two:Int)
  3.      | Returns(1,2)
  4.      | }
  5. moreReturns: java.lang.Object with ScalaObject with Product{def one: Intdef two: Int}
  6. scala> moreReturns
  7. res5: java.lang.Object with ScalaObject with Product{def one: Intdef two: Int} = Returns(1,2)
  8. scala> res5.one
  9. res6: Int = 1
  10. scala> res5.two
  11. res7: Int = 2
  12. scala> import res5._
  13. import res5._
  14. scala> one
  15. res8: Int = 1
  16. scala> two
  17. res9: Int = 2
  18. scala> res5.productIterator foreach println _
  19. 1
  20. 2
  21. scala> res5.productPrefix
  22. res15: java.lang.String = Returns