페이지

레이블이 Scala인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Scala인 게시물을 표시합니다. 모든 게시물 표시

2015년 11월 10일 화요일

Scala2e Chapter5 Basic Types and Operations 5.9 Rich wrappers



These methods are available via implicit conversions, a technique that will be described in detail in Chapter21.

Scala2e Chapter5 Basic Types and Operations 5.8 Operator precedence and associativity

Operator precedence determines which parts of an expression are evaluated before the other parts.

show the precedence given to the first character of a method in decreasing order of precedence, with characters on the same line having the same precedence.
The higher a character is in this table, the higher the precedence of methods that start with that start with that character.

Any method that ends in a ':' character is invoked on its right operand, passing in the left operand.
Methods that end in any other character are the other way around.
They are invoked on their left operand, passing in the right operand.
So a * b yields a.*(b), but a ::: b yields b. :::(a).

2015년 11월 4일 수요일

Scala2e Chapter5 Basic Types and Operations 5.7 Object equality

If you want to compare two objects for equality, you can use either ==, or its inverse !=.

scala> 1 == 2
res31: Boolean = false
scala> 1 != 2
res32: Boolean = true
scala> 2 == 2
res33: Boolean = true

scala> List(1, 2, 3) == List(1, 2, 3)
res34: Boolean = true
scala> List(1, 2, 3) == List(4, 5, 6)
res35: Boolean = false

scala> 1 == 1.0
res36: Boolean = true
scala> List(1, 2, 3) == "hello"
res37: Boolean = false

scala> List(1, 2, 3) == null
res38: Boolean = false
scala> null == List(1, 2, 3)
res39: Boolean = false

This kind of comarison will yield true on different objects, so long as their contents are the same and their equals method is written to be based on contents.

scala> ("he"+"llo") == "hello"
res40: Boolean = true

In Java, you can use == to compare both primitive and reference types.
On primitive types, Java's == compares value equality, as in Scala. 
On reference types, however, Java's == compares reference equality, which means the two variables point to the same object on the JVM's heap.
Scala provides a facility for comparing reference equality, as well, under the name eq. However, eq and its opposite, ne, only apply to objects that directly map to Java objects.



Scala2e Chapter5 Basic Types and Operations 5.6 Bitwise operations

Scala enables you to perform operations on individual bits of integer types with several bitwise methods.

bitwise-and(&), bitwise-or(|), bitwise-xor(^), unary_~

scala> 1 & 2
res24: Int = 0
scala> 1 | 2
res25: Int = 3
scala> 1 ˆ 3
res26: Int = 2
scala> ~1
res27: Int = 2

The first expression, 1 & 2, bitwise-ands each bit in 1 (0001) and 2 (0010), which yiedls 0(0000).
The second expression, 1 | 2, bitwise-ors each ibt in the same operands, yielding 3(0011).
The third expression, 1 ^ 3, bitwise-xors each bit in 1(0001) and 3(0011), yielding 2(0010).
The final expressiion, ~1, inverts each bit in 1 (0001), yielding -2, which in binary looks like 11111111111111111111111111111110.

Scala integer type also offer three shift methods: shift left(<<), shift right(>>), and unsigned shift right(>>>).

scala> 1
>> 31
res28: Int = 1
scala> 1
>>> 31
res29: Int = 1
scala> 1 << 2
res30: Int = 4

-1 in binary is 11111111111111111111111111111111. In the first example,-1 >> 31, -1 is shifted to the right 31 bit positions.
Since an Int consisits of 32 bits, this operation effectively moves the leftmost bit over until it becomes the rightmost bit.
Since the >> method fills with ones as it shifts right, because the leftmost bit of -1 is 1, the result is identical to the original left operand, 32 one its, or -1.

In the second example, -1>>> 31, the leftmost bit is again shifted right until it is in the rightmost position, but this time filling with zeroes along the way. Thus the result this time is binary 00000000000000000000000000000001, or 1. In the final example, 1 << 2,
the left operand, 1, is shifted left two positions (filling in with zeroes), resulting in binary 00000000000000000000000000000100, or 4.




2015년 11월 3일 화요일

Scala2e Chapter5 Basic Types and Operations 5.5 Relational and logical operations

You can compare numeric types with relational methods greater than (>), less than (<), greater than or equal to (>=), and less than or equal to (<=), which yield a Boolean result. In addition, you can use the unary '!' operator(the unary_! method)

The logical-and and logical-or operations are short-circuited as in Java: expressions built from these operators are only evaluated as far as needed to determine the result.
In other words, the right-hand side of logical-and and logical-or expressions won't be evaluated if the left-hand side determines the result.


In the first expression, pepper and salt are invoked, but in the second, only salt is invoked. Given salt returns false, there's no need to call pepper.

Scala methods have a facility for delaying the evaluation of their arguments, or even declining to evaluate them at all.
The facility is call by-name parameters.


Scala2e Chapter5 Basic Types and Operations 5.4 Arithmetic operations


scala> 1.2 + 2.3
res6: Double = 3.5
scala> 3 1
res7: Int = 2
scala> 'b' '
a'
res8: Int = 1
scala> 2L * 3L
res9: Long = 6
scala> 11 / 4
res10: Int = 2
scala> 11 % 4
res11: Int = 3
scala> 11.0f / 4.0f
res12: Float = 2.75
scala> 11.0 % 4.0
res13: Double = 3.0

When both the left and right operands are integral types (Int, Long, Byte, Short, or Char), the / operator will tell you the whole number portion of the quotient, excluding any remainder. The % operator indicates the remainder of an implied integer division.






Scala2e Chapter5 Basic Types and Operations 5.3 Operators are methods

Scala provides a rich set of operators for its basic types.

class Int Contains a method named + that takes an Int and returns an Int result.

scala> val sum = 1 + 2 // Scala invokes (1).+(2)
sum: Int = 3

scala> val sumMore = (1).+(2)
sumMore: Int = 3

You call a method that takes multiple arguments using operator notation, you have to place those arguments in parentheses.

scala> val s = "Hello, world!"
s: java.lang.String = Hello, world!
scala> s indexOf 'o' // Scala invokes s.indexOf(’o’)
res0: Int = 4

scala> s indexOf ('o', 5) // Scala invokes s.indexOf(’o’, 5)
res1: Int = 8

Any method can be an operator
In Scala operators are not special language syntax: any method can be an operator. What makes a method an operator is how you use it. When you write "s.indexOf('o'), indexOf is not an operator. But when you write "s indexOf 'o', indexOf is an operator, because you're using it in operator notation.

Scala also has two other operator notations: prefix and postfix.
In prefix notation, you put the method name before the object on which you are invoking the method, for example, the '-' in -7. In postfix notation, you put the method after the object, for example, the "toLong" in "7 toLong".

In contrast to the infix operator notation = in which operatior take two operands. on th the left and the other to the right - prefix and postfix operators are unary: they take just on operand. In prefix notation, the operand is to the right of the operator. Some examples of prefix operators are -2.0, ! found, and ~0xFF.

scala> -2.0          // Scala invokes (2.0).unary_-
res2: Double = -2.0
scala> (2.0).unary_-
res3: Double = -2.0

The only identifiers that can be used as prefix operators are +, -, !, and ~.
Thus, if you define a method anmed unary_!, you could invoke that method on a value or variable of the appropriate type useing prefix operator notation, such as !p.

Postfix operators are methods that take no arguments, when they are invoked without a dot or parentheses. In Scala, you can leave off empty parentheses on method calls. The convention is that you include parentheses if the method has side effects, such as println(), but you can leave them off if the method has no side effects. such as toLowerCase invoked on a String:

scala> val s = "Hello, world!"
s: java.lang.String = Hello, world!
scala> s.toLowerCase
res4: java.lang.String = hello, world!

scala> s toLowerCase
res5: java.lang.String = hello, world!

Scala2e Chapter5 Basic Types and Operations 5.2 Literals

All of the basic types can be written with literals. A literal is a way to write a constant value directly in code.

- Integer literals
Int, Long, Short, Byte
forms: decimal, hexadecimal, octal

scala> val hex = 0x5
hex: Int = 5
scala> val hex2 = 0x00FF
hex2: Int = 255
scala> val magic = 0xcafebabe
magic: Int = -889275714

scala> val oct = 035  // (35 octal is 29 decimal)
oct: Int = 29
scala> val nov = 0777
nov: Int = 511
scala> val dec = 0321
dec: Int = 209

scala> val dec1 = 31
dec1: Int = 31
scala> val dec2 = 255
dec2: Int = 255
scala> val dec3 = 20
dec3: Int = 20
scala> val prog = 0XCAFEBABEL
prog: Long = 3405691582
scala> val tower = 35L
tower: Long = 35
scala> val of = 31l
of: Long = 31

- Floating point literals

Floating point literals are made up of decimal digits, optionally containing a decimal point, and optionally followed by an E or e and an exponent.

If a floating-point literal ends in an F or f, it is a Float, otherwise it is a Double.
Optionally, a Double floating-point literal can end in D or d.

scala> val big = 1.2345
big: Double = 1.2345
scala> val bigger = 1.2345e1
bigger: Double = 12.345
scala> val biggerStill = 123E45
biggerStill: Double = 1.23E47
scala> val little = 1.2345F
little: Float = 1.2345
scala> val littleBigger = 3e5f
littleBigger: Float = 300000.0
scala> val anotherDouble = 3e5
anotherDouble: Double = 300000.0
scala> val yetAnother = 3e5D
yetAnother: Double = 300000.0

- Character literals
Character literals are composed of any Unicode character between single quotes, such as:

scala> val a = 'A'
a: Char = A

The octal number must be between '\0' and '\377'.

A character literal can also be given as a general Unicode character consisting
of four hex digits and preceded by a \u.


scala> val c = '\101'
c: Char = A

scala> val d = '\u0041'
d: Char = A

scala> val f = '\u0044'
f: Char = D



In fact, such Unicode characters can appear anywhere in a Scala program.

scala> val B\u0041\u0044 = 1
BAD: Int = 1

scala> val backslash = '\\'
backslash: Char = \


- String literals
A string literal is composed of characters surrounded by double quotes

Scala includes a special syntax for raw strings. You start and end a raw string with three double quotation marks in a row(""").

println("""Welcome to Ultamix 3000.
Type "HELP" for help.""")


Welcome to Ultamix 3000.
                 Type "HELP" for help.

The isssue is that the leading spaces before the second line are included in the string!.
To help with this common situation, you can call stripMargin on strings.
To use this method, put a pipe character(|) at the front of each line, and then call stripMargin on the whole string

println("""|Welcome to Ultamix 3000.
|Type "HELP" for help.""".stripMargin)


Welcome to Ultamix 3000.
Type "HELP" for help.


- Symbol literals
A symbol lilteral is written 'ident, where ident can be any alphanumeric identifier.
Symbol literals are typically used in situations where you would use just an identifier in a dynamically typed language. For instance, you might want to define a method that updates a record in a database;

scala> def updateRecordByName(r: Symbol, value: Any){
//code goes here
}
updateRecordByName: (Symbol, Any)Unit

The method takes as parameters a symbol indicating the name of a record field and a value with which the field should b updated in the record.
In a dynamically typed language, you could invoke this operation passing an undeclared field identifier to the method, but in Scala this would not compile:

scala> updateRecordByName(favoriteAlbum, "OK Computer")
:6: error: not found: value favoriteAlbum
           updateRecordByName(favoriteAlbum, "OK Computer")

Instead, and almost as concisely, you can pas a symbol literal:

scala> updateRecordByName('favoriteAlub, "OK Computer")

There is not much you can do with a symbol, except find out its name:

scala>val s = 'aSymbol
s: Symbol = 'aSymbol

scala>s.name
res20: String = aSymbol

Another thing that's noteworthy is that symbols are interned. If you write the same symbol literal twice, both expressions wil refer to the exact same Symbol object.

- Boolean Iiterals
The Boolean type has two literals, true and false:














2015년 11월 2일 월요일

Scala2e Chapter5 Basic Types and Operations 5.1 Some basic types


Collectively, types Byte, Short, Int, Long, and Char are called integral types.
The integral types plus Float and Double are called numeric types.







Scala2e Chapter4 Classes and Objects 4.5 The Application trait

Scala provides a trit, scala.Application

import ChecksumAccumulator.calculate

object FallWinterSpringSummer extends Application {

   for(season <- fall="" list="" p="" spring="" winter="">       println(season + ": " + calculae(season))
}


Then instead of writing a main method, you place the code you would have put in the main method directly between the curly braces of the singleton object. That's it. You can compile and run this application just like any other.

Inheriting from Application is shorter than writing an explicit main method, but it also has some shortcomings.
First, you can't use this trait if you need to access command-line arguments, because the args array isn't available.
Second, because of some restrictions in the JVM threading model, you need an explicit main method if your program is multi-threaded.
Finally, some implementations of the JVM do not optimize the initialization code of an object which is executed by the Application trait. So you should inherit from Application only when your program is relatively simple and single-threaded.

Scala2e Chapter4 Classes and Objects 4.4 A Scala application

To run a Scala program, you must supply the name of a standalone signleton object with a main method that takes on parameter, an Array[String], and has a result type of Unit.

import ChecksumAccumulator.calculate

object Summer{
   def main(args: Array[String]){
       for(arg <- args="" p="">            println(arg + ": " +  calculate(arg))
    }
}

Scala implicitly imports members of packages java.lang and scala, as well as the members of a singlecton object named Predef, into every Scala source file. Predef, which resides in package scala, contains many useful methods. (println,assert...)

.scala files anything you want, no matter what Scala classes or code you put in them.
In general in the case of non=scripts, however, it is recommended style to name files after the classes they contain as in done in java, so that programmers can more easily locate classes by looking at file names.

A script, by contrast, must end in a result expression.

One way to do this is to use scalac, which is the basic Scala compiler, like this:

$scalac ChecksumAccumulator.scala summer.scala

This compiles your source files, but there may be a perceptible delay before the compilation finishes. The reason is that every time the compiler starts up, it spends time scanning the contents of jar files and doing other initial work before it even looks at the fresh source files you submit to it. Fro this reason, the Scala distribution also includes a Scala compiler daemon called fsc(for fast Scala compiler). You use it like this:

$fac ChecksumAccumulator.scala Summer.scala

If you ever want to stop the fsc daemon, you can do so with fsc -shutdown.

Scala2e Chapter4 Classes and Objects 4.3 Singleton objects

Scala connot have static members.
Instead, Scala has singleton objects.
except instead of the keyword class you use the keyword object.

import scala.collection.mutable.Map

object ChecksumAccumulator{

     private val cashe = Map[String, Int]()
     def ccalculate(s: String) : Int =
          if(cache.contains(s))
               cache(s)
          else {
               val acc = new CheckSumAccumulator
               for(c <- p="" s="">                   acc.add(c.toByte)
               val cs = acc.checksum()
               cache += (s -> cs)
                cs
          }
  }

If you are a Java programmer, on way to thick of singleton objects is as the home for any static methods you might have written in Java.

ChecksumAccumulator.calculate("Every value is an object.")

A singleton object is more than a holder of satic methods, however, It is a first-class object. You can think of a singleton object's name, therefore, as a "name tag" attached to the object:



Defining a singleton object doesn't define a type(at the Scala level of abstraction).
Singleton objects extends a superclass and can mix in traits. Given each singleton object is an instance of its superclasses and mixed-in traits, you can invoke its methods via these types, refer to it from variables of these types, and pass it to methods expecting these types.

One difference between classes and singleton objects is that singleton objects cannot take parameters, whereas classes can.

Because you can't instantiate a singleton object with the new keyword, you have no way to pass parameters to it.
Each singleton object is implemented as an instance of a synthetic class referenced from a static variable, so they have the same initialization semantics as Java statics.
In particular, a singleton object is initialized the first time some code accesses it.

A singleton object that does not share the same name with a companion class is called a standalone object.
   

Scala2e Chapter4 Classes and Objects 4.2 Semicolon inference

In a Scala program, a semicolon at the end of a statement is usually optional.

val s = "hello"; println(s)

The rules of semicolon inference

1. The line in questing ends in a word that would not be legal as the end of a statement, such as period or an infix ooperator.

2. The next line begins with a word that cannot start a statement.

3. The line ends while inside parentheses (...) or brackets [...], because these cannot contain multiple statements anyway.




Scala2e Chapter4 Classes and Objects 4.1 Classes, fields, and methods

A class is a blueprint for objects.
Once you define a class, you can create objects from the class blueprint with the keyword new.

class ChecksumAccumulator{
// class definition goes here
}

You can create ChecksumAccumulator objects with:

new ChecksumAccumulator


class ChecksumAccumulator{
    var sum = 0
}

val acc = new ChecksumAccumulator
val csa = new ChecksumAccumulator



acc.sum = 3



An object's instance variables make up the memory image of the object.
You can see this illustrated here not only in that you see two sum variables, but also that when you changed on, the other was unaffected.


//Won't compile, because acc is a val
acc = new ChecksumAccumulator

class ChecksumAccumulator{
   private var sum = 0
}


val acc = new ChecksumAccumulator
acc.sum = 5 //Won't comile, because sum is private


The way you make members public in Scala is by not explicity specifying any access modifier.

class ChecksumAccumulator{

    private var  sum = 0
    def add(b: Byte): Unit = {
      sum += b
    }

    def checksum(): Int = {
       return ~(sum & 0xFF) + 1
    }
}


Ay parameers to a method can be used inside the method. One important characteristic of method parameters in Scala is that they are vals, not vars.

def add(b : Byte) : Unit = {
   b = 1                // This won't complie, becase b is a val
   sum += b
 }

The recommended style for methods is in fact to avoid having explicit, and especially multiple smaller ones. On the other hand, design choices depend on the design context, and Scala makes it easy to write methods that have multiple, explicit returns if that's what you desire.

class ChecksumAccumulater {
   private var sum = 0
   def add(b: Byte) : Unit = sum += b
   def checksum() : Int = ~(sum & 0xFF) + 1
}

Methods with a result type of Unit, such as ChecksumAccumulator's add method, are executed for their side effects.
A side effect is generally defined as mutating state somewhere external to the method or performing an I/O action.


class ChecksumAccumulator{
   private var sum = 0
   def add(b: Byte) { sum += b }
   def checksum() : Int = ~(sum & 0xFF) + 1
}


One puzzler to watch out for is that whenever you leave off the equals sign before the body of a function, its result type will definitely be Unit.
This is true no matter what the body contains, because the Scala compiler can convert any type to Unit. For example, It the last result of a method is a String, but the method's result type is declared to be Unit, the String will be converted to Unit and its value lost.








Scala2e Chapter3 Next Steps in Scala - Step 12. Read lines from a file

In this section, you'll build a script that reads lines from a file and prints them out prepended with the number of characters in each line.

import scala.io.Source
if(argslength > 0){
   for(line <- args="" getlines="" p="" source.fromfile="">       println(line.length + "  "  + line)
   }
}else
   Console.err.println("Please enter filename")

To accomplish this, you can iterate through the lines twice. The first time through you'll determine the maximum width required by any line's character count. the second time through you'll print the output, using the maximum width calculated previously. Because you'll be iterating through the lines twice, you may as well assign them to a variable:

val lines = Source.fromFile(args(0)).getLines().toList

The lines variable, therefore, references a list of strings that contains the contents of the file specified on the command line.

def widthOfLength(s: String) = s.length.toString.length

with the function, you could calculate the maximum width liek this:

var maxWidth = 0
for(line <- lines="" p="">   maxWidth = maxWidth.max(widthOfLength(line))

import scala.io.Source

def widthOfLength(s:String) = s.length.toString.length

if(args.length > 0 ){
   val lines = Source.fromFile(args(0)).getLines().toList

   val longestLine = lines.reduceLeft(
       (a, b) => if(a.length > b.length ) a else b
   )
   val maxWidth = widthOfLength(longestLine)


   for(line <- lines="" p="">      val numSpaces = maxWidth - widthOfLength(line)
      val padding = " " * numSpaces
      println(padding + line.length + " | " + line)
   }
}
else
     Console.err.println("Please enter filename")








2015년 10월 29일 목요일

Scala2e Chapter3 Next Steps in Scala - Step 11. Learn to recognize the functional style

Two style code.

imperative style : if code ontains any vars
functional style : it contains only vals

imperative style:

def printArgs(args: Array[String])):Unit ={
   var i =0
   while (i < args.length) {
       println(args(i))
        i +=1
    }
}

your can transform this bit of code into a more functional style by getting rid of the var, for example, like this.

def printArgs(args: Array[String]): Unit = {
    for( arg <- args="" div="" nbsp="">
       println(arg)
}

or this:


def printArgs(args: Array[String]: Unit = {
    args.foreach(println)
}

Benefit of programming with fewer vars.
- The refactoryed(more functional) code is clearer.
- More concise
- less error-prone than the original(more imperative) code.

The telltale sign of a function with side effects is that its result type is Unit. 
If a function isn't returning any interesting value, which is what a result type of Unit means, the only way that function can make a difference in the world is through some kind of side effect.

2015년 10월 28일 수요일

Scala2e Chapter3 Next Steps in Scala - Step 10. Use sets and maps

Because Scala aims to help you take advantage of both functional and imperative styles, is collections libraries make a point to differentiate between mutable and immutable collections.

For example, the Scala API contains a base trait for sets, where a trait is similar to Java interface.

Scala the providers two subtraits, on for mutable sets and another for immutable sets.

var jetSet = Set("Boeing", "Airbus")
jetSet += "Lear"
println(jetSet.contains("Cessna"))


To add a new element to a set, you call + on the set, passing in the new element. Both mutable and immutable sets offers a + method, but their behavior differs. 
Whereas a mutable set will add the element to itself, an immutable set will create and return a new set with the element added. 

import scala.collection.mutable.Set

val movieSet = Set("Hitch", "Poltergeist")
movieSet += "Shrek"
println(movieSet)


The mutable set by calling the += method on the set.

import scala.collection.immutable.HashSet

val hashSet = HashSet("Tomatoes", "Chilies")
println(hashSet + "Coriander")




There's base Mat trait in package scala.collection, and two subtrait Maps: a mutable Map in scala.collection.mutable and an immutable one in scala.collection.immutable.

import scala.collection.mutable.Map

val treasureMap = Map[Int, String]()
treasureMap  += (1 -> "Go go island.")
treasureMap  += (2 -> "Find big X on ground.")
treasureMap  += (3 -> "Dig.")

println(treasureMap(2))

The map is empty because you pass nothing to the factory method(the parentheses in "Map[Int, String]()" are empty).
This -> method, which you can invoke on any object in a Scala program, returns a two-element tuple containing the key and value.

If you prefer an immutable map, no import is necessary, as immutable is the default map.

val romanNumeral = Map(
1->"I", 2 ->"II", 3 ->"III", 4->"IIII", 5 ->"IIIII")

println(romanNumeral(4))








2015년 10월 27일 화요일

Scala2e Chapter3 Next Steps in Scala - Step 9. Use tuples

Tuples are immutable.
Tuples can contain different type of elements.

val pair = (99, "Luftballons")
println(pair._1)
println(pair._2)

apply method always retuns the same type, but each element of a tuple may be a different type: _1 can have one result type, _2 another, and so on.
These _N numbers are one-based, instead of zero-base, because string with 1 is a tradition set by other lanaguages with statically typed tuples, such as Haskell and ML.



Scala2e Chapter3 Next Steps in Scala - Step 8. Use lists

The functional style of programming is that methods should not have side effects.
A method's only act should be to compute and return a value.
- less entangled
- more reliable
- reusable

Applying this functional philosophy to the world of objects means making objects immutable.

Scala Lists are always immutable(whereas Java Lists can be mutable).
More generally, Scala's List is designed to enable a functional style of programming.

val onTwoThress = List(1,2,3)

val onTwo = List(1,2)
val threeFour = List(3,4)
val oneTwoThreeFour = oneTwo ::: threeFour
println(oneTwo + " and " + threeFour + " were not mutated.")
println("Thus, "+ onTwoThreeFour + " is a new list.")

If you run this script, you'll see:

List(1,2) and List(3,4) were not mutated.
Thus, List(1,2,3,4) is a new List.

List has method named ':::' for list concatenation.
 '::' is pronounced "cpns."
Cons prepends a new element to the beginning of an existiong list, and returns the resulting list.

val thwThree = List(2,3)
val oneTwoThree = 1 :: twoThree
println(oneTwoThree)

You'll see:
List(1,2,3)





Scala2e Chapter3 Next Steps in Scala - Step 7. Parameterize arrays with type

In Scala, you can instantiate objects, or class instances, using new.
When you instantiate an object in Scala, you can parameterize it with values and types.

The follwing Scala coe instantiates a new java.math.BigInteger and parameterizes it with the value "12345"

val big = new java.math.BigInteger("12345")


val greetString = new Array[String](3)

greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"


for(i <- 0="" 2="" p="" to="">print(greetStrings(i))




val greetStrings : Array[String] = new Array[String](3)

greetString(0) = "Hello"
greetString(1) = ", "
greetString(2) = "world!\n"

These three lines of code illustrate an important concept to understand about Scala concerning the meaning of val. When you define a variable with val, the variable can't reassigned, but the object to which it refers could potentially still be changed. So in this case, you couldn't be reassign greetStrings to a different array; greetStrings will always point to the same Array[String] instance with which it was initialized. But you can changed the elements of that array[String] instance with which it was initialized. But you can change the elements of that Array[String] over time, so the array itself is mutable.

for( i <- 0="" 2="" p="" to="">  print(greetString(i))

The code 0 to 2 is transformed into the method call (0).to(2).
Note that this syntax only works if you explicitily specify the receiver of the method call. You cannot write "println 10", but you can write "Console println 10".


greetStrings(0) = "Hello"  => greetStrings.update(0,"Hello")

val greetStrings = new Array[String](3)
greetStrings.update(0,"hello")
greetStrings.update(1,", ")
greetStrings.update(2, "world!\n")

for(i <- 0.to="" p="">   print(greetStrings.apply(i))