Scala Tutorial

Basics

Control Statements

OOP Concepts

Parameterized - Type

Exceptions

Scala Annotation

Methods

String

Scala Packages

Scala Trait

Collections

Scala Options

Miscellaneous Topics

Access Modifiers in Scala

In Scala, access modifiers control the visibility of classes, objects, traits, methods, and fields. They determine from where members can be accessed or modified. Scala provides a more flexible system than many other languages. Here's a breakdown:

  1. Public: By default, members are public. There's no public keyword in Scala; you just leave off an access modifier.

    class Person {
      val name = "John"  // This is public by default
    }
    
  2. Private: Members marked private are visible only inside the class or object that contains them.

    class Person {
      private val secret = "This is a secret"
    }
    

    An interesting aspect of Scala's private is that when it's used inside an object, it is only accessible within that specific object, not instances of a companion class or even subclasses.

  3. Protected: Members marked protected are accessible from subclasses. Unlike Java, protected in Scala does not allow access from any class in the same package.

    class Animal {
      protected val sound = "sound"
    }
    
    class Dog extends Animal {
      def makeSound(): String = sound
    }
    
  4. Private[this]: This is an even more restricted version of private. A member with this modifier can be accessed only from the current object instance, not from other instances of the same class.

    class Example {
      private[this] val secret = "Super Secret"
      def isSameAs(x: Example): Boolean = {
        // secret == x.secret  // This would be an error
        true
      }
    }
    
  5. Private[Scope]: Scala provides a way to make members visible to specific scopes by using private[Scope] where Scope is a package, class, or singleton object. This provides a controlled widening of the accessibility of the member.

    package foo {
      class Example {
        private[foo] val data = "Accessible within foo package"
      }
    }
    
  6. Protected[Scope]: Similarly, protected can also be qualified with a scope. It means the member is protected but still accessible from the specified scope.

    package bar {
      class Example {
        protected[bar] val info = "Protected within bar package"
      }
    }
    

In conclusion, Scala provides a rich set of access modifiers, allowing for fine-grained control over visibility and accessibility. Proper use of these can help in achieving strong encapsulation, making your code safer and more modular.

  1. Public and private access in Scala:

    • Description: Public access is the default access level in Scala. Members are accessible from anywhere. Private access restricts access to within the same class or object.
    • Code Example:
      class MyClass {
        val publicMember: Int = 42
        private val privateMember: String = "Secret"
      }
      
  2. Scala protected access modifier:

    • Description: The protected modifier restricts access to the same class, subclasses, and companion objects.
    • Code Example:
      class MyBaseClass {
        protected val protectedMember: Double = 3.14
      }
      
      class MyDerivedClass extends MyBaseClass {
        def accessProtectedMember(): Double = protectedMember
      }
      
  3. Package-private access in Scala:

    • Description: Package-private access is achieved by not specifying any access modifier. Members are accessible within the same package.
    • Code Example:
      package mypackage
      
      class MyPackageClass {
        // Package-private access
        val packagePrivateMember: String = "Hello"
      }
      
  4. Access modifiers in Scala classes:

    • Description: Access modifiers (public, private, protected) can be used with class members to control their visibility and access.
    • Code Example:
      class MyClass {
        val publicMember: Int = 42
        private val privateMember: String = "Secret"
        protected val protectedMember: Double = 3.14
      }
      
  5. Scala object-private access:

    • Description: Object-private access restricts access to the same instance of the same class or object.
    • Code Example:
      class MyClass {
        private[this] val objectPrivateMember: Boolean = true
      
        def isEqual(other: MyClass): Boolean = {
          // Can access other's objectPrivateMember
          this.objectPrivateMember == other.objectPrivateMember
        }
      }
      
  6. Companion objects and access control in Scala:

    • Description: Companion objects share access with their corresponding classes. They can access private members of each other.
    • Code Example:
      class MyClass {
        private val privateMember: String = "Secret"
      }
      
      object MyClass {
        def accessPrivateMember(instance: MyClass): String = instance.privateMember
      }
      
  7. Scala access modifiers and inheritance:

    • Description: Access modifiers apply to inherited members. Subclasses cannot reduce the visibility of inherited members but can increase it.
    • Code Example:
      class MyBaseClass {
        protected val protectedMember: Double = 3.14
      }
      
      class MyDerivedClass extends MyBaseClass {
        def accessProtectedMember(): Double = protectedMember
      }
      
  8. Scoping and visibility in Scala:

    • Description: Scoping determines where a name is valid, and visibility controls whether a member is accessible from a specific location.
    • Code Example:
      class ScopeExample {
        // Public member accessible outside the class
        val publicMember: Int = 42
      
        def doSomething(): Unit = {
          // Scope: Accessible within the method
          val localVar: String = "Local"
          println(localVar)
        }
      }
      
  9. Encapsulation in Scala with access modifiers:

    • Description: Encapsulation is achieved by using access modifiers to control the visibility of members and implementation details.
    • Code Example:
      class EncapsulationExample {
        private var data: String = "Sensitive"
      
        def getData(): String = data
      
        def setData(newData: String): Unit = {
          // Encapsulation: Validate or manipulate data before updating
          if (newData.length > 5) {
            data = newData
          }
        }
      }
      
  10. Access modifiers in Scala traits:

    • Description: Traits can also use access modifiers to control the visibility of their members when mixed into classes.
    • Code Example:
      trait MyTrait {
        protected val protectedMember: Double = 3.14
      }
      
      class MyClass extends MyTrait {
        def accessProtectedMember(): Double = protectedMember
      }
      
  11. Scala access control hierarchy:

    • Description: The access control hierarchy in Scala includes public, protected, package-private, and private access levels, each with its own scope.
    • Code Example:
      // Public access (default)
      class PublicClass {
        val publicMember: Int = 42
      }
      
      // Protected access
      class ProtectedClass {
        protected val protectedMember: Double = 3.14
      }
      
      // Package-private access
      package mypackage {
        class PackagePrivateClass {
          val packagePrivateMember: String = "Hello"
        }
      }
      
      // Private access
      class PrivateClass {
        private val privateMember: String = "Secret"
      }
      
  12. Abstract members and access modifiers in Scala:

    • Description: Abstract members (methods or fields) in abstract classes or traits can have access modifiers, controlling their visibility in subclasses.
    • Code Example:
      abstract class MyAbstractClass {
        protected def abstractMethod(): Unit
      }
      
      class MyConcreteClass extends MyAbstractClass {
        protected def abstractMethod(): Unit = {
          // Implementation in the subclass
        }
      }