Showing posts with label import. Show all posts
Showing posts with label import. Show all posts

Thursday, January 21, 2010

Exclude style import semantics

I can't remember if I posted this tip yet so I will do it again (or not :-P ).

If you want to import all classes in a package or object exception for one or two there is a neat trick to exclude the unwanted elements:
  1. /*
  2. The File class is aliased to _ (oblivion) and then everything is imported (except File since it does not exist in that scope)
  3. Note: File can be imported later
  4. */
  5. scala> import java.io.{File=>_,_}
  6. import java.io.{File=>_, _}
  7. scala> new File("it is a file")      
  8. < console>:8: error: not found: type File
  9.        new File("it is a file")
  10. scala> object O {
  11.      | def one = 1
  12.      | def two = 2
  13.      | def o = 0
  14.      | }
  15. defined module O
  16. /*
  17. Same tricks can apply to importing methods and fields from objects
  18. */
  19. scala> import O.{o=>_, _}
  20. import O.{o=>_, _}
  21. scala> one
  22. res2: Int = 1
  23. scala> two
  24. res3: Int = 2
  25. scala> o
  26. < console>:15: error: not found: value o
  27.        o
  28. // Once a class is imported into scope it can not be removed
  29. scala> import java.io.File
  30. import java.io.File
  31. scala> import java.io.{File=>_}
  32. import java.io.{File=>_}
  33. /*
  34. this still works because the previous import statement only adds an alias it does not remove the alias
  35. */
  36. scala> new File("..")          
  37. res6: java.io.File = ..
  38. // There can be multiple aliases in a scope
  39. scala> import java.io.{File=>jfile}
  40. import java.io.{File=>jfile}
  41. scala> new jfile("..")
  42. res0: java.io.File = ..
  43. // one more example of importing from objects
  44. scala> case class X(a:Int, b:Int, c:Int)
  45. defined class X
  46. scala> val x = new X(1,2,3)
  47. x: X = X(1,2,3)
  48. scala> import x.{a=>_,b=>_,_}
  49. import x.{a=>_, b=>_, _}
  50. scala> c 
  51. res1: Int = 3
  52. scala> b
  53. < console>:14: error: not found: value b
  54.        b
  55.        ^

Wednesday, December 2, 2009

What the @*!% is with the '_'

  1. scala> import java.io._ // 1
  2. import java.io._
  3. scala> import java.io.{ File => _ } // 2
  4. import java.io.{File=>_}
  5. scala> object MyObj{ def count=(1 to 10) }
  6. defined module MyObj
  7. scala> import MyObj._ // 3
  8. import MyObj._
  9. scala> class MyClass { def countDown= 10 to 5 by -1} 
  10. defined class MyClass
  11. scala> val instance = new MyClass()
  12. instance: MyClass = MyClass@69ebcd0
  13. scala> import instance._ // 4
  14. import instance._
  15. scala> def multiply(by:Int,x:Int)=2*x
  16. multiply: (Int,Int)Int
  17. scala> val double=multiply(2, _:Int// 5 
  18. double: (Int) => Int 
  19. scala> count foreach {i => double(i)}
  20. scala> val double2:Int=>Int = multiply(2,_)
  21. double2: (Int) => Int = & function>
  22. scala> count foreach {i => double2(i)}
  23. scala> count reduceLeft {_+_} // 6
  24. res3: Int = 55
  25. class Generic[T](val t:T)
  26. val generic:Generic[_] = new Generic(2) // 7

While at a glance the underscores do not seem related, in fact the general rule is fill in the blank. Sca_la what goes in the blank?

Going through the examples:
  1. import anything/everything in package
  2. this seems to be an exception. Assign File to oblivion. (It is no longer imported)
  3. import all methods in object
  4. same thing. Import all methods in instance object
  5. creat a new method where the first parameter is defined but all others will be defined later. In this case a special syntax is required so the compiler knows that a new method is desired and the missing parameters was not simply a mistake. There is another syntax for defining methods that do not require the _ for currying
  6. reduceLeft takes method with 2 parameters. _ + _ creates a function of 2 parameters: the first '_' represents the first parameter and the second '_' represents the second parameter.
  7. the '_' represents any value. This syntax is frowned upon since Scala has such a rich type system but can be useful when interoperating with Java. Perhaps a better declaration would be Generic[Any]

Thursday, November 12, 2009

Import Instance Properties

A truly fantastic aspect of Scala is the uniform principle that Scala attempts to adhere to. In other words Scala tries to not make any rules that only apply to a single case when it can be applied generally.

One example is matching you can see several uses of matching in the following topics:
But matching it applies to today's topic as well. This topic covers a cool trick that helps assist with parameter objects and complex return types.

This topic is another take on Assignment and Parameter Objects. There are cases when a method has a large number of parameters and the API can be cleaned up by introducing a parameter object. Or perhaps an object with several public proprties are passed to a method.
  1. scala> case class Params(p1:Int, p2:Int, p3:Int)
  2. defined class Params
  3. scala>  def method(params:Params) = {
  4.      |   println(params.p1, params.p2, params.p3)
  5.      | }
  6. method: (Params)Unit
  7. scala> method(Params(1,2,3))
  8. (1,2,3)
  9. }

The symbol 'params' introduces noise into the code. The noise can be reduced further by assigned the properties of the parameter object to local variables:
  1. scala>  case class Params(p1:Int, p2:Int, p3:Int)
  2. defined class Params
  3. scala> 
  4. scala>  def method(params:Params) = {
  5.      |   val Params(p1,p2,p3) = params
  6.      |   println(p1,p2,p3)
  7.      | }
  8. method: (Params)Unit
  9. scala> method(Params(1,2,3))
  10. (1,2,3)
  11. }

But we can do better remember that we can import methods and properties from an object:
  1. scala> object Obj {
  2.      |  val prop = 10
  3.      | }
  4. defined module Obj
  5. scala> import Obj._
  6. import Obj._
  7. scala> println(prop)
  8. 10

Since all instance are objects it is possible to import fields and methods from instances as well:
  1. scala>  case class Params(p1:Int, p2:Int, p3:Int)
  2. defined class Params
  3. scala> 
  4. scala>  def method(params:Params) = {
  5.      |   import params._
  6.      |   println(p1, p2, p3)
  7.      | }
  8. method: (Params)Unit
  9. }

The same technique is extremely useful when a method needs to return multiple values:
  1. scala>  def method() = {
  2.      |   (1,2,3)
  3.      | }
  4. method: ()(IntIntInt)
  5. scala> val retVal = method()
  6. retVal: (IntIntInt) = (1,2,3)
  7. /*
  8.  retVal is a tuple so we can import the tuple
  9.  properties.  Becareful to not do this multiple times in
  10.  the same scope
  11. */
  12. scala> import retVal._
  13. import retVal._
  14. scala> println(_1,_2,_3)
  15. (1,2,3)
  16. scala> def method2={
  17.        // Notice case class declaration can be contained in method
  18.      | case class Return(v1:Int,v2:Int)
  19.      | Return(6,7)
  20.      | }
  21. method2: java.lang.Object with ScalaObject with Product{def v1: Intdef v2: Int}
  22. scala> val r = method2
  23. r: java.lang.Object with ScalaObject with Product{def v1: Intdef v2: Int} = Return(6,7)
  24. scala> import r._
  25. import r._
  26. scala> println(v1,v2)
  27. (6,7)
  28. }

Wednesday, September 9, 2009

Using objects to access trait functionality

Today's topic is based on an article by Bill Venners. http://www.artima.com/scalazine/articles/selfless_trait_pattern.html. I recommend reading that article as it goes into much more detail. I also recommend taking a look at the earlier topic that covers companion objects.

The normal way to use a trait is to mix it in to an object. However there can be a problem mixing two traits containing methods with equal signatures. If the two traits are not designed to work together then you will get a compile error. Otherwise one method will override the other. Either way you cannot access both methods. There is an additional way to access the functionality of a trait. You can create an object (not instance) that extends the trait and import the methods when you need them.

If the trait is stateless then the object can be shared if not then make sure that sharing the object is carefully handled.

Examples:
  1. scala> trait T1 {
  2.      | def talk = "hi"
  3.      | }
  4. defined trait T1
  5. scala> trait T2 {
  6.      | def talk = "hello"
  7.      | }
  8. defined trait T2
  9. // Cannot extend C with T1 and T2 because they are not designed to work together
  10. scala> class C extends T1 with T2
  11. :6: error: error overriding method talk in trait T1 of type => java.lang.String;
  12.  method talk in trait T2 of type => java.lang.String needs override modifier
  13.        class C extends T1 with T2
  14.              ^
  15. scala> class C extends T1
  16. defined class C
  17. // objects can have state so becareful how you share them
  18. scala> object Obj1 extends T1
  19. defined module Obj1
  20. scala> object Obj2 extends T2
  21. defined module Obj2
  22. // You can give aliases to the imported methods and use them in the class
  23. scala> class C {
  24.      | import Obj1.{talk => hi}
  25.      | import Obj2.{talk => hello}
  26.      | def sayHi = hi
  27.      | def sayHello = hello
  28.      | }
  29. defined class C
  30. scala> val c = new C
  31. c: C = C@54d8fd1a
  32. scala> c.sayHi
  33. res0: java.lang.String = hi
  34. scala> c.sayHello
  35. res1: java.lang.String = hello
  36. scala> class C extends T1 {
  37.      | import Obj2.{talk => hello}
  38.      | def helloTalk = hello
  39.      | }
  40. defined class C
  41. scala> val c2 = new C
  42. c2: C = C@2ee634bf
  43. scala> c2.talk
  44. res2: java.lang.String = hi
  45. scala> c2.helloTalk
  46. res5: java.lang.String = hello

Monday, August 31, 2009

Java Conversions

The collections APIs in Scala are completely separate from those in Java, the primary reason is because they are designed from the ground up to be functional in nature. However, in keeping with Scala's goal of effortless Java integration there are implicits that convert between Java and Scala collections.

The object that needs to be imported has changed between Scala 2.7.x and 2.8 but the usage is the same. In 2.8 all conversions from Java to Scala objects (be it collections, concurrent constructs or others) are in objects call JavaConversions. For example in the August 31 nightly build there are 2 JavaConversions objects. scala.collection.JavaConversions and scala.concurrent.JavaConversions. As time progresses I expect that the types of JavaConversions will expand.

In scala 2.7 you can not convert Scala collections to Java collections only Java to Scala. In 2.8 you can do both.

So here is how to use conversions in 2.7.x:
  1. scala>val jmap = new java.util.HashMap[String,Int]()
  2. jmap: java.util.HashMap[String,Int] = {}
  3. scala> jmap.put("one", 2)
  4. res0: Int = 0
  5. scala> jmap.get("one") 
  6. res1: Int = 2
  7. scala>import scala.collection.jcl.Conversions._
  8. import scala.collection.jcl.Conversions._
  9. scala> jmap("one")
  10. res3: Int = 2
  11. scala> jmap("one") = 1
  12. scala> jmap("one")
  13. res5: Int = 1


And in 2.8:
  1. scala>val jmap = new java.util.HashMap[String,Int]()
  2. jmap: java.util.HashMap[String,Int] = {}
  3. scala> jmap.put("one", 2)
  4. res0: Int = 0
  5. scala> jmap.get("one")
  6. res1: Int = 2
  7. scala>import scala.collection.JavaConversions._
  8. import scala.collection.JavaConversions._
  9. scala> jmap("one")
  10. res3: Int = 2
  11. scala> jmap("one") = 1
  12. scala> jmap("one")
  13. res5: Int = 1

Wednesday, August 19, 2009

Implicit Methods

Scala is designed to be a scalable language and one if the features that assist in realizing this goal are implicit methods. I have seen it occasionally referred to as static duck typing (although I personally think that describes structural typing better).

The idea is to be able to extend an existing class with new methods in a type safe manner. Essentially what happens is a developer defines an implicit method (or imports an implicit method) which converts one object from one type to another type. Once the implicit method is within scope all methods are available from both types.

Note: The conversion is one way. If you want bi-directional conversion you need 2 methods.
  1. scala>class MyInteger( i:Int ) {
  2.      | def myNewMethod = println("hello from myNewMethod")
  3.      | }
  4. defined class MyInteger
  5. // an integer is not a "MyInteger" so you cannot call the myNewMethod on it
  6. scala> 1.myNewMethod
  7. :5: error: value myNewMethod is not a member of Int
  8.        1.myNewMethod
  9.          ^
  10. // define an implicit conversion and now we can call all MyInteger methods on integers
  11. scala> implicit def int2MyInt( i:Int ) = new MyInteger(i)
  12. int2MyInt: (Int)MyInteger
  13. scala> 1.myNewMethod
  14. hello from myNewMethod
  15. scala>class MyInteger2( val i:Int ) {
  16.      | def inc = new MyInteger2( i+1 )
  17.      | }
  18. defined class MyInteger2
  19. // you can define several implicits in an object and import later
  20. scala>object Conversions{
  21.      | implicit def int2MyInt2(i:Int) = new MyInteger2(i)
  22.      | implicit def myInt2Int( mI:MyInteger2) = mI.i
  23.      | }
  24. defined module Conversions
  25. // you can import all implicits    or just    one (although interpreter only allows all for some reason)
  26. scala>import Conversions._
  27. import Conversions._
  28. // inc returns a MyInteger2 instance
  29. scala>val j = 1.inc
  30. j: MyInteger2 = MyInteger2@37f808e6
  31. // test    the bi-directionality of it all    so create a method
  32. // that takes and int
  33. scala>def takesInt( i:Int ) = println(i)
  34. takesInt: (Int)Unit
  35. // j is a MyInteger2 but thanks to the implicit it can be converted back to an int
  36. scala> takesInt( j )
  37. 2
  38. scala> takesInt ( 5.inc )
  39. 6

Imports

Scala's mechanism for importing is analogous to Java's import statements but provides more options. For example import statements can be anywhere in the file and only apply to the scope that they are declared in.
  1. scala>def lineCount = {                                                              
  2.      | import scala.io._ // the '_' character is the wildcard in scala                
  3.      | Source.fromURL("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )
  4.      | }
  5. lineCount: Int
  6. scala> lineCount                                                                             
  7. res1: Int = 11
  8. scala>def lineCount = {                                                               
  9.      | import scala.io.Source                                                          
  10.      |  Source.fromURL("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )
  11.      | }
  12. lineCount: Int
  13. scala> lineCount
  14. res3: Int = 11
  15. scala>def lineCount = {                                                                                      
  16.      | import scala.io.Source.fromURL // import the fromURL method, only methods from objects can be imported.
  17.      | fromURL("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )                       
  18.      | }
  19. lineCount: Int
  20. scala> lineCount
  21. res4: Int = 11
  22. scala>def lineCount = {                                                                                      
  23.      | import scala.io.Source.{fromURL => url} // you can remap imports to another name                       
  24.      | url("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )    
  25.      | }
  26. lineCount: Int
  27. scala> lineCount                                                                       
  28. res5: Int = 11
  29. scala>import java.io.{File, FileWriter} // you can import multiple classes in one statement
  30. import java.io.{File, FileWriter}
  31. scala> println( classOf[File], classOf[FileWriter])
  32. (class java.io.File,class java.io.FileWriter)
Subscribe to: Comments (Atom)

AltStyle によって変換されたページ (->オリジナル) /