What is the idiomatic way in Kotlin of a doing a "...
# announcements
a
What is the idiomatic way in Kotlin of a doing a "mapping" of one object into another one. e.g. from
User(firstName: String, lastName: String, age: Int)
to
UserEntity(name: String, age: Int)
. I found that using a scope function is very useful but I don't know which would be the best. The pros and cons are as follows: •
let
seems as natural choice since it returns lambda result but having to repeat
it
for every property feels a little redundant, e.g.
user.let { UserEntity(it.firstName + it.lastName, it.age)}
run
allows to eliminate
it
from the above example but
run
looks awkward as a mapping function, e.g.
user.run { UserEntity(firstName + lastName, age)}
with
also seems a viable option, e.g.
with(user) { UserEntity(firstName + lastName, age)}
but I'm not sure if this is intended usage of
with
function, in Kotlin docs it is described as a function which lambda result should not be returned or as way to introduce a helper object (https://kotlinlang.org/docs/reference/scope-functions.html), so I'm not sure
w
I tend to create an extension function on the User to map it to appropriate class:
fun User.toEntity() = UserEntity(firstName + lastName, age)
and then write
let(User::toEntity)
. This way I feel I get the best of two worlds
👏 3
8
👍 3
s
Lukasz answer is great. But if you're wondering about these scope functions in general, you may find my Medium post interesting 😀 https://link.medium.com/41VEo8lO1Z
👍 1
a
thanks, if I understood the article correctly, you suggest to use
run
in my case:
Use ‘run’ for transforming objects
, however I find
run
method name not really intuitive. In some other languages you have
map
method name and it sounds much better to me. I think I'll give extension method a try.
r
map
is a collection operation, doesn’t make sense for a single object to me
a
function
map
of collection takes as argument a method for transforming single element of type T to single element of type R, so I'd say it works on single element.
s
Often,
map
is used to map a container-of-
T
to a container-of-
R
and the container can be a
List<T>
, and
Optional<T>
, a
Result<E, T>
, etc. Having a
map
on a ‘naked’/unwrapped type, looks a bit off 🙂 .
a
ok, fair argument, but how does look
run
on single element?
s
I usually don’t use those scoped functions (run/let/etc) for a simple transformation, unless I have code that uses function-composition (e.g. pass a lambda that does
(T) -> R
). I just write an extension function/property that is named
toXXXX
or
asXXXX
s
ah, the art of naming things! How about
convert
?!
😄 1
though I have to say that I like @streetsofboston ’s
toXXX
a lot in the light of the well known
toString
method.
b
Just adding that the convention in the standard library is also
toXXX
and
asXXX
. The difference between the 2 is that
toXXX
creates a new independent object while
asXXX
only creates a view on the original (modifications are applied both 2 the original and the view no matter which is changed)
m
Why would you type
let(User::toEntity)
instead of just
.toEntity()
?
😄 1
👍 1
r
You wouldn’t I think, but I would write
map(User::toEntity)
instead of
map { it.toEntity() }
all the time so I suppose they got confused maybe?
m
for map it makes sense
but not for let
w
Good point, I was thinking about
map
, since that’s what I usually do 🙂
m
i created an extension function on Any called mapElement 😛