Is there a consise way to skip an assignment if a ...
# announcements
a
Is there a consise way to skip an assignment if a value is null? e.g.
Copy code
// fun src.loadString(fieldName: String): String? {...}


dstBuilder.fieldA = src.loadString("aField") ?: throw Exeption("Field A is not present") 
// Instead of throwing, i want to leave dst.fieldA unset - skip this line and move to next.
🧵 1
j
Wrap with a if block?
t
Clarifying.. you don't want to overwrite an existing value if the
src
value for
aField
is null?
l
If you want to write that in a short way, how about using let() ?
src.loadString("test")?.let { loadedString -> dst.fieldA = loadedString}
The code inside let() will only be called if loadString is not null, otherwise dst.fieldA remains unchanged
1
a
that's it, thanks Lars
Cleaning up someone elses protobuf code, there's like 25 fields with corresponding if statments. Looks a bit hairy 😅
g
You can do something like
src.loadString("aField")?.let(dstBuilder::fieldA::set)
Not sure how recommended it is
t
Just be aware that you're changing the semantics. There could be downstream implications because the previous code would
throw
on a missing field - now you're getting stale or missing data instead. Downstream code may assume that new values have been loaded. Yeah, the code maybe prettier, but it's not equivalent.
👍 1
a
yeah sorry existing code does not throw. It looks like
Copy code
if(source.hasProperty("name-A") builder.fieldA = source.getProperty("name-A")
if(source.hasProperty("name-b") builder.fieldA = source.getProperty("name-b")
// (...)
t
ah, gotcha
s
or
src.loadString("aField")?.let { dst.fieldA = it }
t
we discourage using the implicit parameter in our code because it causes readability problems.
d
Refactor
source.hasProperty("name-b")
in a variable
newB
and keep the assigment in the
ìf
. In my opinion that is more clear than using
let
. At least I would have to think a bit longer about the code when its using the
let
. But not a fan of
?.let
in general
Also a possibility would be
dstBuilder.fieldA = src.loadString("aField") ?: dstBuilder.fieldA
But of course then you repeat
dstBuilder.fieldA
o
@Daniel What are your reservations regarding the use of
?.let
? I am a huge fan of using
?.let
in single expression functions, like the following ORM type converter:
Copy code
fun toBigDecimal(bd: String?): BigDecimal? = bd?.let(::BigDecimal)
d
Lots of it is personal opinion. I for example would need to think really hard about
bd?.let(::BigDecimal)
when I see it (and when the function is not so nicely named. Second is that introduces
it
which is more often than not kept as a name. Don't get me wrong.
?.let
is perfectly fine when used sparsely. But I have seen code when lets where used inside lets and all without renaming
it
. You don't need code obfuscation then! Thats why I always prefer:
Copy code
if(xyz == null) return

doStruff with xyz
When its possible. Keeps things flat and for me its immedeately clear what is happening at first glance
s
I only use
it
if the logic is short and sweet, like in the example above. If it becomes more complicated, and always when nesting, I will give it a describing name.
b
I suppose this is an option that might work for you but I'm not a huge fan (oops, have just seen this has already been suggested)
Copy code
dstBuilder.fieldA = src.loadString("aField") ?: dstBuilder.fieldA
I'd probably stick with something like this as others have suggested.
Copy code
src.loadString("aField")?.let { field -> 
    dstBuilder.fieldA = field
}