GIGO: words unreadable aloud
Mishrogo Weedapeval
 

 

GIGO: words unreadable aloud

  Monday 31 May 2004
Chapter 4, Exercise 19 variant

I thought the c4x19 solution might look better this way (with print and create folded into the 2D array class), but it gets me a null pointer crash in the compiler. I guess I oughta download a more recent nightly build and try it again. Makes me leery about trying the 3D version, though.

(PS, I really did post the c4x19 one before heading out for Tucson for the long weekend. The Radio Userland server(s?) seem to suck pretty bad a lot of the time, though.)

class arDbl {
    var ar : Array[Double] = _;
    def length = ar.length;
    def apply( i: Int ) = ar(i);
    def update( i:Int, nv: Double) = ar.update(i, nv );
    def this( sz: Int ) = {
        this();
        ar= new Array[Double]( sz );
    }
};
class ar2D {
    var ard : Array[ arDbl ] = _;
    def length = ard.length; 
    def apply( i: Int ) = ard(i);
    def update( i:Int, j:Int, nv:Double ) = {
        ard(i).update(j, nv );
    }
    def this( rows:Int, cols: Int ) = {
        this();
        ard= new Array[ arDbl ]( rows );
        for( val j <- Iterator.range(0, rows) ) {
            ard(j) = new arDbl(cols);
        }
    }
    def this( rows:Int, cols: Int, start:Double, end:Double ) = {
        this(rows,cols);
        var current = start;
        var step = (end - start) / (rows * cols -1);
        for( val j <- Iterator.range( 0, rows ) ) {
            var curr_row = ard(j);
            for( val i <- Iterator.range( 0, cols ) ) {
                curr_row.update( i, current);
                current = current + step;
            }
        } 
    }
    def print = {
        var rows = ard.length;
        var cols = ard(0).length;
        for( val i <- Iterator.range( 0, rows ) ) {
            for( val j <- Iterator.range( 0, cols ) ) {
                Console.print( ard(i)(j) + " " );
            }
            Console.println("");
        }
    }
}
object c4x19 {
    def main (args: Array[String] ) = {
        Console.println("--> new ar2D( 3, 3, 1.0, 10.0 )" );
        val arm = new ar2D( 3, 3, 1.0, 10.0 );
        arm.print; 
        Console.println("");
        Console.println("--> new ar2D( 3, 4, 1.0, 20.0 )" );
        (new ar2D( 3, 4, 1.0, 20.0 )).print;
        Console.println("");
        Console.println("--> new ar2D( 5, 5, -10.0, 10.0 )" );
        (new ar2D( 5, 5, -10.0, 10.0 )) print
    }
}

11:59:23 PM   comment/     

  Thursday 27 May 2004
Chapter 4, Exercise 19

A simple 2D array exercise. I ran into (I think) a Scala compiler bug, but worked around it by declaring arDbl, my own Array[Double] class. (Here are THECLAPP's Java and Lisp solutions.) And here's my Scala solution:

class arDbl {
    var ar : Array[Double] = _;
    def length = ar.length;
    def apply( i: Int ) = ar(i);
    def update( i:Int, nv: Double) = ar.update(i, nv );
    def this( sz: Int ) = {
        this();
        ar= new Array[Double]( sz );
    }
};
class ar2D {
    var ard : Array[ arDbl ] = _;
    def length = ard.length; 
    def apply( i: Int ) = ard(i);
    def update( i:Int, j:Int, nv:Double ) = {
        ard(i).update(j, nv );
    }
    def this( rows:Int, cols: Int ) = {
        this();
        ard= new Array[ arDbl ]( rows );
        for( val j <- Iterator.range(0, rows) ) {
            ard(j) = new arDbl(cols);
        }
    }
};
object c4x19 {
    def create ( rows:Int, cols:Int, start:Double, end:Double )
        : ar2D = {
        var ar = new ar2D( rows, cols );
        var current = start;
        var step = (end - start) / (rows * cols -1);
        for( val j <- Iterator.range( 0, rows ) ) {
            var curr_row = ar(j);
            for( val i <- Iterator.range( 0, cols ) ) {
                curr_row.update( i, current);
                current = current + step;
            }
        } 
        ar
    }
    def print ( ar : ar2D ) = {
        var rows = ar.length;
        var cols = ar(0).length; // assumes a non-empty rectangular array
        for( val i <- Iterator.range( 0, rows ) ) {
            for( val j <- Iterator.range( 0, cols ) ) {
                Console.print( ar(i)(j) + " " );
            }
            Console.println("");
        }
    }
    def main (args: Array[String] ) = {
        Console.println("--> create( 3, 3, 1.0, 10.0 )" );
        print( create( 3, 3, 1.0, 10.0 ) );
        Console.println("");
        Console.println("--> create( 3, 4, 1.0, 20.0 )" );
        print( create( 3, 4, 1.0, 20.0 ) );
        Console.println("");
        Console.println("--> create( 5, 5, -10.0, 10.0 )" );
        print( create( 5, 5, -10.0, 10.0 ) );
    }
}

9:09:33 PM   comment/     

  Wednesday 26 May 2004
Chapter 4, Exercises 17-18

Chapter 4, Exercise 17

17. Create a class with a static String field that is initialized at the point of definition, and another one that is initialized by the static block. Add a static method that prints both fields and demonstrates that they are both initialized before they are used.

In scala, the body of the class passes for what Bruce is calling a "static block", except that it is static in Scala only because it's inside an object rather than a class.

Here is THECLAPP's c4x17 solution.

package x;
object c4x17 {
    var sdefn : String = "c4x17c sdefn";
    var scons : String = _;
    Console.println( "scala obj main body" );
    scons = "scala static String init" ;
    def main ( args: Array[String] ) = {
        Console.println( "sdefn " + sdefn );
        Console.println( "scons " + scons );
    }
}

Chapter 4, Exercise 18

18. Create a class with a String that is initialized using "instance initialization". Describe a use for this feature (other than the one specified in this book).

In scala, this would just use statements in the main body of the class. Different from the "static block" only in that these statements are in a class, not in a file-level object.

(THECLAPP's c4x18.)

class c4x18c {
    var s1 : String = _;
    s1 = "init in instance init area";
    def demo_init = Console.println( "s1: " + s1 );
}
object c4x18 {
    def main ( args: Array[String] ) = {
        val obj = new c4x18c;
        obj.demo_init;
    }
}

10:41:47 PM   comment/     

  Tuesday 25 May 2004
Chapter 4, Exercises 15-16

A couple more initialization exercises.

Chapter 4, Exercise 15

15. Create a class containing an uninitialized String reference. Demonstrate that this reference is initialized by Java to null.

As we've seen, Scala has no such thing as an uninitialized String -- you're required to make it explicitly initialized to something, even if that something is just the "default value" for that type.

class c4x15c { var s : String = _; }; 
object c4x15 {
    def main ( args: Array[String] ) =
        Console.println( "Is it null?  " + (new c4x15c).s );
}

Chapter 4, Exercise 16

16. Create a class with a String field that is initialized at the point of definition, and another one that is initialized by the constructor. What is the difference between the two approaches?

Each c4x16c instance starts out with the same value for sdefn, versus each c4x16c instance starting out with some value (that you passed to the constructor) for scons. Other distinctions to note beside this one: val versus var (like C++'s "const" or not), and a member of an object (like C++ or Java's static members) versus a member of a class.

class c4x16c {
    var sdflt : String = _;
    var sdefn : String = "c4x16c sdefn";
    var scons : String = _;
    def this ( ts: String ) = { this(); scons = ts; }
}; 
object c4x16 {
    def main ( args: Array[String] ) = {
        val v1 = new c4x16c ;
        Console.println( "v1.sdflt " + v1.sdflt );
        Console.println( "v1.sdefn " + v1.sdefn );
        Console.println( "v1.scons " + v1.scons );
        val v2 = new c4x16c( "v2 ctor arg" );
        Console.println( "v2.sdflt " + v2.sdflt );
        Console.println( "v2.sdefn " + v2.sdefn );
        Console.println( "v2.scons " + v2.scons );
        val v3 = new c4x16c( "v3 ctor arg" ); ;
        Console.println( "v3.sdflt " + v3.sdflt );
        Console.println( "v3.sdefn " + v3.sdefn );
        Console.println( "v3.scons " + v3.scons );
    }
}

10:52:30 PM   comment/     

  Monday 24 May 2004
Chapter 4, Exercise 14

Bruce asks us to "Create a class containing an int and a char that are not initialized, and print their values to verify that Java performs default initialization."

But Scala requires that initialization to be a bit more explicit:

Try 1: val i : Int; gets this error message: class c4x14c needs to be abstract, since value i in class c4x14c is not defined.

Try 2: var i : Int; gets class c4x14c needs to be abstract, since variable i in class c4x14c is not defined ... (Note that variables need to be initialized to be defined).

Try 3 worked. The default value ("_") for Char appears to be zero, the NUL character.

package x;
class c4x14c {
    var i : Int = _;
    var ch : Char = _;
};
object c4x14 {
    def main ( args: Array[String] ) = {
        val ob = new c4x14c;
        val obich : Int = ob.ch;
        Console.println( "ob.i " + ob.i );
        Console.println( "ob.ch [" + ob.ch + "] (or, as Int, " + 
            obich + ")." );
    }
}

11:55:17 PM   comment/     

  Sunday 23 May 2004
Chapter 4, Exercise 13

Ok, here is some more fun with finalizers, despite what I mentioned on Thursday (David Chess' paraphrasing of Joshua Bloch's glowing description of finalizers: "Finalizers are lousy; avoid them in essentially all cases.") The THECLAPP solution for this one is pretty straightforward. My first Scala attempt was not as clean, because I assumed that the fact that the word "finalizer" didn't show up anywhere in the Scala manual meant that finalizers wouldn't work in Scala. So I made a java base class with a finalizer that called a method "my_finalize", and made a scala class that inherited from that java base class, and had an override defined for my_finalize. That all worked just fine, but then I tried it the following simpler way, and it Just Worked too.

package x;
class c4x13fc {
    var i : Int = _;
    var filled : Boolean = false;
    def this(ci: Int) = {
        this();
        Console.println( "c4x13fc::Tank " +ci+ " init." );
        i = ci;
    }
    override def finalize () = {
        if (filled) {
            Console.println( "Error: tank " +i+ " not empty at finalize!" );
        }
        else {
            Console.println( "Ok, tank " +i+ " is empty at finalize." );
        }
    }
}
object c4x13f {
    def testTanks = {
        {   // case 1: tank created, filled, emptied, thrown away
            val tank = new c4x13fc(0);
            tank.filled = true;
            tank.filled = false;
        } 
        { // case 2: tank created, filled, thrown away
            val tank = new c4x13fc(1);
            tank.filled = true;
        } 
        { // case 3: tank created & thrown away
            new c4x13fc(2);
        }
    }
    def main ( args: Array[String] ) = {
        testTanks;
        System.gc();
    }
}

1:54:31 PM   comment/     

  Thursday 20 May 2004
Chapter 4, Exercises 10-12

Chapter 4, Exercise 10

Exercise 10 asks "Create a class with two (overloaded) constructors. Using this, call the second constructor inside the first one." Seems pretty simple and straightforward. Goes with this entry from THECLAPP.

class c4x10c {
    var quantity : Double = _;
    def this( d: Double ) = {
        this();
        quantity = d;
    }
    def this( i: Int ) = {
        this( i * 1.0 );
    }
}
object c4x10 {
    def main ( args: Array[String] ) = {
        var obj = new c4x10c( 3 );
        Console.println( "obj.q is "+ obj.quantity );
    }
}

Chapter 4, Exercise 11

Bruce asks us to "Create a class with a finalize() method that prints a message. In main(), create an object of your class. Explain the behavior of your program." ( Here's the corresponding THECLAPP entry.)

Now, before we get all carried away with finalizers, let's read David Chess' takeaways (from two years ago) from Joshua Bloch's Effective Java:

  • Constructors are lousy; use static "newInstance()" methods instead,
  • Finalizers are lousy; avoid them in essentially all cases,
  • The Serializable interface has serious problems; use it rarely,
  • The Cloneable interface is essentially unusable; avoid it,
  • Inheritance is messy and dangerous; use composition instead,
  • Abstract classes are usually a poor idea; use interfaces instead.

And let's notice that Scala does not have finalizers. Nonetheless, if we put the finalizer in a java class and then extend it in our Scala code, we can get close to the requested code:

class c4x11s extends x.c4x11j {
    var j: Int = 42;
}
object c4x11 {
    def main ( args: Array[String] ) = {
        var obj = new c4x11s;
        //  c4x is not a member of x.c4x11s
        // Console.println( "obj.j " + obj.j + ";  obj.c4x " + obj.c4x );
        Console.println( "obj.j " + obj.j );
        obj = null;   // this is the c4x12 addition
        System.gc();
    }
}

Note that the scala class c4x11s extends a class c4x11j. Since we need a finalizer for this exercise, we implement that finalizer in java. Here's c4x11j.java:

package x;
public class c4x11j {
    public int c4x = 11;
    public void finalize() {
        System.out.println( "Finalizing c4x11j." );
    }
}

One oddity whose explanation I haven't yet looked up is that the scala class cannot access the public member c4x of the java class c4x11j. I probably have to make it into a property, adding at least some kind of get method.

Anyway, Explain the behavior of your program? What, explain why it did not invoke the finalizer? The code in red there gives that away. We still had a live reference to it, right up until the program went away, and Java finalizers aren't really very much like "finally" blocks. This is one of the reasons why Joshua wrote (in David's interpretation) that "finalizers are lousy; avoid them in essentially all cases".

Chapter 4, Exercise 12

See the red line in c4x11. Break our only link to that object by setting our reference to null, and then the finalizer does get invoked. THECLAPP found some other oddities involving inner code blocks and other functions, but none of that was surprising to this old C programmer.
10:36:50 PM   comment/     


  Wednesday 19 May 2004
Chapter 4, Exercises 8-9

Exercise 8 directs us "Create a class without a constructor, and then create an object of that class in main() to verify that the default constructor is automatically synthesized." My response was "Haven't we been doing that already for 5 or 6 exercises?" Then I went to look at the Clapp's version of 4.8, and s/he had written "I've skipped 4.8. It looks pretty trivial."

For completeness, anyway:

Chapter 4, Exercise 8

class c4x8c { Console.println( "A c4x8c object" ) };
object c4x8 {
    def main ( args: Array[String] ) = {
        val obj = new c4x8c;
    }
}

Chapter 4, Exercise 9

class c4x9c {
    def meth1 = {
        meth2( "meth2" );
        this.meth2( "this.meth2" );
    }
    def meth2( s: String ) = {
        Console.println( "Meth2 called as " + s );
    }
}
object c4x9 {
    def main ( args: Array[String] ) = {
        val obj = new c4x9c;
        obj.meth1;
    }
}

11:36:40 PM   comment/     

  Tuesday 18 May 2004
Chapter 4, Exercises 1-2 revisited

The exercise for c4x1 requests: "Create a class with a default constructor (one that takes no arguments) that prints a message. Create an object of this class."

A few days ago, I wrote up Exercises 1-2 of Chapter 4, but still had questions about how to make a default (no-argument) contructor. The answer showed up yesterday on the Scala mailing list: the no-argument constructor is simply the body of the class. Here are the simpler, more java-like solutions to those two exercises.

(The corresponding THECLAPP entries are here and here.)

class c4x1c_deM {
    Console.println( "    ... creating a c4x1c_deM, default ctor." );
}
object c4x1_deM {
    def main ( args: Array[String] ) = {
        Console.println( "Declaring a c4x1c_deM 'o' ..." );
        val o = new c4x1c_deM;
        Console.println( "All done." );
    }
}

C4x2 the exercise: "Add an overloaded constructor to Exercise 1, that takes a String argument and prints it along with your message."

class c4x2c_deM {
    Console.println( "    ... creating a c4x2c_deM, default ctor." );
    def this ( i:Int ) = {
        this();
        Console.println( "c4x2c_deM Int ctor, with argument " + i );
    }
}
object c4x2_deM {
    def main ( args: Array[String] ) = {
        Console.println( "Declaring a plain c4x2c_dem 'o' ..." );
        val o = new c4x2c_deM;
        Console.println( "Declaring a c4x2c_dem 'p' (1) ..." );
        val p = new c4x2c_deM(1);
        Console.println( "All done." );
    }
}

(The "deM" part of the class names is today's date, in my short date-stamp form described here.)
8:32:22 AM   comment/     


  Sunday 16 May 2004
Chapter 4, Exercises 6-7

Since I gave these guys class (object) names with _Dog, you'll have to run them just a little differently from previous exercises. The main point of this pair of exercises is to show a little bit of how Java overloading works. Unfortunately, Scala appears to behave the same way as Java in this instance, which I think is a small language design mistake. The overloading in c4x6_Dog is just fine by me ...

Chapter 4, Exercise 6

package x;
object c4x6_Dog {
    def bark( a: Int ) = { Console.println( "bark!" ); }
    def bark( a: Float ) = { Console.println( "arf!" ); }
    def bark( a: Double ) = { Console.println( "grr!" ); }
    def bark( a: Char ) = { Console.println( "yip!" ); }
    def bark( a: Boolean ) = { Console.println( "bugger off!" ); }
    def main ( args: Array[String] ) = {
        bark(0);
        bark(0.0f);
        bark(0.0d);
        bark('x');
        bark(false);
    }
}

Chapter 4, Exercise 7

... but the overloading in c4x7_Dog should, IMHO, result in a compile time error. There is no version of bark that takes a Float and an Int. It's easy enough (in this case, a single character!) for the programmer to write down explicitly what is meant, so I'm uneasy that there is an int-to-float conversion hidden in there. As the Zen of Python has it, "Explicit is better than implicit".

package x;
object c4x7_Dog {
    def bark( a: Int, b: Float ) = { Console.println( "bark!" ); }
    def bark( a: Float, b: Float ) = { Console.println( "arf!" ); }
    def bark( a: Double ) = { Console.println( "grr!" ); }
    def bark( a: Char ) = { Console.println( "yip!" ); }
    def bark( a: Boolean ) = { Console.println( "bugger off!" ); }
    def main ( args: Array[String] ) = {
        bark(0, 0.0f);
        bark(0.0f, 0);
        bark(0.0d);
        bark('x');
        bark(false);
    }
}

At least Scala refuses to compile the following version (as does java, with a similar java version), because it would require a float-to-int conversion:

c4x7b.scala:11: overloaded method bark of type (scala.Float,scala.Int)scala.Unit (scala.Int,scala.Int)scala.Unit (scala.Double)scala.Unit (scala.Char)scala.Unit (scala.Boolean)scala.Unit cannot be applied to (scala.Int,scala.Float) bark(0, 0.0f);

package x;
object c4x7b_Dog {
    def bark( a: Float, b: Int ) = { Console.println( "arf!" ); }
    def bark( a: Int, b: Int ) = { Console.println( "bark!" ); }
    def bark( a: Double ) = { Console.println( "grr!" ); }
    def bark( a: Char ) = { Console.println( "yip!" ); }
    def bark( a: Boolean ) = { Console.println( "bugger off!" ); }
    def main ( args: Array[String] ) = {
        bark(0.0f, 0);
        bark(0, 0.0f);
        bark(0.0d);
        bark('x');
        bark(false);
    }
}

9:31:56 PM   comment/     

  Friday 14 May 2004
Chapter 4, Exercises 3-5

Note that all three of tonight's exercises use the class c4x2c, which we built yesterday. In order to use it, we must now (for the first time) use a -classpath . argument in the (scalac) compile step.

http://theclapp.blog-city.com/read/11120.htm
http://theclapp.blog-city.com/read/11272.htm
http://theclapp.blog-city.com/read/11276.htm

Chapter 4, Exercise 3

object c4x3 {
    def main ( args: Array[String] ) = {
        val ar = new Array[ c4x2c ]( 10 );
        Console.println( "Note, no talky constructors are called." );
    }
}

Chapter 4, Exercise 4

object c4x4 {
    def main ( args: Array[String] ) = {
        val ar = new Array[ c4x2c ]( 10 );
        Console.println( "Note, no talky constructors are called yet." );
        for (val i <- Iterator.range( 0, ar.length ) ) {
            val s: String = "msg " + i;
            ar(i) = new c4x2c(s);
        }
    }
}

Chapter 4, Exercise 5

object c4x5 {
    def main ( args: Array[String] ) = {
        val ar = new Array[ String ]( 10 );
        for (val i <- Iterator.range( 0, ar.length ) )
            ar(i) = new String( "i = " + i );

        for (val i <- Iterator.range( 0, ar.length ) )
            Console.println( "ar(" + i + ") = " + ar(i) );
    }
}

10:27:23 PM   comment/     
Chapter 4, Exercises 1-2, Thinking in Scala

Chapter 4, Exercise 1

I wonder how one declares ... or even whether one can declare ... and implement a no-argument constructor to do some action (like, say, printing a log message) upon the creating of a c4x1c, without having to do it in an overloaded constructor. For this exercise, I added some extra println's.
class c4x1c {
    def this ( i:Int ) = {
        this();
        Console.println( "    ... creating a c4x1c, with argument " + i );
    }
}
object c4x1 {
    def main ( args: Array[String] ) = {
        Console.println( "Declaring a c4x1c 'o' ..." );
        val o = new c4x1c;
        Console.println( "Declaring a c4x1c 'p' (1) ..." );
        val p = new c4x1c(1);
        Console.println( "Declaring a c4x1c 'q' (2) ..." );
        val q = new c4x1c(2);
        Console.println( "All done." );
    }
}

Chapter 4, Exercise 2

Overloaded constructors are a little weird in Scala. The name is always "this", and the the parser won't accept the definition unless the first thing it does is a call to another constructor. The no-argument constructor is, I gather, the basic one that the compiler generates. I guess that answers the wonder in the first half of this posting.
class c4x2c {
    def this ( i:Int ) = {
        this();
        Console.println( "    ... creating a c4x2c, with int argument " + i );
    }
    def this ( s:String ) = {
        this();
        Console.println( "    ... creating a c4x2c, with String argument '"
                       + s + "'." );
    }
}
object c4x2 {
    def main ( args: Array[String] ) = {
        Console.println( "Declaring a c4x2c 'o' ..." );
        val o = new c4x2c;
        Console.println( "Declaring a c4x2c 'p' (1) ..." );
        val p = new c4x2c(1);
        Console.println( "Declaring a c4x2c 'q' (2) ..." );
        val q = new c4x2c(2);
        Console.println( "Declaring a c4x2c 'r' (Last One) ..." );
        val r = new c4x2c( "Last One" );
        Console.println( "All done." );
    }
}

PS, I talked a bit with Bruce Eckel tonight at the Python BayPIGgies meeting, and told him about this Scala effort here on GIGO, and about THECLAPP series in Java and Lisp, as well as Bill Clementson's catalog of the CLAPP one. I put a brief review of the Python meeting on my zia weblog.
1:24:31 AM   comment/     


  Wednesday 12 May 2004
Chapter 3, Exercise 9, Thinking in Scala

Integer.parseInt is from java.lang.Integer. I guess i could have used the "tfor" loop that I defined here, if I wanted this to look more like Java or more like what the exercise statement was asking for.

object c3x9 {
    def main ( args: Array[String] ) = {
        val limit = Integer.parseInt( args(0) );
        var cand = 2;
        while (cand < limit) {
            var is_prime = true;
            var test = 2;
            while (is_prime  &&  test*test <= cand ) {
                if ( (cand % test) == 0 ) {
                    is_prime= false;
                }
                else {
                    test = test +1;
                }
            } 
            if (is_prime)
                Console.println( cand + " is prime." );
            /*
            else
                Console.println( cand + " is not prime." );
            */ 
            cand = cand +1;
        }
    }
}

8:13:31 AM   comment/     

  Tuesday 11 May 2004
Chapter 3, Exercises 7-8, Thinking in Scala

Here, we finally use an import statement, because I didn't want to say Math.floor(Math.random(...)). Exercise 8 just adds the infinite loop (shown in red here) to the code for exercise 7.

Here are the corresponding THECLAPP entries:

http://theclapp.blog-city.com/read/10083.htm
http://theclapp.blog-city.com/read/10086.htm

package x;
import Math.floor;
import Math.random;
object c3x7_and_8 {
    def main ( args: Array[String] ) = {
        while (true) {
            val fr : Double = (floor(random() * 25.0)); 
            val pivot : Int = fr.asInstanceOf[Int];
            for (val i <- Iterator.range( 0, 25 ) ) {
                val r : Int = (floor(random() * 25)).asInstanceOf[Int];
                Console.println( r +
                     ( if (r < pivot)      " < ";
                       else if (r > pivot) " > ";
                       else                " = "
                     )
                    + pivot );
            }
        }
    }
}

Note that the conversion of Float or Double to Int must be explicit. (That hole in C++ always bugged me.) And I pushed the if-expression into the inside of the println call.
11:43:53 PM   comment/     


  Monday 10 May 2004
Chapter 3, Exercise 6, Thinking in Scala

I made the output from this one a bit more verbose. Hope Radio doesn't mess up the quotings and the backslashes.

object c3x6 {
    def show1 ( ns: String, s: String ) : String =
        ns + " (is \"" + s + "\")";
    def show ( p: String, q: String, opName: String, res: Boolean ) = {
        Console.print( show1( "p", p ) );
        Console.print( " " + opName + " " );
        Console.print( show1( "q", q ) );
        Console.println( "?  " + res );
    }
    def testStringComp ( x: String, y: String ) = {
        show( x, y, "==", x == y );
        show( x, y, "!=", x != y );
        show( x, y, ".equals()", x.equals( y ) );
        // show( x, y, "<", x < y );
    }
    def main ( args: Array[String] ) = {
        testStringComp( "a", "b" );
        testStringComp( "a", "a" );
        testStringComp( "123456", "123" + "456" );
    }
}

I tried a less than, but these strings are java.lang.Strings, so they don't have a less-than method.

Here's the output that I got:

p (is "a") == q (is "b")?  false
p (is "a") != q (is "b")?  true
p (is "a") .equals() q (is "b")?  false
p (is "a") == q (is "a")?  true
p (is "a") != q (is "a")?  false
p (is "a") .equals() q (is "a")?  true
p (is "123456") == q (is "123456")?  true
p (is "123456") != q (is "123456")?  false
p (is "123456") .equals() q (is "123456")?  true

11:41:56 PM   comment/     

  Sunday 9 May 2004
Chapter 3, Exercise 5, Thinking in Scala

For this exercise, the wrinkle is that Scala's "for" has no break statement. We simulate it here, with an exception. The bodies of ifs and whiles are already anonymous nested functions anyway; and that is the kind of thing we are passing as the second ("body") argument to the tfor function.

case class breakEx extends Throwable; 
object c3x5 {
    def break = { throw new breakEx(); } 
    def tfor (iter: Iterator[Int]) (def body: Int => unit): unit = {
        try {
            while( iter.hasNext ) {
                body(iter.next);
            }
        }
        catch { case breakEx => }
    } 
    def main ( args: Array[String] ) = {
        tfor (Iterator.range(1,101) ) { i =>
            if (i == 47) { break; }
            Console.println( i.toString() );
        }
    }
}

This will not satisfy situations where one wants to use the final value of the iterator variable, after the loop completes. A strategy similar to the following should suffice for those cases:

case class breakEx extends Throwable; 
object c3x5n {
    def break = { throw new breakEx(); } 
    def tfor (iter: Iterator[Int]) (def body: Int => unit): unit = {
        try {
            while( iter.hasNext ) {
                body(iter.next);
            }
        }
        catch { case breakEx => }
    } 
    def main ( args: Array[String] ) = {
        var j : Int = _;
        tfor (Iterator.range(1,101) ) { i =>
            if (i == 47) { break; }
            Console.println( i.toString() );
            j = i;
        }
        Console.println( "After the tfor, j is " + j.toString() );
    }
}

5:23:43 PM   comment/     

  Thursday 6 May 2004
Chapter 3, Exercise 4, Thinking in Scala

This exercise is just to show what a Java for loop is like. Now, in Scala, the underlying mechanism is completely different, acting more like a "list comprehension" as in Haskell or Python and involving a translation into some method calls (.filter, .flatMap, .map, et al.). Despite this, the Scala for loop can be made to look pretty innocuous.

package x;
object c3x4 {
    def main ( args : Array[String] ) = 
        for (val i <- Iterator.range(1,101) )
            Console.println( i );
}

As a bonus, here's a definition of a loop construct that I made to look more like the C/C++/Java for loop:

object c3x4_bonus {
    def cFor (def init:unit) (def p: boolean)
             (def incr:unit) (def s: unit): unit =
    {
        init; while(p) { s ; incr }
    }
    def main ( args : Array[String] ) = {
        var i: Int = _;
        cFor (i= 1)(i < 100)(i= i+1) {
            Console.println( i );
        }
    }
}

Foreshadowing: note that the break statement is somewhat troublesome, given the semantics of Scala's for loops.
12:44:13 AM   comment/     


  Wednesday 5 May 2004
Chapter 3, Exercise 3, Thinking in Scala

Today's exercise corresponds to this entry from the Lisp/Java version. Nothing new, though I suppose I should figure out whether "else if" chains work as expected.

package x;
object c3x3 {
    def test ( testval: Int, target: Int ) = {
        var result = 0;
        if(testval > target) {
            result = +1;
        }
        else {
            if(testval < target) { result = -1 }
            else                 { result = 0 }
        }
        result;
    }
    def test2 ( testval: Int, target: Int ) = {
        if (testval > target) { 1 }
        else {
            if (testval < target) { -1 }
            else                  { 0 }
        }
    }
    def main ( args: Array[String] ) = {
        Console.println(test(10, 5));
        Console.println(test(5, 10));
        Console.println(test(5, 5));
        Console.println(test2(10, 5));
        Console.println(test2(5, 10));
        Console.println(test2(5, 5));
    }
}

Hmm; they do seem to, though I'm not posting that version.
9:45:11 PM   comment/     


  Tuesday 4 May 2004
Chapter 3, Exercises 1-2, Thinking in Scala

I think I forgot to mention that I found THECLAPP's version of the Java/Lisp Exercises via this entry in Bill Clementson's excellent (mostly Lisp-related) weblog. Worth reading even if you're not that much of a Lisp fan.

And I didn't like putting the things off in separate files. So that will likely mean fewer blank lines and fewer comments within the code (because Radio thinks they're degenerate URLs), and the occasional < that I forget to escape. Perhaps later I'll go back and fix c2x7-9. And once I've collected a few more, I'll start putting up tarballs of the actual sources. Remember, I'm omitting the "package x;" statements that you might want to use in order that your source directory doesn't get cluttered with .class files.

This entry corresponds to 9920 in THECLAPP.

Chapter 3, Exercise 1

object c3x1 {
    def main ( args : Array[String] ) = {
        val x = 1;
        val y = 2;
        val z = 3;
        var a = x + y - 2/2 + z;
        Console.println( "a is " + a );
        a = x + (y - 2) / (2 + z);
        Console.println( "a is " + a );
    }
}

No comment.

Chapter 3, Exercise 2

object c3x2 {
    def ternary ( i: Int ) = {
        i * (if (i < 10) { 100 } else { 10 } )
    }
    def alternative ( i: Int ) = {
        if (i < 10) { i * 100 }
        else        { i * 10 }
    }
    def main ( args : Array[String] ) = {
        Console.println( ternary( 9 ) );
        Console.println( alternative( 11 ));
    }
}
No need to say "return" explicitly. Do note that I actually had to do something with the values returned from the ternary and alternative methods. The error message that I got when I did not do so was somewhat less than helpful: Exception in thread "main" java.lang.NoSuchMethodError: main

For what it's worth, I did try to define an actual "?" operator, first as a global operator?, then as a member of a new "xBoolean" class. And a new "xInt" class to go with it, and an auxiliary class to keep track of the values of the predicate and the then-part, and that auxiliary class was going to have a "|" operator (I figured that colon was too integrated into Scala syntax to be a good choice here) ... but I guess that'll have to wait until I understand Scala operator overloading a lot better.
11:34:59 PM   comment/     


  Monday 3 May 2004
Chapter 2, Exercises 7-9, Thinking in Scala

I'm trying a new tack. Maybe a little less error prone than trying to slip Scala source code past Radio UserLand's text munger. Unfortunately, UserLand's restrictive filename policy requires that I rename these as foo.scala.txt. Sorry.

Later: scratch that, I didn't like how that worked.

This entry corresponds to http://theclapp.blog-city.com/read/9551.htm . There's nothing very new here ...

Chapter 2, Exercise 7

Print three args from the command line
object c2x7 {
    def main ( args : Array[String] ) = {
        Console.println( "Arg 1: " + args( 0 ) );
        Console.println( "Arg 2: " + args( 1 ) );
        Console.println( "Arg 3: " + args( 2 ) );
    }
}

Chapter 2, Exercise 8

AllTheColorsOfTheRainbow -- not really colors, just member access
class AllTheColorsOfTheRainbow {
    var anIntegerRepresentingColors : Int = _ ;
    def changeTheHueOfTheColor ( newHue : Int ) =
        anIntegerRepresentingColors = newHue;
};
object c2x8 {
    def main ( args : Array[String] ) = {
        var atcotr = new AllTheColorsOfTheRainbow;
        atcotr.changeTheHueOfTheColor( 10 );
    }
}

Chapter 2, Exercise 9

HelloDate (javadoc -> scaladoc)

//: c2x9.scala
/** The first Thinking in Scala example program.
 * Displays a string and today's date.
 *
 * @author Bruce Eckel
 * @author www.BruceEckel.com
 * @translator (into Scala) Doug Landauer
 * @version 2.0
*/
package x;
object HelloDate {
  /** Sole entry point to class &amp; application
   *
   * @param args array of string arguments
   * @return No return value
   * @exception exceptions No exceptions thrown
  */
  def main ( args : Array[String] ) = {
    Console.println("Hello, it's: ");
    Console.println(new java.util.Date());
  }
} //\/:~

Here, we learn that the stuff inside scaladoc comments has to be sorta reasonable xhtml. I had to escape the ampersand. Scaladoc created 9 .html files for this example. I copied the one for the x package here. It does look better in context.

Update: Sorry, it was 54 .html files. I copied some of them up to here. You want to click on package x, Object HelloDate in order to see the part that's relevant to this exercise. Most of the other links won't work because I didn't upload their files.

Note that scaladoc (and, I imagine, javadoc) creates the .html files for the package in the same subdirectory where that package's .class files are generated.
11:31:42 PM   comment/     


  Sunday 2 May 2004
Chapter 2, Exercises 1-6, Thinking in Scala

Here's a start at a Scala version of a selected subset of the examples from Bruce Eckel's Thinking in Java.

In my usage, I typically prepend a "package x;" statement (yep, literally "x") in order to keep the generated .class files out of my current directory. But in future blog entries, I'll likely omit the package lines, until such time as we're really looking at packages. If I get that far.

I've renamed as many classes and objects as made sense to me, to have names that indicate the chapter number and example number. Like the author of THECLAPP, I use zsh. I've never messed with the completion control stuff, and the fact that I put all of my example classes into the "x" package makes these commands less necessary, but here are the zsh commands to make the tab-completion work better for scala:

compctl -g '*.scala' scalac
compctl -g '*.class(:r)' scala
compctl -g '^*.class' vi gvim

I'm currently using Scala version 1.1.1.0 on Mac OS X (10.3, i.e., Panther). Use commands like the following to compile and run the examples:

scalac c2x2.scala
scala  x.c2x2

Here are exercises 1 through 6 from chapter 2, corresponding to the first couple of entries from THECLAPP.

Chapter 2 Example 1

package x;
object c2x1 {
    def main ( args: Array[String] )  = {
        Console.println( "Hello, world" );
    }
}

Note that c2x1 is an object, not a class: From the scala language reference manual, section 5.4.1: Classes in Scala do not have static members; however, an equivalent effect can be achieved by an accompanying object definition.

Chapter 2 Example 2

You could actually give the class (c2x2c here) the same name as the module-level object, but then you couldn't run it as main, because scala appears to look first for a main method in the given class, before it looks for one in the object. Which is weird, since main has to be static and scala classes do not have static members. Anyway, this works for me:
package x;
class c2x2c {  };
object c2x2 {
    def main ( args: Array[String] )  = {
        val x = new c2x2c;
    }
}

Chapter 2 Example 3

The obvious translation is illegal in scala:
c2x3.scala:5: class DataOnly needs to be abstract, since variable i in class DataOnly is not defined (Note that variables need to be initialized to be defined).

To get it to compile, I made the additions shown in red:

package x;
// DataOnly.scala
// chapter 2, exercise 3 
class DataOnly {
    var i : Int = _;
    var f : Float = _;
    var b : Boolean = _;
}
object c2x3 {
    def main ( args : Array[String] ) = {
        var d = new DataOnly;
        d.i = 47;
        d.f = 1.1f;
        d.b = false;
    }
} 

The underscore is a type-specific "default value".

Chapter 2 Example 4

Not really anything new or surprising here, except to note that System.out is forwarded to a shorter and more convenient name in Scala.

package x;
// DataOnly.scala
// chapter 2, exercise 3 
class DataOnly {
    var i : Int = _;
    var f : Float = _;
    var b : Boolean = _;
}
object c2x4 {
    def main ( args : Array[String] ) = {
        var d = new DataOnly;
        d.i = 47;
        d.f = 1.1f;
        d.b = false;
        Console.println("d.i is " + d.i);
        Console.println("d.f is " + d.f);
        Console.println("d.b is " + d.b);
    }
} 

Chapter 2 Example 5

For c2x5, note that the method "storage" does not require {} nor return. Scala is an expression-oriented language. There are still statements, but most of them are declarations (var, val, class, trait, object). Even "if" and "while" are function calls.

Scala could have defined "length" to be a method that would get called without requiring the parentheses. And note that I could have omitted the return type declaration for the "storage" method: scala's type system could infer that from the type of String.length.

class UseStorage {
    def storage ( s : String ) : Int = s.length() * 2;
}
object c2x5 {
    def main ( args : Array[String] ) = {
        val s = new UseStorage( ).storage( args(0) );
        Console.println( "storage for \"" + args(0) + "\" is " + s );
    }
} 
Also note that array access in Scala uses parentheses, not [square] brackets. Brackets in Scala are pretty much restricted to generic types and their instantiations.

Chapter 2 Example 6

Classes in Scala still do not have static members; so this looks a little different. And I took the liberty of printing out the value before and after the incr call. And note that the incr call does not require parentheses.
object StaticTest {
    var i = 47;
    def pri ( s : String ) = {
        Console.print( "StaticTest.i " + s + ": " );
        Console.println( i );
    }
}
object StaticFun {
    def incr = { StaticTest.i = StaticTest.i + 1; }
}
object c2x6 {
    def main ( args : Array[String] ) = {
        StaticTest.pri( "before" );
        StaticFun.incr;
        StaticTest.pri( "after" );
    }
}


Whew. Putting all that into Radio UserLand's HTML-Lite form took longer than I thought it would.
4:06:06 PM   comment/     


  Saturday 1 May 2004
Thinking in Scala

Bill Clementson made a catalog of a weblog called THECLAPP. I suspect that it's an acronym, but haven't puzzled it out. The "CL" part is probably for Common Lisp. The author of that weblog was going through Bruce Eckel's "Thinking in Java" and doing the exercises in both Java and Common Lisp. Maybe I can make the time to do something similar in Scala.

(Cool, turns out the guy is another zsh fan.)
2:51:52 PM   comment/     



Click here to visit the Radio UserLand website. Click to see the XML version of this web page. © Copyright 2007 Doug Landauer .
Last update: 07/2/6; 12:40:12 .
Click here to send an email to the editor of this weblog.