``` if (x != null) { y = x } ``` is there a sh...
# announcements
l
Copy code
if (x != null) {
    y = x
}
is there a shorter way to do this? I recall there being some way by using the
?
operator but im not sure if that was in kotlin or another language
m
if (x!=null) y=x
😄
😄 1
2
l
pls
m
y= x?:y
1
🚫 1
m
x?.let { y = it }
✔️ 2
l
thanks
s
I personally wouldn’t recommend that as a good use of the safe-navigation operator (or the elvis operator either)
l
should i just keep it as is?
s
there’s nothing wrong with a simple null-check every now and again, especially when it comes to, like, assignments or side-effecty code
m
Best approach depends on the context
m
Try to cut down `var`s and assignments as much as possible for clean, functional and thread-safe code
s
that’s also true
m
val z = x ?: y
might be better option
1
m
The approach with
if
won't even work (reliably) in cases where a smart cast is not possible.
l
i have 2 objects of a data class that contains lots of nullables (character update packet in a game server that doesn't always contain every information) i keep the first packet i receive to store the current character data (position ect) and want to update it everytime i get a new packet, so i gotta do this operation for every information the packet might contain, every time i receive a new packet looks somewhat like this
Copy code
oldCharacterData.Update(newCharacterData)

fun CharacterData.Update(newData: CharacterData) {
    if (newData.position != null) {
        this.position = newData.position
    }
    //the same code for all 47 fields
}
i figured since i need to do it 47 times in a row it'd be nice to be able to do it in a 1liner
m
Why do you update a data class instance rather than creating a new one containing the data merged from the precious one and the update?
👆 1
l
i could do that, but i don't see the benefit since i have to nullcheck the newer data either way
m
Then you could use
.copy
and the approach of Marko, on line per property.
It's not just about the null checks, it's about immutability.
l
ah yes that makes sense
guess im gonna do that then, ty
m
Copy code
data.copy(
   position = newData.position ?: data.position,
  ...
)
Or wrapped in an extension function even shorter.
l
what exactly does the
.copy
do here?
You could also use the constructor instead of copy if you change all properties.
If you know at the point where you receive the data which properties you need to change you could copy the data instance with only these properties specified.
l
ok i just read the docs you linked, it was very helpful! kotlin really is an amazing language
K 2
m
It is :)
l
is there any way to execute a secondary constructor BEFORE the primary constructor? i use a secondary constructor to read the data from stream, but that only works when all the fields are mutable, which is otherwise unnecessary
k
Write a factory function instead.
👆 3
In general, constructors really shouldn't do anything.
s
write and invoke method in companion object
TBH i dont suggest that but in kotlin that does the trick
l
factory means a function that creates and returns an object?
👌 2
it just occurred to me, isn't immutability in this case implying a performance overhead as i have to create a whole new object (compared to changing a value inside that object when using mutability) everytime i change something? or is
.copy
optimized enough to not bother about that?
m
It will always cause an allocation. In most cases however thinking about allocations is just over-thinking of micro-optimizations. Unless the code is called at a high frequency and super performance critical, safe code which is easy to reason about should be of much higher priority.
🎖️ 1
l
position updates are sent about 20 times per second per player, does that qualify as "high frequency" or is it negligible?
i guess if performance was that important i'd be writing C++
m
In that case I’d recommend to finish the implementation first with a safe & idiomatic approach and have automated testing set up. Then if you see that performance is really a problem start measuring timings and then start optimizing.
l
Why do you update a data class instance rather than creating a new one containing the data merged from the precious one and the update?
Then you could use
.copy
and the approach of Marko, on line per property
isnt this in the end be the same as just creating a new object manually since i have to pass a value for every property to .copy (either the new value or the old if the new is null) ?
i get that the idea of
.copy
is precisely not having to pass the old value again, but wouldnt marko's approach be doing just that?
m
Yeah, that’s why I said you could also just use the constructor.
.copy()
is most helpful if you only need to change some of the properties. I don’t know how your relevant code works so I don’t know what case makes more sense for you 🙂
pseudocode example:
Copy code
data class Data(val a: A? = null, val b: B? = null)

received = Data()
…
for each message:
   when message
      is A -> received = received.copy(a=message)
      is B -> received = received.copy(b=message)