/* CS:2820 Object Oriented Software Development Spring 2015 The University of Iowa Instructor: Cesare Tinelli */ /* Scala examples seen in class */ /* Basic types */ 3 3 + 5 4 - 2 3.0 // some symbols are overloaded 1.4 + 3.0 // implicit conversion 1.4 + 3 // syntactic sugar for 1.4 + 3.toDouble "hi" "hi" ++ " there" // ill-typed "hi" ++ 3 "hi" + " there" // implicit conversion "high " + 5 // abbreviates "high " + 5.toString // functionally equivalent to "high " ++ "5" // implicit conversion and left associativity of + "hi" + 3.4 + 1 // implicitly converted to ("hi" + 3.4.toString) + 1.toString 3.4 + 1 + "hi" // implicitly converted to (3.4 + 1.toDouble).toString + "hi" true ! true true && false true || false 3 == 5 - 2 3 == 3.0 // implictly converted to 3.toDouble == 3.0 3 == "3" /** no implicity conversion here! **/ /* tuple types */ (1,3) (3,4,5) (3,"pp",4.3) ((1,2),3) == (1,(2,3)) // tuples of different type ((1,2),3) == (1,2,3) // tuples of different type /* Unit type */ () val a = () /* values and variables */ val a = 3 // declares symbolic value a as a synonym for 3 a a = 4 // error, symbolic values are immutable var b = 4 // declares a variable b b = 0 // variables are mutable /* Type ascription */ val a:Int = 4 // prescribes right hand-side expression to have type Int val a:Int = 4.7 // will generate a type error val a:Float = 4 // will convert 4 to 4.0 val a:String = "abc" val a:String = 3 // type error 3:Int (3:Int) + 1 3:Long // implicitly converted to (3.toLong):Long (3:Long) + 1 // implicitly converted to ((3.toLong):Long) + 1.toLong 3:String // failed implict conversion, type error /* methods */ // methods with automatically inferred return type def f1 (n:Int) = n + 1 val a = 3 f1(a) def f2 (n:Int) = n + 1.5 f2(3) // method with return type Unit def g (n:Int) = println("Input value was " + n) // alternative syntax for Unit returning method def g (n:Int) { println("Input value was " + n) } // g is interesting for its side effect (printing something), // not for its returned value val x = g(4) def max (x:Int, y:Int) = if (x > y) x else y // parsed incorrectly // 'if' statement must be in a single line or // enclosed in a block (see later) def max (x:Int, y:Int) = if (x > y) x else y // correct syntax def max (x:Int, y:Int) = { if (x > y) x else y } var c = 3 // The if construct is an expression. // It can be seen as a mixfix operator with three arguments: // // if (_) _ else _ // // The first argument must be of type Boolean. // The second and third argument must be of the same type. // The type of an if expression is determined by the type of its // second and third arguments // val k = if (c > 0) 10 else 20 // if expressions can go everywhere an expression of can go (if (c > 0) 1 else 0) + 7 // if the left and right branches are not of the same type // they are implicitly converted the their closest common supertype // (roughly speaking) if (true) 1 else 2.0 if (true) 1 else "f" /* expressions with side effects */ // assignments are also expressions ... c = 4 // ... of type Unit :type (c = 4) val w = (c = 0) // this looks a lot like Jave code but it is an expression // (of type Unit) if (c > 0) c = c + 1 else c = c - 1 /* sequential composition of expressions */ // expressions can be composed and made into a block {3; 4} // block evaluates to and has the type of its last expression // in the sequence // a new line separator can be used instead of ; { 3 4 } // zero or more espressions can be composed {} // of type unit {3} {3; 4; "a"} // blocks are expressions and so can be nested {{3; 4}; 5} {3; {4; 5}} // composition is most useful with expressions with side effect, // such as assignments {c = 40; c} // changes c and returns its value val x1 = {c = 42; c - 2} // x1 is an Int c val x2 = {2; c = 41} // x2 is a Unit c // since blocks are expressions, they can be used as arguments // in method calls (not recommended for clarity though) f1({c = 3; 2}) c