https://kotlinlang.org logo
#server
Title
# server
j

julien lengrand-lambert

07/27/2022, 1:35 PM
Hey folks, I'm looking into data classes and I wanted to verify that
copy
creates shallow, not deep copies. The math checks out for complex types such as lists or other data classes, but not for 'primitives' likes Strings and Enums. Can someone help me clarify this? [Here is a complete example](https://pl.kotl.in/CzsYyKC_l) , but in essence for the given code, I would potentially expect
name
to also be mutated in the copy if data classes were purely shallow. Am I getting this wrong?
Copy code
import java.util.*

enum class WEAPONS{
    AXE, SWORD, WAND, BOW
}

enum class CLASS{
    WIZARD, WARRIOR, PALADIN, THIEF
}

data class Origin(val city: String, var country: String)

data class FantasyHero(var name: String, val weapons: MutableList<WEAPONS>, var heroClass: CLASS?, val origin: Origin = Origin("Utrecht", "The Netherlands"))

fun main(){
    val gandalf = FantasyHero("Gandalf the Grey", mutableListOf(WEAPONS.WAND), CLASS.WIZARD)
    val anotherGandalf = FantasyHero("Gandalf the Grey", mutableListOf(WEAPONS.WAND), CLASS.WIZARD)
    val gandalfCopy = gandalf.copy()
    val betterGandalf = gandalf.copy(name="Gandalf the White")

    println("--------")
    println("Changing the first instance's name")


    gandalf.name = "Gandalf the White"
    println(gandalf.name)
    println(anotherGandalf.name)
    println(gandalfCopy.name)
    println(betterGandalf.name)

    println("--------")
    println("Changing the first instance's class")

    gandalf.heroClass = CLASS.PALADIN
    println(gandalf.heroClass)
    println(anotherGandalf.heroClass)
    println(gandalfCopy.heroClass)
    println(betterGandalf.heroClass)
}

--------
Changing the first instance's name
Gandalf the White
Gandalf the Grey
Gandalf the Grey
Gandalf the White
--------
Changing the first instance's class
PALADIN
WIZARD
WIZARD
WIZARD
s

Sam

07/27/2022, 1:39 PM
This is quite a long example; is there a specific line or part of the example that’s behaving in a way you don’t expect?
Your understanding that
copy
creates shallow copies is correct
l

Larry Meadors

07/27/2022, 1:41 PM
i think this is a terminology issue
j

julien lengrand-lambert

07/27/2022, 1:42 PM
@Sam, much shorter example ->
Copy code
data class Origin(var city: String, var country: String)


fun main(){
    val myHome = Origin("Utrecht",  "the Netherlands")
    val myHomeCopy = myHome.copy()
    
    myHome.city = "Amsterdam"
    println(myHome.city)
    println(myHomeCopy.city)

}
If we are talking about pure shallow copies, I'd expect myHome.city and myHomeCopy.city to print the same value here (since they reference the same location in memory, right?)
l

Larry Meadors

07/27/2022, 1:43 PM
i'd expect to see:
Copy code
Utrecht
Amsterdam
j

julien lengrand-lambert

07/27/2022, 1:43 PM
Except I get Amsterdam, UTrecht
s

Sam

07/27/2022, 1:44 PM
The Kotlin/Java memory model is a bit different from what you’re picturing, I think
j

julien lengrand-lambert

07/27/2022, 1:44 PM
Now, for anything more complex (Lists, other data class, Set, ...), The values do get mutated in the copies as well
s

Sam

07/27/2022, 1:44 PM
Think of it more like a pointer
☝️ 1
l

Larry Meadors

07/27/2022, 1:44 PM
copy creates a new instance with the same top-level (shallow) values
the "values" for a list or set are the references to them
j

julien lengrand-lambert

07/27/2022, 1:45 PM
So, if we do think of it as pointers indeed, how is it that I don't get "Amsterdam, Amsterdam"? I would expect both String pointers to point to the same value ?
s

Sam

07/27/2022, 1:46 PM
References in Kotlin are immutable — if you change a variable you’re pointing it at a new reference, not changing the existing reference
l

Larry Meadors

07/27/2022, 1:47 PM
not a pointer to the copied object, but a pointer to the property
(sam i saying this better than me 🙂)
s

Sam

07/27/2022, 1:52 PM
Copy code
var a = "1"
val b = a
a = "2"
println(b) // "1"
same concept, without the data class
copy
being involved
the reference is always immutable; all you can do is point at a different object reference instead
Nothing you do to
a
can change which object
b
points to
j

julien lengrand-lambert

07/27/2022, 1:53 PM
🧐
Right
Yeah I think I got it. The behaviour will be the same for anything that you can set like this. So enums have the same behaviour
👍 1
Got it, ty
s

Sam

07/27/2022, 1:56 PM
It catches out a a lot of newcomers to Java tbh, I think people who started out on Java don’t always realise how different it is from other languages
People often ask “is Java pass by reference or pass by value”
And the answer is actually “it’s pass by value but the value is a reference” 😂 🤦
💯 5
j

julien lengrand-lambert

07/27/2022, 1:56 PM
oh well, I only have 10 years of experience xD
😄 1
Thanks! Good to come back to the basics sometimes clearly
l

Larry Meadors

07/27/2022, 2:13 PM
@Sam you are only the second java dev i have heard say that (i am the other one) 😄
1
😄 1
“it’s pass by value but the value is a reference” - always always always pass by value 😄
1
c

cedric

07/27/2022, 10:34 PM
Unrelated to your question, @julien lengrand-lambert, but your code has a lot of
var
and mutable list that don't seem necessary.
j

julien lengrand-lambert

07/28/2022, 2:52 PM
Thanks @cedric. you're very correct, it's actually the point. I typically use only vals but use vars explicitely to mutate things around and see the behaviour of those 😊
c

cedric

07/30/2022, 4:35 AM
While I think that
val
and immutable structures are a great default starting point, writing a lot of Rust these past years has made me more comfortable embracing the mutable nature of things as long as the compiler makes sure I'm not writing stupid code 🙂
👀 1
In much the same way that Kotlin has made me more comfortable embracing
null
values
4 Views