Default Access Modifier

Scala’s access modifier is different from Java:

  • Java defaults to package internal visibility if you don’t specify any access modifier. Scala, on the other hand, defaults to public.

  • Java provides an all-or-nothing proposition. Either it’s visible to all classes in the current package or it’s not visible to any. Scala gives fine-grained control over visibility.

  • Java’s protected is generous. It includes derived classes in any package plus any class in the current package. Scala’s protected is akin to C++ and C#—only derived classes can access it. However, you can also ask Scala for quite a liberal and flexible interpretation of protected.

  • Finally, Java encapsulation is at the class level. You can access the private fields and methods of any object of a class from within its instance method. This is the default in Scala as well; however, you can customize it to access only within the current instance’s methods, similar to what Ruby provides.

Let’s explore these variations from Java using some examples.

Customizing Access Modifiers

By default, Scala treats classes, fields, and methods as public if you don’t use an access modifier. If you want to make a member private or protected, simply mark it with the respective keyword like this:

FromJavaToScala/Access.scala
 
class​ Microwave {
 
def​ start() = println(​"started"​)
 
def​ stop() = println(​"stopped"​)
 
private​ ​def​ turnTable() = println(​"turning table"​)
 
}
 
val​ microwave = ​new​ Microwave
 
microwave.start() ​// OK

In this code, by default the methods start and stop are public. We can access those two methods on any instance of Microwave. On the other hand, we’ve defined turnTable explicitly as private. We can’t access that method from outside the class. If we try, as in the previous example, we will get this error:

 
Access.scala:9: error: method turnTable in class Microwave cannot be
 
accessed in this.Microwave
 
microwave.turnTable() //ERROR
 
^
 
one error found

Leave out access modifiers for public fields and methods. For other members, make the access as restrictive as desired with an explicit access modifier.

Scala’s Protected

In Scala, protected makes the decorated members visible to the class and its derived classes only. Other classes that belong to the same package, of the defining class, can’t access these members. Furthermore, the derived class can access the protected members only on its own type. Let’s examine these with an example:

FromJavaToScala/Protected.scala
Line 1 
package​ automobiles
class​ Vehicle {
protected​ ​def​ checkEngine() {}
}
class​ Car ​extends​ Vehicle {
def​ start() { checkEngine() ​/*OK*/​ }
def​ tow(car: Car) {
car.checkEngine() ​//OK
10 
}
def​ tow(vehicle: Vehicle) {
vehicle.checkEngine() ​//ERROR
}
}
15 
class​ GasStation {
def​ fillGas(vehicle: Vehicle) {
vehicle.checkEngine() ​//ERROR
}
}

By compiling the code we can see, in the compiler error message, these access controls taking effect:

 
Protected.scala:12: error: method checkEngine in class Vehicle cannot be
 
accessed in automobiles.Vehicle
 
Access to protected method checkEngine not permitted because
 
prefix type automobiles.Vehicle does not conform to
 
class Car in package automobiles where the access take place
 
vehicle.checkEngine() //ERROR
 
^
 
Protected.scala:17: error: method checkEngine in class Vehicle cannot be
 
accessed in automobiles.Vehicle
 
Access to protected method checkEngine not permitted because
 
enclosing class GasStation in package automobiles is not a subclass of
 
class Vehicle in package automobiles where target is defined
 
vehicle.checkEngine() //ERROR
 
^
 
two errors found

In the previous code, checkEngine of Vehicle is protected and is accessible from any instance method of Vehicle. We can access that method from within an instance method, like start, of the derived class Car. We can also access it on an instance of Car from within an instance method, like tow, of Car. However, we can’t access that method on an instance of Vehicle from within Car and also from within another arbitrary class, like GasStation, even if it belongs to the same package as Vehicle. This behavior is different from how Java treats protected access. Scala is a lot more stringent about access to protected members.

Fine-Grained Access Control

On one hand, Scala is more restrictive than Java in how it treats the protected modifier. On the other hand, it gives a far greater flexibility and also fine-grained control over setting access visibility.

You can specify additional parameters for private and protected modifiers. So, instead of simply decorating a member with private, you can decorate it as private[AccessQualifier], where AccessQualifier may be any enclosing class name, an enclosing package name, or this—meaning instance-only visibility.

The qualifier in the access modifier may tell Scala to treat the member as private for all classes except in these cases:

  • If no AccessQualifier is given—this is the default—then the member is accessible only from the current class and its companion object (we’ll look at companion objects in Chapter 4, Working with Objects).

  • If the AccessQualifier is a class name, then the member is accessible from the class, its companion objects, plus the class and the companion objects of the enclosing class whose name is given as the AccessQualifier.

  • If the AccessQualifier is an enclosing package name, then the member is accessible from the class, its companion object, plus within any class nested under the mentioned package.

  • If the AccessQualifier is this, then the access to the member is restricted to the instance and is not visible to other instances of the same class—this is the most restrictive of all the options.

That’s quite a few combinations that can set heads spinning. An example of the fine-grained access control can help make things clear:

FromJavaToScala/FineGrainedAccessControl.scala
Line 1 
package​ society {
package​ professional {
class​ Executive {
private​[professional] ​var​ workDetails = null
private​[society] ​var​ friends = null
private​[​this​] ​var​ secrets = null
def​ help(another : Executive) = {
10 
println(another.workDetails)
println(secrets)
println(another.secrets) ​//ERROR
}
}
15 
class​ Assistant {
def​ assist(anExec: Executive) = {
println(anExec.workDetails)
println(anExec.friends)
20 
}
}
}
package​ social {
25 
class​ Acquaintance {
def​ socialize(person: professional.Executive) {
println(person.friends)
println(person.workDetails) ​// ERROR
}
30 
}
}
}

Compiling the code produces the following errors:

 
FineGrainedAccessControl.scala:12: error: value secrets is not a member of
 
society.professional.Executive
 
println(another.secrets) //ERROR
 
^
 
FineGrainedAccessControl.scala:28: error: variable workDetails in class
 
Executive cannot be accessed in society.professional.Executive
 
println(person.workDetails) // ERROR
 
^
 
two errors found

The example illustrates quite a few Scala nuances. In Scala we can define nested packages, akin to C++ and C# nested namespaces. We can either follow the Java style to define packages—using dots, as in package society.professional;—or use the C++ or C# nested namespace style. If we decide to place multiple small classes belonging to a hierarchy of packages all in one file—again a departure from Java—the latter style is convenient.

In the previous code, we gave visibility for Executive’s private field workDetails to any class within the enclosing package professional. Scala thus permits access to this field from a method of the class Assistant, which is in that package. However, the class Acquaintance from another package can’t touch the field.

For the private field friends, on the other hand, we gave access to any class within the enclosing package society. This gives permission to access the field friends from the class Acquaintance, which is located in a subpackage of society.

The default visibility of private is class level—from an instance method of a class we can access the members decorated as private on any instance of the same class. However, Scala gives a finer control over private and protected with the this qualifier. For instance, in the previous example, since secrets is decorated private[this], instance methods can access this field only on implicit instances, that is, on this instance—that field can’t be accessed on other instances. That’s the reason why we can access secrets but not another.secrets from within the help instance method. Likewise, a field decorated with protected[this] is accessible from within an instance method of a derived class but only on the current instance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.144.6