Visibility

Application elements such as classes, functions and variables can have varying visibilities, which describes how accessible they are to other areas of the application. Some elements have restricted visibility, and can only be accessed by a certain block of code or parent class/function, while other elements have more public visibility and can be accessed from elsewhere in the application.

Public visibility

By default, most components for applications built using languages such as Java or Kotlin will have public visibility. Public code is accessible throughout the code base. For example, the below Kotlin code demonstrates how to write a public function explicitly and implicitly:

// A function with explicit public visibility
public fun publicFunction() {
    println("I'm a public function")
}

// Functions have public visibility by default
fun anotherPublicFunction() {
    println("I'm another public function")
}

fun main(args: Array<String>) {
	// Prints: I'm a public function
	publicFunction()
    
    // Prints: I'm another public function
    anotherPublicFunction()
}

Internal visibility

Programming languages such as Kotlin support internal visibility modifiers. Code labelled as internal will be accessible only within a given module (a module is a collection of related code files).

// A function that can be called from anywhere within its parent module
internal fun internalFunction() {
    println("I'm an internal function")
}

Protected visibility

Elements assigned protected visibility are accessible within their enclosing class and all subclasses. For example, in the below code, the Person class contains a protected property called passportNumber. The passportNumber property can be accessed by the SecretAgent class because the SecretAgent class is a subclass of the Person class; however, the passportNumber property cannot be accessed directly from the main function because the main function is external to the Person class.

import kotlin.random.Random

open class Person(name: String) {
    protected var passportNumber: String? = null
}

class SecretAgent(name: String): Person(name) {
    init {
        // Generates a random String e.g. James5647283
        this.passportNumber = name + Random.nextInt(1000000, 9999999)
    }
    
    fun requestPassportNumber(isTrusted: Boolean) {
        if (isTrusted) println(passportNumber)
        else println("That information is classified")
    }
}

fun main(args: Array<String>) {
	val agent = SecretAgent("James")
    
    // Will throw an error because passportNumber is protected
    // and we are attempting to access it from outside the
    // class/its subclasses.
    println(agent.passportNumber)
    
    // Prints: {agent.passportNumber}
    // This method works because the SecretAgent class is retrieving the
    // passportNumber field, and the SecretAgent class is a subclass of 
    // the Person class.
    agent.requestPassportNumber(true)
}

Private visibility

Elements assigned private visibility will only be accessible to the class or file in which they are defined. External classes, subclasses and other files will not be able to access private data from another class or file.

class Person(name: String) {
	// The passportNumber property is only accessible to the Person class
    private var passportNumber: String? = null
	
	init {
        // Generates a random String e.g. James5647283
        this.passportNumber = name + Random.nextInt(1000000, 9999999)
    }
}