Showing posts with label assignment. Show all posts
Showing posts with label assignment. Show all posts
Monday, March 22, 2010
Implicit '=' operator
Continuing on with operators, There is a special type of operator in Scala. It is an operator that ends with =. If a class has operation (methods with an operator identifer) the = can be appended to the effectively creating a new method. In truth a new method is not created instead the compiler rewrites the line.
For example. If a method (like Int) defines + then a method call += can be used. It can be used to mutate a variable:
To illustrate this is not a special case for Int the next example defines several operations and demonstrates in place variable mutation.
Here are several more examples using existing classes in Scala. They are all immutable examples.
Note: assignment operators can also be defined as methods to mutate an object
For example. If a method (like Int) defines + then a method call += can be used. It can be used to mutate a variable:
- scala> var i = 1
- i: Int = 1
- scala> i += 1
- scala> i
- res3: Int = 2
To illustrate this is not a special case for Int the next example defines several operations and demonstrates in place variable mutation.
- scala> case class MyClass(i:Int) {
- | def +(j:Int) = new MyClass(j + i)
- | def -(j:Int) = new MyClass(i - j)
- | def ^(j:Int) = MyClass(j)
- | def +|(j:Int) = new MyClass(j + i / 3)
- | }
- defined class MyClass
- scala> var c = MyClass(1)
- c: MyClass = MyClass(1)
- scala> c+=6
- scala> c
- res5: MyClass = MyClass(7)
- scala> c -= 2
- scala> c
- res7: MyClass = MyClass(5)
- scala> c ^= 10
- scala> c
- res23: MyClass = MyClass(10)
- scala> c +|= 5
- scala> c
- res25: MyClass = MyClass(8)
Here are several more examples using existing classes in Scala. They are all immutable examples.
- scala> var l = Set(1,2,3)
- l: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
- scala> l += 10
- scala> l
- res7: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 10)
- scala> var seq = Seq(5,6,3)
- seq: Seq[Int] = List(5, 6, 3)
- scala> seq :+= 10
- scala> seq
- res9: Seq[Int] = List(5, 6, 3, 10)
- scala> seq +:= 10
- scala> seq
- res11: Seq[Int] = List(10, 5, 6, 3, 10)
- scala> var list = List(32)
- list: List[Int] = List(32)
- scala> list ::= 12
- scala> list
- res13: List[Int] = List(12, 32)
Note: assignment operators can also be defined as methods to mutate an object
- scala> case class MyClass(var i:Int) {
- | def += (j:Int) = { i+=j ; this }
- | }
- defined class MyClass
- scala> val m = MyClass(6)
- m: MyClass = MyClass(6)
- scala> m += 7
- res0: MyClass = MyClass(13)
- scala> m += 9
- res1: MyClass = MyClass(22)
- scala> res1 eq m
- res2: Boolean = true
Labels:
assignment,
intermediate,
operator,
Scala
Friday, March 19, 2010
Operators
Since Scala allows one to define the behavior of operators there are some rules involving operators and assignment like +=. One of the standard method calls in most languages is
Since
These characters can be method names but they cannot be combined with other identifier characters.
Update: These characters can be combined with other identifier characters if there is an under score so:
However these characters are special because they can be combined in a special way with '=' for a special assignment construct as shown in the next post.
(end update)
i += 1.
Since
i+=1
(no spaces) is also valid, Scala has some rules regarding how statements like i+=1
should be broken up. Obviously we know it should be 'i' '+=' and '1'. So there is a special class of characters called operators. I don't know all of them but a few are: + - ^ * / % ! | & =
( ':' is sort of part of this group but has some special properties as well). These characters can be method names but they cannot be combined with other identifier characters.
Update: These characters can be combined with other identifier characters if there is an under score so:
- def x+ = 3 // not valid
- def x_+ = 3 // valid
- def +x = 3 // not valid
However these characters are special because they can be combined in a special way with '=' for a special assignment construct as shown in the next post.
(end update)
- scala> case class MyClass(i:Int) {
- | def +(j:Int) = new MyClass(j + i)
- | def -(j:Int) = new MyClass(i - j)
- | def ^(j:Int) = MyClass(j)
- | def +|(j:Int) = new MyClass(j + i / 3)
- | }
-
- scala> val c = MyClass(3)
- c: MyClass = MyClass(3)
- scala> c + 4
- res26: MyClass = MyClass(7)
- scala> c-2
- res27: MyClass = MyClass(1)
- scala> c -6
- res28: MyClass = MyClass(-3)
- scala> c ^ 3
- res29: MyClass = MyClass(3)
- scala> c+|5
- res31: MyClass = MyClass(6)
Labels:
assignment,
beginner,
operator,
Scala
Monday, February 1, 2010
Temporary variables during object instantiation
In Java a common pattern with class constructors is to assign field values and often there are several intermediate values used for the calculation. If the code is ported to Scala the resulting class will have the intermediate values as fields, which take up space in the object. However the issue is easily worked around. Lets look at a couple examples.
Example 1: Assigning a single field
In Scala the naive way to port this would be:
Problem is that it has an extra field "file" now. The correct way to port this would be as follows:
Example 2: Assigning multiple fields
The Scala port:
In some ways the Scala port is cleaner in that it splits the constructor up and decouples the dependencies between fields.
Example 1: Assigning a single field
- // Java
- import java.io.File
- /**
- No real logic behind class. But for some reason it needs the path of a tmp directory in the working directory
- */
- class OneAssignment {
- final String field;
- public OneAssignment() {
- File file = new File("tmp");
- if(!file.exists()) {
- file.mkdirs();
- }
- field = file.getAbsolutePath();
- }
- }
In Scala the naive way to port this would be:
- // Scala
- import java.io.File
- class OneAssignment {
- val file = new File("tmp")
- if(!file.exists()) {
- file.mkdirs()
- }
- val field = file.getAbsolutePath()
- }
Problem is that it has an extra field "file" now. The correct way to port this would be as follows:
- // Scala
- import java.io.File
- class OneAssignment {
- /*
- notice that assignment is in a block so file is only visible within the block
- */
- val field = {
- val file = new File("tmp")
- if(!file.exists()) {
- file.mkdirs()
- }
- file.getAbsolutePath()
- }
- }
Example 2: Assigning multiple fields
- // Java
- import java.io.File
- /**
- Basically the same as last example but multiple fields are assigned
- Notice that 2 fields depend on the temporary file variable but count does not
- */
- class MultipleAssignments {
- final String tmp,mvn_repo;
- find int count;
- public OneAssignment() {
- File file = new File("tmp");
- if(!file.exists()) {
- file.mkdirs();
- }
- tmp = file.getAbsolutePath();
- count = file.listFiles.length;
-
- File home = new File(System.getProperty("user.home"));
- mvn_repo = new File(home, ".m2").getPath();
- }
- }
The Scala port:
- // Scala
- import java.io.File
- class MultipleAssignments {
- /*
- When multiple fields depend on the same temporary variables the fields can be assigned together from one block by returning a tuple and using Scala's matching to expand the tuple during assignment. See previous topics on assignment for details
- */
- val (tmp,count) = {
- val file = new File("tmp");
- if(!file.exists()) {
- file.mkdirs();
- }
- val tmp = file.getAbsolutePath();
- val count = file.listFiles.length;
- (tmp, count)
- }
- val mvn_repo = {
- val home = new File(System.getProperty("user.home"));
- new File(home, ".m2").getPath();
- }
- }
In some ways the Scala port is cleaner in that it splits the constructor up and decouples the dependencies between fields.
Labels:
assignment,
constructor,
intermediate,
Scala
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
Thursday, September 10, 2009
Assignments
Assignment in Scala follows more or less the same rules as Java and other related rules. There are some differences.
Increment operators do not work (
Assignments do not return a value. For example you cannot do
One feature that is fairly unique in Scala is the ability to expand a case-class or other class that has an associated extractor. For details look at the previous topic Assignment and Parameter Objects.
Examples:
Increment operators do not work (
i++
). As I understand it the rational is that it is too specific an idiom. There is not an easy way to generalize it. Instead you must use i += 1
.Assignments do not return a value. For example you cannot do
val i = j = 2
or while( (i = read(buffer)) > 0 ){...}
.One feature that is fairly unique in Scala is the ability to expand a case-class or other class that has an associated extractor. For details look at the previous topic Assignment and Parameter Objects.
Examples:
- scala> val i,j=2
- i: Int = 2
- j: Int = 2
- scala> val (i,j) = (1,2)
- i: Int = 1
- j: Int = 2
- scala> val (i,j,k) = (1,"two",3.0)
- i: Int = 1
- j: java.lang.String = two
- k: Double = 3.0
- scala> case class Data( name:String, age:Int, weight:Float)
- defined class Data
- scala> val Data(name, age, weight) = Data("Jesse", 133, 100f)
- name: String = Jesse
- age: Int = 133
- weight: Float = 100.0
- scala> val value = 1
- value: Int = 1
- scala> i += 1
:10: error: reassignment to val - i += 1
- ^
- scala> var variable = 1
- variable: Int = 1
- scala> variable += 1
- scala> println(variable)
- 2
Labels:
assignment,
beginner,
case-classes,
java,
Scala,
tuple
Sunday, August 16, 2009
Assignment and Parameter Objects
One of the principle design goals of Scala is to be "deep" not wide, which means the language attempts to have a small set of rules that can be applied in many different ways in different situations. Pattern matching is one of my favourite examples of this. Pattern matching is commonly seen in match { case... } statements but you will also see it frequently in exception handling, function declaration and, most important for this post, assignment.
Scala does not have multiple assignment like some languages. Instead it has tuples and matching. Tuples are a light-weight way of grouping data in a simple data object.
This is pattern matching.
Notice that in both cases you need the brackets around firstname, lastname. This instructs the compiler that you are matching against a Tuple.
Now the interesting use is with parameter objects. Tuples are a poor substitute for parameter objects because they do not have context. Changing:
to
Is not a good change because you loose context. What are the 3 strings? The information must go in the Javadocs. A better option:
The beauty is that you have an object that you can pass around easily. It is a case class therefore extracting the information is incredibly easy and unlike a tuple it has context and can have methods added easily.
Yes it is longer to write but if you need to reuse the data in several locations the trade off is well worth it in clarity.
Examples:
Scala does not have multiple assignment like some languages. Instead it has tuples and matching. Tuples are a light-weight way of grouping data in a simple data object.
(1,2.0,'c',"string", true)
. A simple example of a 5 element tuple. Tuples can be up to 22 elements long and can be homogenous or heterogenous. Using this for multiple assignement works something like:- val (firstname, lastname) = ("Jesse","Eichar")
This is pattern matching.
- scala> ("Jesse","Eichar") match {
- | case (firstname,lastname) => println(firstname,lastname)
- | }
- (Jesse,Eichar)
Notice that in both cases you need the brackets around firstname, lastname. This instructs the compiler that you are matching against a Tuple.
Now the interesting use is with parameter objects. Tuples are a poor substitute for parameter objects because they do not have context. Changing:
- def myMethod( firstname:String, middlename:String, lastname:String) = {...}
to
- def myMethod( name:(String,String,String)) = {...}
Is not a good change because you loose context. What are the 3 strings? The information must go in the Javadocs. A better option:
- case class Name(first:String, middle:String, last:String)
- def myMethod( name:Name ) = {
- val Name(first, middle, last) = name
- // do something with first middle last
- }
The beauty is that you have an object that you can pass around easily. It is a case class therefore extracting the information is incredibly easy and unlike a tuple it has context and can have methods added easily.
Yes it is longer to write but if you need to reuse the data in several locations the trade off is well worth it in clarity.
Examples:
- // define name data object.
- // Notice toString is a lazy val. This means value is calculated only once.
- scala> case class Name(first:String, middle:String, last:String) {
- | override lazy val toString="%s, %s %s" format (last, first,middle)
- | }
- defined class Name
- // toString formats name nicely.
- scala> Name("Jesse","Dale","Eichar")
- res1: Name = Eichar, Jesse Dale
- scala> def readName() = {
- | //maybe load from a file or database
- | Name("Jesse","Dale","Eichar") :: Name("Jody","","Garnett") :: Name("Andrea","","Antonello"):: Nil
- | }
- readName: ()List[Name]
- scala> def firstLastName(name:Name) = {
- | // we are putting _ because we don't care about middle name
- | val Name( first, _, last ) = name
- | (first, last)
- | }
- firstLastName: (Name)(String, String)
- // convert the list of Names to a list of tuples of first and last name
- scala> readName().map( firstLastName _ )
- res2: List[(String, String)] = List((Jesse,Eichar), (Jody,Garnett), (Andrea,Antonello))
- // print all first names starting with J
- scala> for( Name(first,_,_) <- readname; if (first.startsWith("J"))) println(first)
- Jesse
- Jody
- // print the first and middle parts of the first name in the list
- scala> readName() match {
- | // the :: _ indicates that we are matching against a list but we don't care about the rest of the list
- | case Name(f,m,_) :: _ => println( f, m)
- | case _ => println("Not a list of names")
- | }
- (Jesse,Dale)
Labels:
assignment,
case-classes,
data object,
intermediate,
matching,
Scala,
tuple
Thursday, August 6, 2009
Simple classes
Scala classes are similar to java classes but are designed to work around some of the boiler plate code. We will address multiple constructors another day. But one thing to note is that normally the code that is in a Java constructor goes directly in the body of a Scala class or in a companion object (also covered later).
- scala> class NewClass( aPrivateInt:Int, val iAmPublic:Int, var iAmAlsoPublic:Int)
- defined class NewClass
- scala> val c = new NewClass(1,2,3)
- c: NewClass = NewClass@da99836
- scala> c.aPrivateInt
:7: error: value aPrivateInt is not a member of NewClass - c.aPrivateInt
- ^
- scala> c.iAmPublic
- res2: Int = 2
- scala> c.iAmAlsoPublic
- res3: Int = 3
- scala> c.iAmPublic = 10 // not allowed because iAmPublic is a val
:6: error: reassignment to val - c.iAmPublic = 10
- ^
- scala> c.iAmAlsoPublic = 10 // iAmAlsoPublic is a var
- scala> c.iAmAlsoPublic
- res4: Int = 10
- scala> class c2( aPrivate:Int ) {
- | val aPublic = aPrivate + 10
- | }
- defined class c2
- scala> class c3(tmp:Int) extends c2(tmp){
- | override val aPublic = tmp * 10 // can't access super.aPrivate because it
- is class private so use tmp
- | }
- defined class c3
- scala> new c2(10).aPublic
- res5: Int = 20
- scala> new c3(10).aPublic
- res6: Int = 100
- scala> class c4( aPrivate:Int ) {
- | println(aPrivate)
- | private val private2 = aPrivate % 10
- | println(private2)
- | }
- defined class c4
- scala> new c4(22)
- 22
- 2
- res7: c4 = c4@64d90254
Labels:
assignment,
beginner,
classes,
Scala
Subscribe to:
Posts (Atom)