https://kotlinlang.org logo
Title
l

LastExceed

08/23/2019, 12:11 PM
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

Marko Mitic

08/23/2019, 12:12 PM
if (x!=null) y=x
😄
2
😄 1
l

LastExceed

08/23/2019, 12:12 PM
pls
m

Marko Mitic

08/23/2019, 12:12 PM
y= x?:y
🇳🇴 1
1
m

Marc Knaup

08/23/2019, 12:13 PM
x?.let { y = it }
✔️ 2
l

LastExceed

08/23/2019, 12:13 PM
thanks
s

Shawn

08/23/2019, 12:14 PM
I personally wouldn’t recommend that as a good use of the safe-navigation operator (or the elvis operator either)
l

LastExceed

08/23/2019, 12:14 PM
should i just keep it as is?
s

Shawn

08/23/2019, 12:14 PM
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

Marc Knaup

08/23/2019, 12:15 PM
Best approach depends on the context
m

Marko Mitic

08/23/2019, 12:16 PM
Try to cut down `var`s and assignments as much as possible for clean, functional and thread-safe code
s

Shawn

08/23/2019, 12:16 PM
that’s also true
m

Marko Mitic

08/23/2019, 12:17 PM
val z = x ?: y
might be better option
1
m

Marc Knaup

08/23/2019, 12:18 PM
The approach with
if
won't even work (reliably) in cases where a smart cast is not possible.
l

LastExceed

08/23/2019, 12:21 PM
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
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

Marc Knaup

08/23/2019, 12:23 PM
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

LastExceed

08/23/2019, 12:24 PM
i could do that, but i don't see the benefit since i have to nullcheck the newer data either way
m

Marc Knaup

08/23/2019, 12:24 PM
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

LastExceed

08/23/2019, 12:25 PM
ah yes that makes sense
guess im gonna do that then, ty
m

Marc Knaup

08/23/2019, 12:26 PM
data.copy(
   position = newData.position ?: data.position,
  ...
)
Or wrapped in an extension function even shorter.
l

LastExceed

08/23/2019, 12:27 PM
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

LastExceed

08/23/2019, 12:38 PM
ok i just read the docs you linked, it was very helpful! kotlin really is an amazing language
:kotlin-flag: 2
m

Marc Knaup

08/23/2019, 12:38 PM
It is :)
l

LastExceed

08/23/2019, 1:19 PM
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

karelpeeters

08/23/2019, 1:20 PM
Write a factory function instead.
👆 3
In general, constructors really shouldn't do anything.
s

Sinan Kozak

08/23/2019, 1:21 PM
write and invoke method in companion object
TBH i dont suggest that but in kotlin that does the trick
l

LastExceed

08/23/2019, 1:21 PM
factory means a function that creates and returns an object?
:yes: 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

Marc Knaup

08/23/2019, 1:32 PM
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

LastExceed

08/23/2019, 1:34 PM
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

Marc Knaup

08/23/2019, 1:39 PM
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

LastExceed

08/23/2019, 1:51 PM
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

Marc Knaup

08/23/2019, 1:52 PM
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:
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)