Saturday, May 30, 2009

Simple Scala Keyword Parameters

Everything here is mostly intuitive, but I'm putting it here for personal reference. Should be helpful to a lot of people though. There's probably a whole ton of interesting cases I'm leaving out, and I'll try to keep this updated when I think of them. For now I'm covering Default Values, No Default Values, and Overloading. (Note, this doesn't come out until 2.8, I'm working off trunk)

Default Values


  • Define a class that takes two keyword args, name and lives, and provide default values.

    scala> case class Cat(name:String="kitty", lives:Int=9)
    defined class Cat

  • Instantiate the cat providing no arguments.

    scala> new Cat
    res1: Cat = Cat(kitty,9)

  • Instantiate a cat providing both params, unnamed.

    scala> Cat("Java", 1)
    res2: Cat = Cat(Java,1)

  • Instantiate a cat providing just the first param, unnamed.

    scala> Cat("Scala")
    res3: Cat = Cat(Scala,9)

  • Instantiate a cat providing both params, named.

    scala> new Cat(name="newspeak", lives=20)
    res4: Cat = Cat(newspeak,20)

  • Instantiate a cat providing both params in reverse order. (Only works if names the argument names are given.)

    scala> new Cat(lives=20, name="newspeak")
    res5: Cat = Cat(newspeak,20)

  • Instantiate a cat providing the first param, named.

    scala> new Cat(name="newspeak")
    res6: Cat = Cat(newspeak,9)

  • Instantiate a cat providing the second param, named.

    scala> Cat(lives=4)
    res7: Cat = Cat(kitty,4)

  • Instantiate a cat providing the first argument unnamed, and the second argument named!

    scala> new Cat("Lua", lives=1)
    res8: Cat = Cat(Lua,1)

  • Attempt to instantiate a cat providing the first argument named, and the second argument unnamed. You can't do it! After you name a parameter, the parameters that follow must be named.

    scala> new Cat(name="Lua", 1)
    :7: error: positional after named argument.
    new Cat(name="Lua", 1)
    ^

No Default Values


  • Redefine class Cat without supplying default values. This means values must be provided when instantiating a cat (more generically, calling a function).

    scala> case class Cat(name:String, lives:Int)
    defined class Cat

  • Instantiate a cat providing both params, unnamed.

    scala> Cat("Java", 1)
    res9: Cat = Cat(Java,1)

  • Instantiate a cat providing both params, named.

    scala> new Cat(name="Douglas", lives=42)
    res10: Cat = Cat(Douglas,42)

  • Attempt to instantiate a cat, not providing values for the arguments.

    :7: error: not enough arguments for constructor Cat:
    (name: String,lives: Int)Cat, unspecified parameters:
    value name, value lives
    new Cat
    ^

Overloading


  • Redefine the class, overloading the constructor.

    scala> case class Cat(name:String="kitty", lives:Int=9){
    | def this(name:String) = this(name, -54)
    | }

  • Instantiate a cat providing just the first argument, unnamed. Since the compiler does find a method with the exact signature (in this case - one String), it calls it.

    scala> new Cat("Martin")
    res11: Cat = Cat(Martin,-54)

  • Here's a couple of other similar, and interesting cases. First, overload the constructor giving the argument a different name than the one defined in the primary constructor.

    scala> case class Cat(name:String="kitty", lives:Int=9){
    | def this(x:Int) = this("hello", x+99)
    | }
    defined class Cat

  • Instantiate a cat, using the keyword 'lives'. Since the overloading method uses the name x, and x!=lives, and the original constructor uses 'lives', that is the method that is invoked.

    scala> new Cat(lives=8)
    res12: Cat = Cat(kitty,8)

  • Instantiate a cat - same as the String overloading case above.

    scala> new Cat(8)
    res13: Cat = Cat(hello,107)

1 comment:

  1. Thing that i liked most of all about named/optional arguments feature is auto-generated copy method for case classes. It really makes Scala more friendly for functional programming: you can work with immutable objects and still have a convinient way to "modify" them:

    scala> case class Person(firstName: String, lastName: String)

    defined class Person

    scala> val john = Person("John", "Smith")

    john: Person = Person(John,Smith)

    scala> val hisWife = john.copy("Jane")

    hisWife: Person = Person(Jane,Smith)

    scala> val hisSon = john.copy(firstName="George")

    hisSon: Person = Person(George,Smith)

    ReplyDelete