More Scala for busy Java programmers
Visibility
private - Outer classes cannot see the private methods in inner classes. "Java would permit both accesses" [1]
protected - "In Scala, a protected member is only accessible from subclasses of the class in which it is defined. In Java, such accesses are also possible from classes in the same package." [1]
You can also qualify the access modifier keywords with a scope. For example:
package com.phenry.scala.subpackage
class MyVisibility {
protected[MyVisibility] def printSomething = {
println("Something has been printed :)")
}
}
object MyVisibility {
def main(args : Array[String]) = {
def app = new MyVisibility()
app.printSomething
}
}
Note, in this case, the protected method can only be called from an object called MyVisibility
as protected[MyVisibility] is basically the same as private.
But we can also qualify with packages. Let's change that listing slightly:
protected[subpackage] def printSomething = { ... }
.
.
object MyVisibilityXXX {
def main(args : Array[String]) = {
def app = new MyVisibility()
app.printSomething // < compiles!
}
}
Now anything in the package subpackage can access our function, including our object with the new name MyVisibilityXXX.
The visibility is possible for anything beneath the restriction. For instance:
package society {
package professional {
import society.professional.elite.Illuminati
class Executive {
private[professional] var workDetails = null
def help(illuminati : Illuminati): Unit = {
// DOES NOT COMPILE:
println(illuminati.topSecret) // <-- WRONG
}
}
package elite {
class Illuminati {
protected[elite] val topSecret = null;
def help(executive : Executive): Unit = {
println(executive.workDetails)
}
}
}
}
}
So, an Illuminati can see an Executive's workDetails by virtue of being one package further down. However, an Executive cannot see an Illuminati's top secrets.
This is different to Java where the hierarchy of packages makes no difference to the access modifiers.
Scope can even be restricted to this object (see here).
But Scala is clever enough that if we create another package called elite but in a different part of the namespace tree, it won't allow it access to the first:
package society {
package professional {
.
.
package other {
package elite {
class OtherIlluminati {
def otherHelp(illuminati : Illuminati) = {
// "Symbol topSecret is inaccessible from this place"
println(illuminati.topSecret) // <-- WRONG. does not compile
}
}
}
}
package elite {
class Illuminati {
protected[elite] val topSecret = null;
.
.
Shadowing
Types, passing methods and partial application
Say we have two functions that encode data and we expect the input and output to be the same. The test then becomes an ideal candidate for passing functions, that is we, we can write a test function that takes either function, applies the input and checks the output. What does the type of this functions parameter look like?
Say, this is one of the methods we want to pass:
def canBePartiallyApplied(count : Int)(f : Int => Int) : Unit = {...}
to a function. The called function would look something like this:
def fnTakingFnThatCanBePartiallyApplied(f : (Int, (Int) => Int) => Unit) = {...}
and we'd call it so:
fnTakingFnThatCanBePartiallyApplied(app.canBePartiallyApplied(_)(_))
So, the testing function takes a function that has parameters of Int and another function that takes an Int and returns an Int. Phew.
If we partially applied our function, so:
def partiallyApplied = canBePartiallyApplied(3)(_)
We could not longer pass partiallyApplied to our test method. It's type is not the same. We've dropped the first Int type, leaving just an argument that is a function taking and Int and returning an Int. The kind of function we could pass this too would look something like:
def fnTakingPartiallyApplied(f : (Int => Int) => Unit) = {...}
[1] Programming in Scala, Odersky.
Visibility
private - Outer classes cannot see the private methods in inner classes. "Java would permit both accesses" [1]
protected - "In Scala, a protected member is only accessible from subclasses of the class in which it is defined. In Java, such accesses are also possible from classes in the same package." [1]
You can also qualify the access modifier keywords with a scope. For example:
package com.phenry.scala.subpackage
class MyVisibility {
protected[MyVisibility] def printSomething = {
println("Something has been printed :)")
}
}
object MyVisibility {
def main(args : Array[String]) = {
def app = new MyVisibility()
app.printSomething
}
}
as protected[MyVisibility] is basically the same as private.
But we can also qualify with packages. Let's change that listing slightly:
protected[subpackage] def printSomething = { ... }
.
.
object MyVisibilityXXX {
def main(args : Array[String]) = {
def app = new MyVisibility()
app.printSomething // < compiles!
}
}
The visibility is possible for anything beneath the restriction. For instance:
package society {
package professional {
import society.professional.elite.Illuminati
class Executive {
private[professional] var workDetails = null
def help(illuminati : Illuminati): Unit = {
// DOES NOT COMPILE:
println(illuminati.topSecret) // <-- WRONG
}
}
package elite {
class Illuminati {
protected[elite] val topSecret = null;
def help(executive : Executive): Unit = {
println(executive.workDetails)
}
}
}
}
}
So, an Illuminati can see an Executive's workDetails by virtue of being one package further down. However, an Executive cannot see an Illuminati's top secrets.
This is different to Java where the hierarchy of packages makes no difference to the access modifiers.
Scope can even be restricted to this object (see here).
But Scala is clever enough that if we create another package called elite but in a different part of the namespace tree, it won't allow it access to the first:
package society {
package professional {
.
.
package other {
package elite {
class OtherIlluminati {
def otherHelp(illuminati : Illuminati) = {
// "Symbol topSecret is inaccessible from this place"
println(illuminati.topSecret) // <-- WRONG. does not compile
}
}
}
}
package elite {
class Illuminati {
protected[elite] val topSecret = null;
.
.
Shadowing
If the val keyword means a reference is immutable, why does Scala have a final keyword? Well, fields can be shadowed in Scala like so:
class MyVisibility {
val shadowMe : String = "super class String"
def printShadowMe() = { println(shadowMe) }
}
class MyVisibilitySubClass extends MyVisibility {
override val shadowMe : String = "subclass's String"
}
object MyVisibilityXXX {
def main(args : Array[String]) = {
def appSubclass = new MyVisibilitySubClass()
appSubclass.printShadowMe() // subclass's String
}
}
Using final would prevent this shadowing.class MyVisibility {
val shadowMe : String = "super class String"
def printShadowMe() = { println(shadowMe) }
}
class MyVisibilitySubClass extends MyVisibility {
override val shadowMe : String = "subclass's String"
}
object MyVisibilityXXX {
def main(args : Array[String]) = {
def appSubclass = new MyVisibilitySubClass()
appSubclass.printShadowMe() // subclass's String
}
}
Types, passing methods and partial application
Say we have two functions that encode data and we expect the input and output to be the same. The test then becomes an ideal candidate for passing functions, that is we, we can write a test function that takes either function, applies the input and checks the output. What does the type of this functions parameter look like?
Say, this is one of the methods we want to pass:
def canBePartiallyApplied(count : Int)(f : Int => Int) : Unit = {...}
def fnTakingFnThatCanBePartiallyApplied(f : (Int, (Int) => Int) => Unit) = {...}
fnTakingFnThatCanBePartiallyApplied(app.canBePartiallyApplied(_)(_))
If we partially applied our function, so:
def partiallyApplied = canBePartiallyApplied(3)(_)
def fnTakingPartiallyApplied(f : (Int => Int) => Unit) = {...}
[1] Programming in Scala, Odersky.
Thanks Phil. You are getting me interested in programming than in the medicine I should be doing.
ReplyDeleteDr Egar! Good to hear from you again. Yes, it's an interesting time at the moment in IT. But I didn't realize anybody actually read my blog! I'll have to triple check my facts before I publish from now on...
ReplyDelete