Not an arrow question per se, but is there a way t...
# arrow
k
Not an arrow question per se, but is there a way to have a function return a function with a generic type in Kotlin/Arrow. I want to do
Copy code
fun doSomething(): ((Class<T>) -> T) -> T
However because lambda expressions can't have generic types, this doesn't compile for me.
s
You'll need to declare the generic type for
doSomething
too. e.g.
Copy code
fun <T> doSomething(): (Class<T>) -> T
k
I wanted
doSomething
to be a reusable factory function
s
I'm not sure I follow, sorry.
Is there something that prevents that from being reused?
It's difficult to implement, because that suggests that the function has to support all possible
T
as determined by the call-site
k
Is there something that prevents that from being reused?
Because I couldn't do
Copy code
val something = doSomething()
val makeString = { cls: Class<String> -> "Hello World" }
val makeInt = { cls: Class<Int> -> 0 }

something(makeString(String.javaClass))
something(makeInt(Int.javaClass))
All my FP experience has been in dynamically typed languages, so I'm having to rethink how to write my code in Kotlin.
s
That's a different signature for what you have above.
That would be something more akin to:
Copy code
fun <T> doSomething(): ((Class<T>) -> T) -> ...
k
You're right, I muffed up the original
s
Does that help at all, or is there still a further problem to solve?
k
Edited my original question.
So now my example of what I can't do still is a problem.
s
So the essence is "if you give me a function that can produce a value for some type of class, I can give you that value back"?
k
Yep.
The factory function (
doSomething
) should not care about the type of
T
s
at what point is the class provided?
k
After
doSomething
is invoked
s
Is your example above correct in terms of how you want to call it? i.e.
Copy code
something(makeString(String.javaClass))
something(makeInt(Int.javaClass))
k
Where I can type the result
Copy code
val s: String = something(makeString(String.javaClass))
val n: Int = something(makeInt(Int.javaClass))
I've gotten pretty close with star projections, however there's a bit of casting involved somewhere.
s
so in that case,
something
doesn't need to know anything about the
Class<T>
correct? As it is provided by `makeString`/`makeInt`
k
Correct.
doSomething
returns a function that takes a function of
Class<T> -> T
I just am struggling with the syntax.
s
something(makeString(String.javaClass))
something doesn't know anything about the
Class<String>
, only
makeString
needs to
sorry, the
something
function doesn't know about
Class<String>
at all
m
Make
doSomething
return a class that has
operator fun <T> invoke(p1: (Class<T>) -> T): T
implemented.
k
Yes.
something
takes a function and returns a String.
something
takes another function and returns an Int.
m
That should let you call
something
with any generic type
T
at the call site
Instead of fixing it at the creation site.
k
@Mitchell Skaggs That's some Kotlin magic above my level at the moment (this project is my first serious Kotlin project). Got some docs please? 😄
m
Sorry 😆. It's defining the "invoke" operator (one of many operators that can be overloaded: https://kotlinlang.org/docs/operator-overloading.html).
k
Thanks 😄
m
If you want a polymorphic type, you'll need to define your own interface that has the operator function abstract, and then
something
can return that type and you can return different subtypes. The standard
Function
type doesn't support function-scoped generic type parameters.
(That's what the
fun <T>
is, a function-scoped generic type parameter. Java has them as well, just in a slightly different location.)
k
So what would the signature be for
doSomething
then @Mitchell Skaggs?
m
You would need to define your own interface:
Copy code
interface Thing {
    operator fun <T> invoke(p1: (Class<T>) -> T): T
}
k
So
fun doSomething(): Thing
?
m
Yep! This is the full example I made:
Copy code
interface Thing {
    operator fun <T> invoke(p1: (Class<T>) -> T): T
}

fun doSomething(): Thing {
    return object : Thing {
        override fun <T> invoke(p1: (Class<T>) -> T): T {
            TODO("Not yet implemented")
        }
    }
}

val something: Thing = doSomething()
val s: String = something { c: Class<String> -> "" }
❤️ 1
The
object : Thing
syntax is just creating an anonymous class implementing
Thing
👍 1
k
Yeah I do love how Kotlin does anonymous classes
I wonder if one could do a
reified
version that means you don't need the
Class
arg? 🤔
m
It can be reified if you make
Thing
into a class and implement the
invoke
function there.
reified
requires an
inline
function, which can't be virtual (overrides another method, runtime polymorphism), so you can only have one implementation.
👍 1
But lambdas are inherently virtual, so there's no way to make that function
reified
.
k
Thanks @Mitchell Skaggs and @Scott Christopher for your help.
👍 2