How do you control the visibility of a primary constructor and of a property's setter independently in Kotlin?
answer
- Modifier before the 'constructor' keyword
- private constructor forces a factory
- 'private set' = public read, private write
- Setter visibility cannot exceed property visibility
- Getter visibility isn't independently settable
basics
~20 sPut the visibility keyword before the constructor keyword to restrict a primary constructor, e.g. class C private constructor(). For a property, you can give the setter its own visibility like 'var x: Int = 0; private set' so reads are public but writes are private.
solid answer
~50 sVisibility modifiers attach to more than just classes and functions. For a **primary constructor**, the default visibility is public, but you can restrict it by writing the modifier **before the `constructor` keyword**, which then becomes mandatory: `class Conn private constructor(...)`. This is the idiomatic way to force construction through a factory or `companion object`. For **properties**, the property and its accessors can have different visibilities. You can give the **setter** a narrower visibility than the property using `var x: T = init private set`, producing a publicly readable but privately writable property — a common immutability-from-outside pattern. The getter cannot have a *broader* visibility than the property, and the setter cannot be *more* visible than the property either. You can also annotate the setter with a body and a modifier. These per-element modifiers let you encapsulate mutation while still exposing reads.
code
kotlin · 13 linesclass User private constructor(val id: Long) {
var name: String = ""
private set
companion object {
fun create(id: Long, name: String) = User(id).apply { this.name = name }
}
}
val u = User.create(1, "Ann")
println(u.name) // OK: public getter
// u.name = "Bob" // ERROR: setter is private
// User(1) // ERROR: constructor is privatego deeper
Recognizes the 'private set' syntax for public-read/private-write.
Can write a private primary constructor and explain it forces factory construction.
Knows the setter≤property rule, the mandatory constructor keyword, and combines accessor visibility with custom bodies.
Designs encapsulated state-holders and factory-based APIs using constructor/accessor visibility to lock down mutation paths across module boundaries.
## Visibility applies to more than classes and methods Kotlin lets you attach visibility modifiers to **constructors** and to **property accessors** independently, which is essential for proper encapsulation. ## Primary constructor visibility Normally you write the primary constructor inline with the class header and it's `public`: ```kotlin class Point(val x: Int, val y: Int) // public constructor ``` To restrict it, place the modifier **before the `constructor` keyword** — and note the keyword becomes **required** when you add a modifier or annotation: ```kotlin class Connection private constructor(val url: String) { companion object { fun open(url: String) = Connection(url) // factory can see private ctor } } // Connection("x") // ERROR: constructor is private ``` This enforces a **factory pattern**: outside code must go through `open(...)`, letting you validate, cache, or return subtypes. You can use `internal constructor`, `protected constructor`, etc. the same way. **Secondary constructors** take a modifier the same way: `protected constructor(...)`. ## Property accessor (getter/setter) visibility A `var` has an implicit getter and setter. You can give the **setter** its own, narrower visibility: ```kotlin class Counter { var count: Int = 0 private set // public read, private write fun increment() { count++ } // allowed: inside the class } ``` Outside the class, `counter.count` is readable but `counter.count = 5` is a compile error. This gives **externally-immutable, internally-mutable** state — extremely common for view-model / state-holder design. ### Rules and constraints - The **setter** may be *equal to or narrower* than the property's visibility, never broader. `var x: Int = 0; public set` on a `private var` is illegal. - The **getter cannot** have its own visibility modifier different from the property — only the setter can be restricted independently. (You change read visibility by changing the property's visibility.) - You can combine a modifier with a custom accessor body: `private set(value) { field = value.coerceAtLeast(0) }` (using the `field` backing-field keyword). ## Putting it together ```kotlin class Session internal constructor(token: String) { var lastSeen: Long = 0L internal set // module code can update; consumers read-only } ``` ## Recall - Modifier goes **before** `constructor`; the keyword then becomes mandatory. - `private constructor` forces factory/companion construction. - `var x = ...; private set` = public read, private write. - Setter visibility ≤ property visibility; getter can't be set independently.
- Why does the 'constructor' keyword become mandatory when you add a modifier?The modifier must attach to something; Kotlin requires the explicit constructor keyword so the parser knows the modifier targets the constructor rather than the class.
- Can you make a setter more visible than its property?No. A setter's visibility must be the same as or narrower than the property's; making it broader is a compile error.
- How would you make a property read-only to consumers but writable inside the module?Declare the property public and write 'internal set', so module code can mutate it while external consumers only read.
A 'private set' property is a museum exhibit: everyone can look (get), only staff can rearrange it (set).
saying these in an interview costs you the question
- Forgetting the 'constructor' keyword is required with a modifier
- Claiming you can widen a setter beyond the property's visibility
- Thinking getters take independent visibility modifiers
- Not knowing the companion object can see the private constructor
- Confusing 'private set' with making the whole property private