Java Code Migration where an "andThen" and apply of a function is used


#1

I have the following java code:

 `final Optional<Date> storyDate = extractDate.andThen(toDate).apply(storyFrom);`

I have already asked about this code. The solution there may affect this (I’m not sure). extractDate has been converted to

`private val extractDate = { from:Optional<String> ->
           from.flatMap({ line -> Regex.extractMatch("((\\d{2}-){2}(\\d{4}))", line) }) }`

The converter generates for the given java code generates:

val storyDate = extractDate.andThen(toDate).apply(storyFrom)

storyFrom has been converted to:
val storyFrom: Optional<String> = lines.stream().filter(Predicate<String> { this.storyFrom(it) }).findFirst()

Now, I am aware that andThen is not available in kotlin (I think it should be as it’s used often enough in java code).

I’ve added the following to address the missing andThen (and this seems to have worked)
infix fun <F: (T1)->T2,T1,T2,T3> F.andThen(g: (T2)->T3): (T1)->T3 = { g(this(it)) }

So in my kotlin code:

 `final Optional<Date> storyDate = extractDate.andThen(toDate).apply(storyFrom);`

I get the compile errors…

At the .apply I get

Error:(46, 47) Kotlin: Type inference failed: inline fun T.apply(block: T.() -> Unit): T
cannot be applied to
receiver: (Optional) -> Optional arguments: (Optional<String!>!)

and at the storyFrom I get error:
Error:(46, 53) Kotlin: Type mismatch: inferred type is Optional<String!>! but ((Optional) -> Optional).() -> Unit was expected

as far as I can tell the issue is related to how the apply and the andThen work together…


#2

I would get rid of Optional as soon as possible, and then use Kotlin constructs from then on:

// Inferred type: Date?
val storyDate = storyFrom.orElse(null)?.extractDate()?.toDate()

I could not find it, but it seems like a useful addition to the standard library:

fun <T: Any> Optional<T>.toNullable(): T? = this.orElse(null)

Then you can write:

// Inferred type: Date?
val storyDate = storyFrom.toNullable()?.extractDate()?.toDate()

#3

How do I make this code work? i.e. I get an unresolved reference extractDate()…

How do I hydrate extractDate?


#4

Sorry, I should have mentioned that you also need to convert extractDate and toDate to extension functions of String. If you have to reuse the existing functions written in Java, then my proposed solution is not useful.


#5

This seems to work?

val storyDate = storyFrom.toNullable()?.let(extractDate)?.let (toDate)

I’d prefer not to have the overhead of extension functions - think it’s a little more difficult to read.


#6

I love extension functions, but if you prefer let over extension functions, and you are satisfied with the readability of the resulting code, then use let.

I don’t know exactly what you mean by overhead, but there is probably no difference between using extension functions and the let solution.


#7

I am new to kotlin so I guess shouldn’t be so opinionated yet…

Could you please show me how it would look with extension functions? i.e. how would you define the extension functions?


#8

Something like the following. I have not compiled or tested this:

val DATE_REGEX = Regex("((\\d{2}-){2}(\\d{4}))")
fun String.extractDate() = DATE_REGEX.find(this)?.value
fun String.toDate() = ... // Your implementation here, using "this" for the string to be converted to a date

Though it does help a lot to follow most idioms, I am very pragmatic when it comes to coding styles. If I don’t like how idiomatic code looks, I do it my own way. For example:

  • I never use single letter names for generic type parameters.
  • I never use break or continue, but use a flag indicating whether the loop is done instead.

My advice is to get to know the constructs that Kotlin offers really well, and then use them in the way that you are most comfortable with. Also let go of how things are done in languages you already know. Every language has its own design principles, and writing code according to the design principles of another language usually does not result in good code.