cos I want to build a `TextView` instance with som...
# announcements
r
cos I want to build a
TextView
instance with something like:
Copy code
render(TextView::class, hashOf("text", "abc123"))
s
this is ancillary to the main discussion on constructors, but you could make this a bit more idiomatic using a reified type param here
r
sure. so how would the
render
function look like so that the class from the first argument can be instantiated?
s
Copy code
fun <reified T : Any> render(params: Map<String, String>): T? {
  return T::class.primaryConstructor?.call(params)
}

// called as such
val view = render<TextView>(mapOf("text" to "abc123"))
// or with type inferencing
val view: TextView? = render(mapOf("text" to "abc123"))
👍 1
r
oh ok
s
still, this seems rather brittle and may be better implemented not using reflection
r
how is reflection involved?
s
gaining references to arbitrary class constructors requires reflection
KClass<T>
is a member of
kotlin.reflect
r
Actually my example above isn't exactly what I'm doing, im doing this:
Copy code
data class Virtual(val cls: KClass<out View>, val attr: Map<String, Any>)

fun realiseView(activity: Context, parent: ViewGroup, virtual: Virtual): View {
    val view = virtual.cls(activity)
    parent.addView(view)
    return view
}
realiseView(activity, vg, Virtual(TextView::class, hashOf("text" to "abc")));
I know you advised against KClass
So do you advise against passing a class as argument?
Or in the above case, keeping the class in Virtual
s
I mean, there’s nothing wrong with passing
KClass
instances around, the problem is with disparate constructor signatures
maybe all these
View
objects have the exact same constructor in which case I guess it’s nbd
r
I do want to avoid using extensions
s
I also don’t really know why you need a
Virtual
data class, but maybe you’re using it elsewhere
what’s wrong with extensions?
r
just seem like unnecessary code just to instantiate a class
s
factory methods?
I mean, idk what your use case is or anything about android views (I’m guessing), but this is pretty normal stuff afaik
r
This didnt work:
virtual.cls.primaryConstructor?
s
What didn’t work? that line on its own is a syntax error
r
How would I access and call the primary constructor from
virtual.cls
then?
I come from Python, so all these extra syntaxes is a learning process
s
if you just need a reference to the primary constructor itself without invoking it, just
virtual.cls.primaryConstructor
, which will be of type
KFunction<{class type}>?
if you want to call it, I don’t think the reflection
KFunction<T>
type defines
invoke
, and instead provides
.call(Any)
r
.primaryConstructor
don't exist
there is
.constructors
though, but I gotta loop it
If I don't use
KClass
, then
TextView:class
will complain
s
well, sure, that’s like saying “I didn’t import
java.lang.List
and now my function that needs
List
is complaining”
there’s nothing wrong with
KClass
itself, I’m just trying to warn against this kind of arbitrary factory method
you can still do it lol
I’m not a cop
and to do it you’ll need reflection, so
use KClass
r
Alright, I'll try to get it working with KClass first, then I'll explore alternatives
I still can't use
.primaryConstructor
though. Don't exist
s
.primaryConstructor
looks like an extension val, check to see if you have
import kotlin.reflect.full.primaryConstructor
at the top of the file
should be available on Kotlin/JVM since 1.1
r
unresolved reference full
s
What version of Kotlin do you have included?
Assuming you’re using gradle
r
1.2.41
s
wait, hm, I wonder if you’re missing some stuff since android JVM is a bit different than regular JVM
r
should i explore another way, cos it just looks complicated importing all these things just to instantiate a class.
s
I mean, can’t you just directly use your respective view constructors
TextView(params)
r
TextView
is kept inside the
Virtual
data class
so I need
virtual.cls(params)
or equivalent to work
s
no I mean, wherever you were planning on using
myFunc
what is this
Virtual
data class anyhow
r
just something I made up
s
why do you even need it? I feel like this is a crazy x-y problem
also check out #C0B8M7BUY
and the other more specific android channels if you need them
r
I think it isn't crazy to store a class as a value
and then to instantiate it later
s
no, not in a vacuum, I suppose
If you need to defer instantiation of a class, why not use a lambda?
val myBuilder = { MyClass(params) }
r
That's an option
s
can even use invoke
val view = myBuilder()
r
I guess the essence of the question is why this doesn't just work:
Copy code
val boo = TextView
        boo(activity);
s
val foo = TextView
in Kotlin doesn’t get you a type-like reference to a given class
r
Then I try to solve that with:
Copy code
val boo = TextView::class;
        boo(activity);
Which complains about not having invoke method
s
specifically it’ll yield a reference to
TextView.Companion
or result in a compile error if there is no companion object defined on TextView (which there probably isn’t)
r
so complex
I think I like your lambda idea
s
like I said,
TextView::class
doesn’t let you use the reference like you would like if you were just calling a constructor by hand
really what you might want is
val foo = ::TextView
Bar != KClass<Bar>
r
this didn't work either:
Copy code
val boo = ::TextView
        boo(activity)
overload resolution ambiguity
s
right, and therein lies the problem
you can’t really have a function that arbitrarily constructs any class you tell it to
there can be any number of constructors defined for a given class, and you’ll have to manually resolve which constructor you need based on your parameters
However
r
i dont understand why it's ambiguous, TextView accepts 1 argument with Activity type, and I've provided it
s
There isn’t a single other constructor for TextView?
r
there are, but I've only provided 1 argument, so it should clearly pick the constructor with 1 argument of Activity type
This works
TextView(activity)
and it knows which constructor to run for that
s
well sure
but when you’re getting the reference
val foo = ::TextView
which constructor should it pick
r
I guess the smarts are lost at that point
I thought it will pick the right constructor when you execute foo
s
it can’t
r
ok then I understand
So how do I explicitly pick the constructor
s
Foo(params)
will resolve which constructor you need at compile-time
in any case, you can specify which constructor you want using a type annotation
val ctor: (Context) -> TextView = ::TextView
r
Fark I got bitten by this before!
I mean your solution works, and I've applied it before. And I keep forgetting it.
s
happens ¯\_(ツ)_/¯
r
Actually this is a bit different
s
this is what I meant by this being an x-y problem
r
I thought
() ->
is reserved for functions
didn't know you can use it for classes
ok I didn't know that's what you meant by x-y
s
i mean. a constructor for a class
T
is a function that returns
T
, no?
r
Ok I didn't know that
::TextView
is the constructor and not the class.
s
yup
r
Anyway thanks, I can sleep now at 6am!
it's hard to google for these problems as well. Pain in the ass.
s
it helps to try to understand what the problem is at an abstract level
rather than going directly to “how do I get a constructor from a KClass”
but it’s definitely a skill you pick up over time, as you gain the intuition for a given language
r
I'm good for now, thanks again. I'm out.
👍 1