0
0
Kotlinprogramming~15 mins

Properties with val and var in Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - Properties with val and var
What is it?
In Kotlin, properties are variables that belong to classes or objects. They can be declared using val or var. A val property is read-only, meaning once it is set, its value cannot change. A var property is mutable, so its value can be changed anytime after initialization.
Why it matters
Properties with val and var help control how data inside objects can be changed or protected. Without this, it would be hard to keep data safe or predictable, leading to bugs and unexpected behavior. This control makes programs more reliable and easier to understand.
Where it fits
Before learning properties, you should understand basic Kotlin variables and classes. After this, you can learn about custom getters and setters, data classes, and immutability concepts to write safer and cleaner code.
Mental Model
Core Idea
Properties declared with val are like locked boxes you can only read from, while var properties are like open boxes you can put things into or take things out of anytime.
Think of it like...
Imagine you have two jars: one sealed with glue (val) and one with a removable lid (var). You can look inside both, but you can only change the contents of the jar with the removable lid.
┌───────────────┐       ┌───────────────┐
│   val property│       │   var property│
│  (read-only)  │       │  (read-write) │
│  ┌─────────┐  │       │  ┌─────────┐  │
│  │  value  │  │       │  │  value  │  │
│  └─────────┘  │       │  └─────────┘  │
│  cannot change│       │  can change   │
└───────────────┘       └───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding val and var basics
🤔
Concept: Learn the difference between val and var keywords for properties.
In Kotlin, val declares a property that cannot be reassigned after initialization. var declares a property that can be reassigned any number of times. For example: class Person { val name: String = "Alice" // cannot change var age: Int = 30 // can change } Here, name is fixed, age can be updated.
Result
You can read both properties, but only age can be changed after the object is created.
Knowing val means 'fixed after set' and var means 'changeable' is the foundation for controlling data safety in Kotlin.
2
FoundationProperty initialization rules
🤔
Concept: Properties must be initialized before use, either immediately or in constructors.
Kotlin requires all properties to have a value before you use them. You can assign a value when declaring, or inside the constructor: class Car(val brand: String, var speed: Int) { // brand is val, speed is var } val car = Car("Toyota", 0) Here, brand and speed get values when the object is created.
Result
You cannot create a Car without giving brand and speed values first.
Understanding initialization prevents errors where properties have no value and keeps your objects consistent.
3
IntermediateChanging var properties safely
🤔Before reading on: do you think val properties can be changed inside class methods? Commit to your answer.
Concept: Only var properties can be reassigned after initialization, even inside class methods.
Inside a class, you can update var properties but not val. For example: class Counter { var count = 0 fun increment() { count += 1 // allowed } } Trying to change a val property will cause a compile error.
Result
You can increase count, but cannot change val properties once set.
Knowing val properties are truly immutable after set helps avoid accidental changes and bugs.
4
IntermediateCustom getters and setters
🤔Before reading on: do you think val properties can have setters? Commit to your answer.
Concept: Properties can have custom code to run when getting or setting values; val properties cannot have setters.
You can add custom behavior when reading or writing a property: var temperature: Int = 0 get() = field set(value) { if (value >= -50 && value <= 50) field = value } val readonly: Int = 10 get() = field val properties cannot have setters because they cannot change after initialization.
Result
You can control how var properties change, but val properties remain read-only.
Custom accessors let you add rules or calculations, but val enforces no changes, keeping data safe.
5
IntermediateBacking fields and property storage
🤔
Concept: Properties use backing fields to store their values, accessed via 'field' in getters/setters.
When you write custom getters or setters, Kotlin provides a hidden 'field' variable to hold the actual value: var name: String = "" get() = field.toUpperCase() set(value) { field = value.trim() } This 'field' is the real storage behind the property.
Result
You can customize how values are stored and retrieved while keeping the property interface clean.
Understanding backing fields clarifies how properties work internally and how to safely customize behavior.
6
AdvancedImmutable vs mutable properties in data classes
🤔Before reading on: do you think data class properties should be val or var by default? Commit to your answer.
Concept: Data classes often use val for properties to keep objects immutable, improving safety and predictability.
Data classes represent data holders. Using val properties means once created, the data cannot change: data class User(val id: Int, val name: String) If you use var, the data can change, which may cause bugs or unexpected behavior in collections or caches.
Result
Immutable data classes help keep data consistent and thread-safe.
Choosing val or var in data classes affects program safety and design; immutability is often preferred.
7
ExpertHow val properties can still change internally
🤔Before reading on: do you think val properties always guarantee complete immutability? Commit to your answer.
Concept: Val properties prevent reassignment but do not guarantee the object they point to is immutable.
If a val property holds a mutable object, the object's internal state can still change: class Box(val items: MutableList) val box = Box(mutableListOf("apple")) box.items.add("banana") // allowed Here, 'items' cannot point to a new list, but the list itself can change.
Result
Val protects the reference, not the object's internal state.
Understanding this subtlety prevents false assumptions about immutability and helps design safer code.
Under the Hood
Kotlin properties declared with val or var compile down to private fields with public getter methods. Var properties also have setter methods. The compiler generates these accessors automatically unless custom ones are provided. The 'field' keyword inside accessors refers to the backing field storing the actual value. Val properties have no setter generated, enforcing read-only access at runtime.
Why designed this way?
This design balances simplicity and safety. By generating accessors, Kotlin allows properties to behave like fields but with controlled access. Val enforces immutability at the language level, reducing bugs. Custom accessors provide flexibility without losing safety. This approach replaces verbose getter/setter methods common in Java, making code cleaner and less error-prone.
┌───────────────┐
│ Kotlin Class  │
│  Property     │
│  (val/var)    │
└──────┬────────┘
       │
       ▼
┌───────────────┐       ┌───────────────┐
│ Backing Field │◄──────│  Getter       │
│  (private)   │       │  (public)     │
└───────────────┘       └───────────────┘
       ▲                      │
       │                      ▼
┌───────────────┐       ┌───────────────┐
│  Setter       │──────►│  var only     │
│  (public)     │       │  (optional)   │
└───────────────┘       └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does declaring a property as val guarantee the object it points to cannot change internally? Commit to yes or no.
Common Belief:Val properties make the entire object immutable, so nothing inside can change.
Tap to reveal reality
Reality:Val only prevents the property from pointing to a different object; the object's internal state can still be mutable and change.
Why it matters:Assuming full immutability can lead to bugs when mutable objects change unexpectedly, breaking program logic or thread safety.
Quick: Can you add a setter to a val property? Commit to yes or no.
Common Belief:You can add a setter to val properties to control how they change.
Tap to reveal reality
Reality:Val properties cannot have setters because they are read-only after initialization.
Why it matters:Trying to add setters to val properties causes compile errors and confusion about property mutability.
Quick: Are var properties always unsafe to use compared to val? Commit to yes or no.
Common Belief:Var properties are bad because they allow changes and cause bugs.
Tap to reveal reality
Reality:Var properties are necessary when data must change; using them carefully with validation and encapsulation keeps code safe.
Why it matters:Avoiding var entirely limits program flexibility and can lead to awkward or inefficient designs.
Quick: Does Kotlin treat val and var properties exactly like Java fields? Commit to yes or no.
Common Belief:Val and var are just like Java fields with no difference.
Tap to reveal reality
Reality:Kotlin properties compile to private fields with generated getters/setters, providing controlled access unlike Java fields.
Why it matters:Misunderstanding this leads to incorrect assumptions about property access and encapsulation.
Expert Zone
1
Val properties guarantee reference immutability but not deep immutability; understanding this helps design truly immutable data structures.
2
Custom getters and setters can add logic without changing the property interface, enabling lazy loading or validation transparently.
3
Backing fields are only available inside property accessors; trying to use 'field' elsewhere causes errors, which is a subtle Kotlin rule.
When NOT to use
Avoid using var properties when you want to guarantee immutability and thread safety; prefer val with immutable types or data classes. Use var only when state changes are necessary and controlled. For complex state management, consider using immutable data patterns or libraries.
Production Patterns
In production Kotlin code, val is preferred for most properties to ensure immutability and safer concurrency. Var is used for mutable state like counters, caches, or UI state. Custom accessors implement validation, lazy initialization, or computed properties. Data classes use val to represent fixed data snapshots.
Connections
Immutable Data Structures
Properties with val support building immutable data structures by preventing reassignment.
Understanding val helps grasp how immutable data structures maintain consistent state without accidental changes.
Encapsulation in Object-Oriented Programming
Kotlin properties with val and var provide controlled access to data, a core part of encapsulation.
Knowing how val and var control access deepens understanding of encapsulation principles and data hiding.
Functional Programming
Val properties align with functional programming's emphasis on immutability and pure functions.
Recognizing val as a tool for immutability bridges Kotlin's object-oriented style with functional programming concepts.
Common Pitfalls
#1Trying to reassign a val property after initialization.
Wrong approach:class Person { val name = "Alice" fun changeName() { name = "Bob" // error: val cannot be reassigned } }
Correct approach:class Person { var name = "Alice" fun changeName() { name = "Bob" // allowed } }
Root cause:Confusing val as a variable that can change rather than a read-only property.
#2Assuming val properties make the entire object immutable.
Wrong approach:class Box(val items: MutableList) val box = Box(mutableListOf("apple")) box.items.add("banana") // allowed, unexpected mutation
Correct approach:class Box(val items: List) // use immutable List val box = Box(listOf("apple")) // items cannot be changed
Root cause:Not distinguishing between reference immutability (val) and object immutability.
#3Adding a setter to a val property.
Wrong approach:class Example { val number: Int = 5 set(value) { field = value } // error: val cannot have setter }
Correct approach:class Example { var number: Int = 5 set(value) { field = value } // allowed }
Root cause:Misunderstanding that val means no setter allowed.
Key Takeaways
In Kotlin, val properties are read-only after initialization, while var properties can be changed anytime.
Val properties protect the reference from reassignment but do not guarantee the object's internal state is immutable.
Custom getters and setters allow adding logic when accessing or modifying var properties, but val properties cannot have setters.
Choosing between val and var affects program safety, design, and how data changes over time.
Understanding backing fields and property accessors clarifies how Kotlin manages property storage and access behind the scenes.