Bart Kleijngeld
02/08/2022, 10:33 AMBart Kleijngeld
02/08/2022, 10:36 AMModel
, and I want to support converting this data to JSON, Avro, and Turtle for instance.
So, similar to the Collections API in Kotlin, it naturally occurred to me to implement toJson
, toAvro
and toTurtle
methods for this.
There is no state kept here, so these are pure functions for all intents and purposes (but of course the source data is this
, instead of a passed in parameter).
Is this a valid approach within FP? If not, then why not, and what would be the way to deal with it here?
ThanksBart Kleijngeld
02/08/2022, 10:41 AMraulraja
02/08/2022, 11:12 AMraulraja
02/08/2022, 11:13 AMraulraja
02/08/2022, 11:14 AMraulraja
02/08/2022, 11:15 AMraulraja
02/08/2022, 11:15 AMthis
is actually not an outer reference but the name of the receiver paramater
of the function.raulraja
02/08/2022, 11:16 AMBart Kleijngeld
02/08/2022, 11:31 AMAlejandro Serrano Mena
02/08/2022, 11:36 AMBart Kleijngeld
02/08/2022, 11:39 AMBart Kleijngeld
02/10/2022, 6:46 AMModel
class for, say, a file input and a Reader
input?
And more generally I'm trying to understand how to distinguish OO smells creeping in, versus a legitimately flexible approach towards FP.raulraja
02/10/2022, 8:33 AMraulraja
02/10/2022, 8:36 AMsuspend
takes care of what otherwise you would call IO
in other langs like Haskell or Scala.
In the case of Kotlin IO effect tracking is built on top of continuations and the community in general prefers suspend
and imperative style for monadic ops vs passing higher order functions via flatMap or similar.raulraja
02/10/2022, 8:38 AMBart Kleijngeld
02/10/2022, 9:13 AMBart Kleijngeld
02/10/2022, 9:24 AM// model: Model
model.toJson() // Nicer in my opinion.
transformToJson(model)
This is a simple example of your point of what you may consider the partially applying role of immutable classes.
Now, I have a similar question for initializing a data model like this from several sources, such as File
or Reader
. So:
val reader: Reader = File("input.txt").reader()
val model = Model.fromReader(reader) // (1)
val model = readModelFromFile(reader) // (2)
In this case, I wouldn't know of any other way to do (1) without using constructors. I dislike that, since you get data and logic mixed up in your files (this is so clean about extension functions).
(Also note that in this example, Reader
implementations could have side effects, which I guess would definitely not be desirable here, but I hope the example it still clear enough)
I guess the remainder of my question would be: is (2) simply the easiest/preferred way to go? Or is (1) achievable and potentially desirable?raulraja
02/10/2022, 9:31 AMmodel.toJson()
is nice and would implement this as extension function to avoid coupling the data model to how it’s serialized. Same applies to (1) and (2) both can be expressed as extension functions if Model declares a companion in the case (1) or extending over reader or the modelraulraja
02/10/2022, 9:32 AMraulraja
02/10/2022, 9:32 AMclass Model {
companion object
}
fun Model.Companion.fromReader(reader: Reader): Model = TODO()
fun Reader.model(): Model = TODO()
Bart Kleijngeld
02/10/2022, 9:35 AMReader
extension is yet another flavor indeed. And that companion object usage was just what was missing from my understanding. Nice, thank you! Great explanations 🙂raulraja
02/10/2022, 9:38 AMList.Companion
and other java related types you don’t own.raulraja
02/10/2022, 9:39 AMraulraja
02/10/2022, 9:39 AMraulraja
02/10/2022, 9:40 AMcontext(Model.Companion, Reader)
fun model(): Model = TODO()
raulraja
02/10/2022, 9:40 AMraulraja
02/10/2022, 9:41 AMBart Kleijngeld
02/10/2022, 9:45 AM