Computer Science Canada

[Scala] A little code

Author:  wtd [ Tue Jun 05, 2007 11:43 am ]
Post subject:  [Scala] A little code

code:
// A simple expression

5 * 2

// A character

'h'

// A string

"Hello"

// An Object object

new Object

// A constant, inferred typing

val message = "Hello"

// A variable, inferred typing

var message = "hello"

// A variable, explicit typing

var message: String = "hello"

// Assigning a new value to that variable

message = "Yo"

// A very simply method that returns a String (inferred)

def foo = "bar"

// The same thing, explicitly typed return type

def foo: String = "bar"

// The same thing, with parentheses

def foo(): String = "bar"

// Method with a parameter

def timesTwo(n: Int) = n * 2

// Conditional expression

if (foo == 2)
   42
else
   27

// With braces

if (foo == 2) {
   42
}
else {
   27
}

// Conditionally assign value to variable using conditional as a statement

var foo: Int = 0

if (bar == 36)
   foo = 42
else
   foo = 27

// Do the same using conditional as expression

var foo: Int = if (bar == 36) 42 else 27

// Do the same, but make foo constant

val foo: Int = if (bar == 36) 42 else 27

// And use type inferencing

val foo = if (bar == 36) 42 else 27

// Now, a method that uses a conditional expression

def foo(bar: Boolean) = if (bar) 42 else 27

// A method that calls an object's method

def len(s: String) = s.length

// The same, with postfix method syntax

def len(s: String) = s length

// A class that extends Object, but does nothing additional

class Foo

// Override the toString method from Object

class Foo {
   override def toString = "A Foo object"
}

// A singleton object, with the toString method overriden

object Bar {
   override def toString = "A Bar object"
}

// Assigning a Foo object to a constant

val f = new Foo

// Assigning its String representation to a constant

val s = f toString

// Skipping the middle-man

val s = new Foo toString

// With parens to disambiguate the precedence rules

val s = (new Foo) toString

// Another class, with a constructor, and two constant fields

class MyRange(val start: Int, val end: Int)

// A MyRange object

val r = new MyRange(1, 4)

// Assigning its start and end to constants

val s = r.start
val e = r.end

// Using postfix syntax

val s = r start
val e = r end

// Giving it a toString method

class MyRange(val start: Int, val end: Int) {
   override def toString = start + ".." + end
}

// Extending the class

class MyExclusiveEndedRange(val start: Int, val end: Int) extends MyRange(start, end) {
   override def toString = start + "..." + end
}

// We need a way to iterate over a range.  Let's create a simple Iterator trait.

trait IntIterator {
   def start
   def current: Int
   def atEnd: Boolean
   def advance
}

// A class which implements this

class MyRangeIterator(val target: MyRange) extends IntIterator {
   private var _current = target.start
   def start { _current = target.start }
   def current = _current
   def atEnd = current > target.end
   def advance { _current += 1 }
}

// A method for MyRange which gets us one of these

class MyRange(val start: Int, val end: Int) {
   override def toString = start + ".." + end
   def iterator = new MyRangeIterator(this)
}

// We can use an anonymous class

class MyRange(val start: Int, val end: Int) {
   override def toString = start + ".." + end
   def iterator = new IntIterator {
      private var _current = start
      def reset { _current = start }
      def current = _current
      def atEnd = current > end
      def advance { _current = _current + 1 }
   }
}

// Now we can loop over and print the range using the Console object's println method

val r = new MyRange(1, 4)
val i = r.iterator

while (!i.atEnd) {
   Console.println(i)
   i.advance
}

// The !i.atEnd bit looks ugly.  Let's provide a hasMore method with a default implementation.

trait IntIterator {
   def start
   def current: Int
   def atEnd: Boolean
   def hasMore = !atEnd
   def advance
}

// Now, to rewrite the loop.

val r = new MyRange(1, 4)
val i = r.iterator

while (i.hasMore) {
   Console.println(i)
   i.advance
}

// Now, that IntIterator trait might be better as a generic trait.

trait Iterator[A] {
   def start
   def current: A
   def atEnd: Boolean
   def hasMore = !atEnd
   def advance
}

// And now...

class MyRange(val start: Int, val end: Int) {
   override def toString = start + ".." + end
   def iterator = new Iterator[Int] {
      private var _current = start
      def reset { _current = start }
      def current = _current
      def atEnd = current > end
      def advance { _current = _current + 1 }
   }
}

// But MyRange should probably extend some kind of trait to indicate that it has an iterator method.

trait Iterable[A] {
   def iterator: Iterator[A]
}

// ...

class MyRange(val start: Int, val end: Int) extends Iterable[Int] {
   override def toString = start + ".." + end
   def iterator = new Iterator[Int] {
      private var _current = start
      def reset { _current = start }
      def current = _current
      def atEnd = current > end
      def advance { _current = _current + 1 }
   }
}

// A blast from the past.

class MyExclusiveEndedRange(val start: Int, val end: Int) extends MyRange(start, end) {
   override def toString = start + "..." + end
   override def iterator = new Iterator[Int] {
      private var _current = start
      def reset { _current = start }
      def current = _current
      def atEnd = current >= end
      def advance { _current = _current + 1 }
   }
}

// All together now!

trait Iterator[A] {
   def start
   def current: A
   def atEnd: Boolean
   def hasMore = !atEnd
   def advance
}

trait Iterable[A] {
   def iterator: Iterator[A]
}

class MyRange(val start: Int, val end: Int) extends Iterable[Int] {
   override def toString = start + ".." + end
   def iterator = new Iterator[Int] {
      private var _current = start
      def reset { _current = start }
      def current = _current
      def atEnd = current > end
      def advance { _current = _current + 1 }
   }
}

class MyExclusiveEndedRange(val start: Int, val end: Int) extends MyRange(start, end) {
   override def toString = start + "..." + end
   override def iterator = new Iterator[Int] {
      private var _current = start
      def reset { _current = start }
      def current = _current
      def atEnd = current >= end
      def advance { _current = _current + 1 }
   }
}

Author:  wtd [ Wed Jun 06, 2007 12:55 pm ]
Post subject:  Re: [Scala] A little code

code:
// Let's add a method to Iterable.  It takes, as a paremeter, a function.

trait Iterable[A] {
   def iterator: Iterator[A]
   def doForAll(f: A => Unit) {
      val i = iterator
      while (i.hasMore) {
         f(i.current)
         i.advance
      }
   }
}

// Now, let's rewrite the loop.

val r = new MyRange(1, 4)
r.doForAll((x: Int) => Console.println(x))

// Or perhaps...

val r = new MyRange(1, 4)
r.doForAll { case x => Console.println(x) }

// Or using special syntax for binary methods, we can get rid of all of the periods.

new MyRange(1, 4) doForAll { case x => Console println x }

Author:  richcash [ Wed Jun 06, 2007 10:03 pm ]
Post subject:  Re: [Scala] A little code

Great introduction! Smile

I like the keywords override and trait.

wtd wrote:
code:
// Or using special syntax for binary methods, we can get rid of all of the periods.

new MyRange(1, 4) doForAll { case x => Console println x }

Wow, that is cool. But isn't doForAll a unary method, not a binary method? Confused

Author:  wtd [ Wed Jun 06, 2007 11:12 pm ]
Post subject:  RE:[Scala] A little code

I suppose you might classify it that way as well. Binary in this case because it has both a receiver and an argument.

Author:  richcash [ Thu Jun 07, 2007 12:58 am ]
Post subject:  Re: [Scala] A little code

wtd wrote:

I suppose you might classify it that way as well. Binary in this case because it has both a receiver and an argument.

Oh, now I see what you mean. Thanks for clarifying.

Author:  wtd [ Thu Jun 07, 2007 10:54 am ]
Post subject:  RE:[Scala] A little code

Another possibility for that last one:

code:
new MyRange(1, 4) doForAll (Console println _)

Author:  wtd [ Thu Jun 07, 2007 2:57 pm ]
Post subject:  RE:[Scala] A little code

code:
// Turns out, there're generic Iterable and Iterator traits already
// defined as part of Scala's standard library.

class MyRange(val start: Int, val end: Int) extends Iterable[Int] {
   def elements = new Iterator[Int] {
      private var current = start
      def hasNext = current <= end
      def next = {
         val c = current
         current += 1
         c
      }
   }
}

// Now we can write our while loop.

val r = new MyRange(1, 4)
val i = r.elements

while (i.hasNext) {
   Console.println(i.next)
}

// But you'd think it would be easier.

for (val x <- new MyRange(1, 4))
   Console.println(x)

// But what if we only want to print the even numbers?

val r = new MyRange(1, 4)
val i = r.elements

while (i.hasNext) {
   val x = i.next
   if (x % 2 == 0)
      Console.println(x)
}

// I said something about "easier"

for (val x <- new MyRange(1, 4))
   if (x % 2 == 0)
      Console.println(x)

// Ahem... *easier*

for (val x <- new MyRange(1, 4) if x % 2 == 0)
   Console.println(x)

// Or alternatively...

new MyRange(1, 4) filter (_ % 2 == 0) foreach (Console println _)

Author:  wtd [ Thu Jun 07, 2007 3:26 pm ]
Post subject:  RE:[Scala] A little code

code:
// Being picky.

for (val x <- new MyRange(1, 55)) {
   if (x == 42)
      Console println "42!  The answer!  But what is the question?"
   else if (x % 2 == 0)
      Console println x
   else
      Console println "Better luck next time."
}

// Let's inject some pattern-matching.

for (val x <- new MyRange(1, 55)) {
   x match {
      case 42 => Console println "42!  The answer!  But what is the question?"
      case _ =>
         if (x % 2 == 0)
            Console println x
         else
            Console println "Better luck next time."
   }
}

// Or perhaps...

new MyRange(1, 4) foreach {
   case 42 => Console println "42!  The answer!  But what is the question?"
   case _ =>
      if (x % 2 == 0)
         Console println x
      else
         Console println "Better luck next time."
}

Author:  Clayton [ Thu Jun 07, 2007 3:28 pm ]
Post subject:  RE:[Scala] A little code

I must ask, I've noticed you use an underscore quite a bit, like in here:

scala:
case _ =>
      if (x % 2 == 0)
         Console println x
      else
         Console println "Better luck next time."


What exactly does it mean?

Author:  wtd [ Thu Jun 07, 2007 3:31 pm ]
Post subject:  RE:[Scala] A little code

In that context, it is a nameless pattern that matches anything that a previous pattern has not.

Author:  Clayton [ Thu Jun 07, 2007 3:32 pm ]
Post subject:  RE:[Scala] A little code

So in essence a safeguard for something that slips through?

Author:  wtd [ Thu Jun 07, 2007 3:33 pm ]
Post subject:  RE:[Scala] A little code

Yes. Essentially analogous to "default" in Java's "switch" statement.

Author:  Clayton [ Thu Jun 07, 2007 3:35 pm ]
Post subject:  RE:[Scala] A little code

Ah, excellent.

Now, I may have missed something about this earlier, but this:

code:
val x <- new MyRange(1, 55)
confuses me a bit, care to explain?

Author:  wtd [ Thu Jun 07, 2007 3:39 pm ]
Post subject:  RE:[Scala] A little code

It is part of the for comprehension.

We assign each element of the object created by "new MyRange(1, 55)" to the constant "x". The keyword "var" could also be used, allowing x to be modified within the body of the comprehension.

Author:  Clayton [ Thu Jun 07, 2007 3:41 pm ]
Post subject:  RE:[Scala] A little code

Ah, alright. I think the '<-' from the "new MyRange(1, 55)" kind of obscured the fact that that was an assignation. I have to admit, Scala looks pretty darn cool.

Author:  wtd [ Thu Jun 07, 2007 6:09 pm ]
Post subject:  RE:[Scala] A little code

code:
// A MyRange object could really just be an Iterator[Int].

class MyRange(val start: Int, val end: Int) extends Iterator[Int] {
   protected var current = start
   def hasNext = current <= end
   def next = {
      val c = current
      current += 1
      c     
   }
}

// And a MyExclusiveEndedRange.

class MyExclusiveEndedRange(override val start: Int, override val end: Int)
 extends MyRange(start, end) {
   override def hasNext = current < end
}

Author:  wtd [ Thu Jun 07, 2007 8:57 pm ]
Post subject:  RE:[Scala] A little code

code:
// Let's number the numbers in a range.

var count = 0
val r = new MyRange(5, 10)

while (i.hasNext) {
   Console.println(count + ": " + i.next)
   count += 1
}

// Easier?

var count = 0
val r = new MyRange(5, 10)

for (val x <- r) {
   Console.println(count + ": " + x)
   count += 1
}

// Not easy enough.

val r = new MyRange(5, 10)
val i = r.counted

for (val x <- i)
   Console.println(i.count + ": " + x)

// How about a new class?

class EnumeratedIterator[+T](val targetIterator: Iterator[T])
 extends Iterator[(Int, T)] {
   protected val iter = targetIterator.counted
   def hasNext = iter.hasNext
   def next = {
      val n = iter.next
      (iter.count, n)
   }
}

// And now...

val r = new MyRange(5, 10)

for (val (count, x) <- new EnumeratedIterator(r))
   Console.println(count + ": " + x)

Author:  wtd [ Thu Jun 07, 2007 11:23 pm ]
Post subject:  RE:[Scala] A little code

code:
// Use the power of the standard library!

for (val (x, count) <- new MyRange(5, 10) zipWithIndex)
   Console.println(count + ": " + x)

// Let's try some XML.

val xml = <list>
   { for (val (x, c) <- new MyRange(5, 10) zipWithIndex)
        yield <item><num>{c}</num><val>{x}</val></item> }
</list>

Console.println(xml)

Author:  rizzix [ Sat Jun 09, 2007 3:09 am ]
Post subject:  RE:[Scala] A little code

Scala:
class Foo {
    private[this] var n = ""
    def name = n
    def name_=(n : String) =
        this.n = if (n == "bar") "baz" else n
}

val foo = new Foo;
foo.name = "bar"
Console print foo.name // "baz"


Properties Smile

Author:  wtd [ Thu Jun 21, 2007 7:49 pm ]
Post subject:  RE:[Scala] A little code

Let's create our own loop.

code:
def myFor(init: Int, test: Int => Boolean, update: Int => Int)(action: Int => Unit): Unit =
   if (test(init)) {
      action(init)
      myFor(update(init), test, update)(action)
   }


And then we'll try calling it.

code:
myFor(1, _ <= 3, _ + 1) {
   case n => Console println n
}


Or perhaps...

code:
val doFromOneToThree = myFor(1,  _ <= 3, _ + 1) _
doFromOneToThree { case n => Console println n }

Author:  wtd [ Thu Jun 21, 2007 8:11 pm ]
Post subject:  RE:[Scala] A little code

Perhaps something inspired by education.

code:
type Name = (String, String)
type NameList = List[Name]

class MathClass(protected var teachers: NameList, protected var students: NameList) {
    def addTeacher(teacher: Name) {
        teachers = teachers ::: List(teacher)
    }

    def addStudent(student: Name) {
        students = students ::: List(student)
    }

    def foreachTeacher(action: Name => Unit) {
        for (val teacher <- teachers) action(teacher)
    }

    def foreachStudent(action: Name => Unit) {
        for (val student <- students) action(student)
    }

    def foreachTeacherStudentCombination(action: (Name, Name) => Unit) {
        for (val teacher <- teachers;
             val student <- students) action(teacher, student)
    }
}


code:
val myClass = new MathClass(List(("Foo", "Bar"), ("Baz", "Smith")), List(("Baz", "Qux"), ("Wooble", "Ninja")))
myClass foreachTeacherStudentCombination {
    case ((tFirst, tLast), (sFirst, sLast)) =>
        if (tFirst == sFirst || tLast == sLast || tFirst == sLast || tLast == sFirst) {
            Console println "Whoa!  Similar names.... groovy!"
        }
        else {
            val tName = tFirst + " " + tLast
            val sName = sFirst + " " + sLast

            Console println (tName + " teaches " + sName + ".")
        }
}


: