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:
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:
- /*
- The File class is aliased to _ (oblivion) and then everything is imported (except File since it does not exist in that scope)
- Note: File can be imported later
- */
- scala> import java.io.{File=>_,_}
- import java.io.{File=>_, _}
- scala> new File("it is a file")
- < console>:8: error: not found: type File
- new File("it is a file")
- scala> object O {
- | def one = 1
- | def two = 2
- | def o = 0
- | }
- defined module O
- /*
- Same tricks can apply to importing methods and fields from objects
- */
- scala> import O.{o=>_, _}
- import O.{o=>_, _}
- scala> one
- res2: Int = 1
- scala> two
- res3: Int = 2
- scala> o
- < console>:15: error: not found: value o
- o
- // Once a class is imported into scope it can not be removed
- scala> import java.io.File
- import java.io.File
- scala> import java.io.{File=>_}
- import java.io.{File=>_}
- /*
- this still works because the previous import statement only adds an alias it does not remove the alias
- */
- scala> new File("..")
- res6: java.io.File = ..
- // There can be multiple aliases in a scope
- scala> import java.io.{File=>jfile}
- import java.io.{File=>jfile}
- scala> new jfile("..")
- res0: java.io.File = ..
- // one more example of importing from objects
- scala> case class X(a:Int, b:Int, c:Int)
- defined class X
- scala> val x = new X(1,2,3)
- x: X = X(1,2,3)
- scala> import x.{a=>_,b=>_,_}
- import x.{a=>_, b=>_, _}
- scala> c
- res1: Int = 3
- scala> b
- < console>:14: error: not found: value b
- b
- ^
Labels:
import,
import alias,
intermediate,
Scala
Wednesday, December 2, 2009
What the @*!% is with the '_'
- scala> import java.io._ // 1
- import java.io._
- scala> import java.io.{ File => _ } // 2
- import java.io.{File=>_}
- scala> object MyObj{ def count=(1 to 10) }
- defined module MyObj
- scala> import MyObj._ // 3
- import MyObj._
- scala> class MyClass { def countDown= 10 to 5 by -1}
- defined class MyClass
- scala> val instance = new MyClass()
- instance: MyClass = MyClass@69ebcd0
- scala> import instance._ // 4
- import instance._
- scala> def multiply(by:Int,x:Int)=2*x
- multiply: (Int,Int)Int
- scala> val double=multiply(2, _:Int) // 5
- double: (Int) => Int
- scala> count foreach {i => double(i)}
- scala> val double2:Int=>Int = multiply(2,_)
- double2: (Int) => Int = & function>
- scala> count foreach {i => double2(i)}
- scala> count reduceLeft {_+_} // 6
- res3: Int = 55
- class Generic[T](val t:T)
- 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:
- import anything/everything in package
- this seems to be an exception. Assign File to oblivion. (It is no longer imported)
- import all methods in object
- same thing. Import all methods in instance object
- 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
- 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. - 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]
Labels:
import,
Scala,
underscore
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.
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:
But we can do better remember that we can import methods and properties from an object:
Since all instance are objects it is possible to import fields and methods from instances as well:
The same technique is extremely useful when a method needs to return multiple values:
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.
- scala> case class Params(p1:Int, p2:Int, p3:Int)
- defined class Params
- scala> def method(params:Params) = {
- | println(params.p1, params.p2, params.p3)
- | }
- method: (Params)Unit
- scala> method(Params(1,2,3))
- (1,2,3)
- }
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:
- scala> case class Params(p1:Int, p2:Int, p3:Int)
- defined class Params
- scala>
- scala> def method(params:Params) = {
- | val Params(p1,p2,p3) = params
- | println(p1,p2,p3)
- | }
- method: (Params)Unit
- scala> method(Params(1,2,3))
- (1,2,3)
- }
But we can do better remember that we can import methods and properties from an object:
- scala> object Obj {
- | val prop = 10
- | }
- defined module Obj
- scala> import Obj._
- import Obj._
- scala> println(prop)
- 10
Since all instance are objects it is possible to import fields and methods from instances as well:
- scala> case class Params(p1:Int, p2:Int, p3:Int)
- defined class Params
- scala>
- scala> def method(params:Params) = {
- | import params._
- | println(p1, p2, p3)
- | }
- method: (Params)Unit
- }
The same technique is extremely useful when a method needs to return multiple values:
- scala> def method() = {
- | (1,2,3)
- | }
- method: ()(Int, Int, Int)
- scala> val retVal = method()
- retVal: (Int, Int, Int) = (1,2,3)
- /*
- retVal is a tuple so we can import the tuple
- properties. Becareful to not do this multiple times in
- the same scope
- */
- scala> import retVal._
- import retVal._
- scala> println(_1,_2,_3)
- (1,2,3)
- scala> def method2={
- // Notice case class declaration can be contained in method
- | case class Return(v1:Int,v2:Int)
- | Return(6,7)
- | }
- method2: java.lang.Object with ScalaObject with Product{def v1: Int; def v2: Int}
- scala> val r = method2
- r: java.lang.Object with ScalaObject with Product{def v1: Int; def v2: Int} = Return(6,7)
- scala> import r._
- import r._
- scala> println(v1,v2)
- (6,7)
- }
Labels:
assignment,
case-classes,
import,
intermediate,
return,
Scala
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:
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:
- scala> trait T1 {
- | def talk = "hi"
- | }
- defined trait T1
- scala> trait T2 {
- | def talk = "hello"
- | }
- defined trait T2
- // Cannot extend C with T1 and T2 because they are not designed to work together
- scala> class C extends T1 with T2
:6: error: error overriding method talk in trait T1 of type => java.lang.String; - method talk in trait T2 of type => java.lang.String needs override modifier
- class C extends T1 with T2
- ^
- scala> class C extends T1
- defined class C
- // objects can have state so becareful how you share them
- scala> object Obj1 extends T1
- defined module Obj1
- scala> object Obj2 extends T2
- defined module Obj2
- // You can give aliases to the imported methods and use them in the class
- scala> class C {
- | import Obj1.{talk => hi}
- | import Obj2.{talk => hello}
- | def sayHi = hi
- | def sayHello = hello
- | }
- defined class C
- scala> val c = new C
- c: C = C@54d8fd1a
- scala> c.sayHi
- res0: java.lang.String = hi
- scala> c.sayHello
- res1: java.lang.String = hello
- scala> class C extends T1 {
- | import Obj2.{talk => hello}
- | def helloTalk = hello
- | }
- defined class C
- scala> val c2 = new C
- c2: C = C@2ee634bf
- scala> c2.talk
- res2: java.lang.String = hi
- scala> c2.helloTalk
- res5: java.lang.String = hello
Labels:
import,
import alias,
object,
Scala,
traits
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:
And in 2.8:
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:
- scala> val jmap = new java.util.HashMap[String,Int]()
- jmap: java.util.HashMap[String,Int] = {}
- scala> jmap.put("one", 2)
- res0: Int = 0
- scala> jmap.get("one")
- res1: Int = 2
- scala> import scala.collection.jcl.Conversions._
- import scala.collection.jcl.Conversions._
- scala> jmap("one")
- res3: Int = 2
- scala> jmap("one") = 1
- scala> jmap("one")
- res5: Int = 1
And in 2.8:
- scala> val jmap = new java.util.HashMap[String,Int]()
- jmap: java.util.HashMap[String,Int] = {}
- scala> jmap.put("one", 2)
- res0: Int = 0
- scala> jmap.get("one")
- res1: Int = 2
- scala> import scala.collection.JavaConversions._
- import scala.collection.JavaConversions._
- scala> jmap("one")
- res3: Int = 2
- scala> jmap("one") = 1
- scala> jmap("one")
- res5: Int = 1
Labels:
beginner,
collections,
conversion,
implicit,
import,
java,
Scala
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.
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.
- scala> class MyInteger( i:Int ) {
- | def myNewMethod = println("hello from myNewMethod")
- | }
- defined class MyInteger
- // an integer is not a "MyInteger" so you cannot call the myNewMethod on it
- scala> 1.myNewMethod
:5: error: value myNewMethod is not a member of Int - 1.myNewMethod
- ^
- // define an implicit conversion and now we can call all MyInteger methods on integers
- scala> implicit def int2MyInt( i:Int ) = new MyInteger(i)
- int2MyInt: (Int)MyInteger
- scala> 1.myNewMethod
- hello from myNewMethod
- scala> class MyInteger2( val i:Int ) {
- | def inc = new MyInteger2( i+1 )
- | }
- defined class MyInteger2
- // you can define several implicits in an object and import later
- scala> object Conversions{
- | implicit def int2MyInt2(i:Int) = new MyInteger2(i)
- | implicit def myInt2Int( mI:MyInteger2) = mI.i
- | }
- defined module Conversions
- // you can import all implicits or just one (although interpreter only allows all for some reason)
- scala> import Conversions._
- import Conversions._
- // inc returns a MyInteger2 instance
- scala> val j = 1.inc
- j: MyInteger2 = MyInteger2@37f808e6
- // test the bi-directionality of it all so create a method
- // that takes and int
- scala> def takesInt( i:Int ) = println(i)
- takesInt: (Int)Unit
- // j is a MyInteger2 but thanks to the implicit it can be converted back to an int
- scala> takesInt( j )
- 2
- scala> takesInt ( 5.inc )
- 6
Labels:
implicit,
import,
intermediate,
object,
Scala
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.
- scala> def lineCount = {
- | import scala.io._ // the '_' character is the wildcard in scala
- | Source.fromURL("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )
- | }
- lineCount: Int
- scala> lineCount
- res1: Int = 11
- scala> def lineCount = {
- | import scala.io.Source
- | Source.fromURL("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )
- | }
- lineCount: Int
- scala> lineCount
- res3: Int = 11
- scala> def lineCount = {
- | import scala.io.Source.fromURL // import the fromURL method, only methods from objects can be imported.
- | fromURL("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )
- | }
- lineCount: Int
- scala> lineCount
- res4: Int = 11
- scala> def lineCount = {
- | import scala.io.Source.{fromURL => url} // you can remap imports to another name
- | url("http://www.google.com").getLines.foldRight(0)( (line, acc) => acc + 1 )
- | }
- lineCount: Int
- scala> lineCount
- res5: Int = 11
- scala> import java.io.{File, FileWriter} // you can import multiple classes in one statement
- import java.io.{File, FileWriter}
- scala> println( classOf[File], classOf[FileWriter])
- (class java.io.File,class java.io.FileWriter)
Subscribe to:
Comments (Atom)