The following code does the same thing. The functions tr and td take a function literal with receiver object as input in order to add tr or td tag inside of a table.
class TABLE : Tag("table") {
fun tr(init: TR.() -> Unit) {
children += TR().apply(init)
}
}
class TR : Tag("tr") {
fun td(init: TD.() -> Unit) {
val td = TD()
td.init()
children += td
}
}
My Question is why do I need to use .apply() instead of:
class TABLE : Tag("table") {
fun tr(init: TR.() -> Unit) {
children += TR().init()
}
}
I guess it has something to do with the compiler looking for init() in the tr-object. But shouldn't this be decided on runtime?
As already suggested in my comment, using .apply you can chain invocations of init and += together, because apply returns the target of its invocation.
If you prefer to use init(), you can obtain the same result with
val tr = TR()
children += tr
tr.init()
The key aspect of the chained variation is that the applyfunction of the Kotlin's standard library is defined as an extension function of a generic typeT, accepting a *lambda with receiver as its sole parameter, as you can see here:
inline fun <T> T.apply(block: T.() -> Unit): T
In order to explain its meaning, you can implement this function yourself:
fun <T> T.myApply(block: T.() -> Unit) : T {
this.block()
return this
}
The following example mimics your code, using a fake MyClass type in place of the original TR:
fun <T> T.myApply(block: T.() -> Unit) : T {
this.block()
return this
}
class MyClass(val text: String) {
fun foo() : Unit {
println("foo $text")
}
}
fun initializer(mc: MyClass) {
println("initializer ${mc.text}")
mc.foo()
}
fun run(init: MyClass.() -> Unit) {
val result = MyClass("first").myApply(init)
val x = MyClass("second")
x.init()
}
fun main(args: Array<String>) {
run(::initializer)
}
You can play with this example in order to follow the flow from run to MyClass.foo, through the function accepting init as lambda with receiver parameter: I hope this can help you to clarify your understanding of the key charateristics of both the original and the alternative implementation of tr.
Related
I try to call fun bind declared in the inner class LaunchesViewHolder from onBindViewHolder() but I got error "Unresolved resource bind"
I was trying with an other variable x, just to see, same problem
class LaunchesAdapter(private val dataSet: List<LaunchItem>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
inner class LaunchesViewHolder( val binding: LaunchesItemLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
val x = 0
public fun bind(currentLaunch: LaunchItem) {
//do something
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return LaunchesViewHolder(
LaunchesItemLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
holder.bind(dataSet[position]) => error unresolved resource bind
holder.x =1 => error unresolved resource x
}
override fun getItemCount(): Int {
return dataSet.size
}
}````
In your onBindViewHolder you should use your specific ViewHolder, that is LaunchesViewHolder and not the RecyclerView.ViewHolder. Please see code below.
override fun onBindViewHolder(holder: LaunchesViewHolder, position: Int) {
holder.bind(dataSet[position])
}
Edited:
You need to specify the class you override too
class LaunchesAdapter(private val dataSet: List<LaunchItem>) :
RecyclerView.Adapter<LaunchesAdapter.LaunchesViewHolder>() {
}
it works with
(holder as LaunchesViewHolder).bind(dataSet[position])
instead of holder.bind(dataSet[position])
see more details https://www.section.io/engineering-education/implementing-multiple-viewholders-in-android-using-kotlin/
I have a class that has the type parameter KFunction<*>
(It is understood that I will indicate the type of function that I want to work with in the future)
I want a class method to take the same parameters that KFunction has and call subscribers with those arguments. However, I don't know how to get the type of the function parameters. There are delegates in C #. How to do something like this in Kotlin?
My class:
class Event<Function: KFunction<*>> {
val subscribers = mutableListOf<Function>()
operator fun plus(increment: Function) {
subscribers.add(increment)
}
// i want arguments as KFunction
operator fun invoke(args: ???) {
subscribers.forEach { it(args) }
}
}
fun c(i: Int) {
println("result of function c: $i")
}
fun main() {
val event = Event<KFunction1<Int, Unit>>()
event + ::c
event(100) // passing arguments Int from KFunction1<Int, Unit>
}
Is there a way to implement my idea exactly like this?
So, it's implied that type, passed as a Function : KFunction<*> type parameter (KFunction1<Int, Unit> in this case) will have its own type parameters (Int and Unit in this case), and you want to declare args parameter as an uncertain amount of parameters with these exact types (excluding the last one, which represents type of function call result)?
I believe it's impossible.
The best you can do is to declare args as vararg with Any? type:
operator fun invoke(vararg args: Any?) = subscribers.forEach { it.call(*args) }
It seems that the only normal solution to problem is to accept only 1 abstract type of parameters.
class Event<ArgsT> {
private val subscribers = mutableListOf<(ArgsT) -> Any>()
operator fun plusAssign(increment: (ArgsT) -> Any) {
subscribers.add(increment)
}
operator fun invoke(params: ArgsT) {
subscribers.forEach { it(params) }
}
}
fun c(i: Int, b: Int) {
println(i + b)
}
data class Data(val i: Int, val b: Int)
fun main() {
val event = Event<Data>()
event += { (i, b) -> c(i, b) } // pass arguments using a lambda
event(Data(2, 5))
}
How can I (de)serialize kotlin delegate properties with jackson.
I have a class like this
class MyClass {
var a: Int = 42
set(value) {
val changed = field != value
field = value
if (changed) notifyListeners()
}
... and a dozen other properties that all follow this pattern ...
}
I wanted to simplify that by using
class MyClass {
var a: Int by NotifyUiOnChange(42)
...
private inner class NotifyUiOnChange<T>(initialValue: T) : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
notifyUiListeners()
}
}
}
but then Jackson will ignore that property.
How can I tell Jackson to serialize and deserialize that property anyway?
And how do I then apply #JsonIgnore annotations (or something comparable)?
You must use outdated version on Jackson (or maybe a version for Java, not Kotlin?). I've checked this using "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.+" (resolved to 2.10.1).
I've declared two classes:
class MyClass {
var a: Int = 42
set(value) {
val changed = field != value
field = value
if (changed) notifyListener(field)
}
private fun notifyListener(field: Any?) {
println("changed: $field")
}
}
class MyDelegatedClass {
var a: Int by NotifyUi(42)
private inner class NotifyUi<T>(initialValue: T) : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
notifyListener(newValue)
}
}
private fun notifyListener(field: Any?) {
println("changed: $field")
}
}
My main function:
fun main() {
val noDelegate = MyClass()
val delegated = MyDelegatedClass()
val mapper = ObjectMapper().registerKotlinModule()
// Deserialization
val noDelegateValue = mapper.writeValueAsString(noDelegate)
val delegatedValue = mapper.writeValueAsString(delegated)
println("No delegate:\t$noDelegateValue")
println("With delegate\t$delegatedValue")
// Serialization
val noDelegateObject = mapper.readValue<MyClass>("{\"a\":42}".trimIndent())
val delegateObject = mapper.readValue<MyDelegatedClass>("{\"a\":42}".trimIndent())
}
Output:
No delegate: {"a":42}
With delegate {"a":42}
changed: 42
We even can see output on delegate when we use delegate property :) (I believe it's a side-effect that should be consider as bug actually)
So, handling delegates is out of the box feature in jackson (I am not sure since when, but I used lazy delegate with jackson in older project I used to participate and there was no problems with delegates).
How to ignore delegated property?
So, you cannot apply JsonIgnore annotation to delegated field, because you will get This annotation is not applicable to target 'member property with delegate'. But, you can define the scope that annotation should be applied. Example below:
class MyDelegateClass {
#get:JsonIgnore // or set:
val a: Int by NotifyUi(42)
}
Unfortunately, seems that it's kind of broken, because you can use get: or set: and it's not apply to getter or setter only, but for both.
Let's say I have a data class like this:
data class MyData(val something: Int, val somethingElse : String) {
init {
require(something > 20) { "Something must be > 20" }
require(StringUtils.isNotEmtpy(somethingElse)) { "Something else cannot be blank" }
}
}
I'd like to be able to apply a function to somethingElse before the init method is called. In this case I want to remove all \n characters from the somethingElse String while maintaining immutability of the field (i.e. somethingElse must still be a val). I'd like to do something similar to this in Java:
public class MyData {
private final int something;
private final String somethingElse;
public MyDate(int something, String somethingElse) {
this.something = something;
this.somethingElse = StringUtils.replace(somethingElse, '\n', '');
Validate.isTrue(something > 20, "...");
Validate.isTrue(StringUtils.isNotEmtpy(this.somethingElse), "...");
}
// Getters
}
I could of course create a normal class (i.e. no data class) in Kotlin but I want MyData to be a data class.
What is the idiomatic way to do this in Kotlin?
While you can not literally do what you want, you can fake it.
Make all constructors of your data class private.
Implement factories/builders/whatevers on the companion as operator fun invoke.
Usages of Companion.invoke will -- in Kotlin! -- look just like constructor calls.
In your example:
data class MyData private constructor(
val something: Int,
val somethingElse : String
) {
init {
require(something > 20) { "Something must be > 20" }
require("" != somethingElse) { "Something else cannot be blank" }
}
companion object {
operator fun invoke(something: Int, somethingElse: String) : MyData =
MyData(something, somethingElse.replace("\n", " "))
}
}
fun main(args: Array<String>) {
val m = MyData(77, "something\nwicked\nthis\nway\ncomes")
println(m.somethingElse)
}
Prints:
something wicked this way comes
You'll note the helpful warning:
Private data class constructor is exposed via the generated 'copy' method.
This method can not be overridden (as far as I can tell) so you have to take care, still. One solution is to hide the actual data class away:
interface MyData {
val s: Int
val sE: String
private data class MyDataImpl(
override val s: Int,
override val sE: String
) : MyData {
init {
require(s > 20) { "Something must be > 20" }
require("" != sE) { "Something else cannot be blank" }
}
}
companion object {
operator fun invoke(s: Int, sE: String) : MyData =
MyDataI(s, sE.replace("\n", " "))
}
}
Now your invariant (no line breaks) is maintained, copy and other dangerous methods (if any, I haven't checked) are hidden away -- but therefore also unavailable, potentially removing some of the convenience data classes provide.
Choose your poison.
Suppose I have a Kotlin (data) class with the primary constructor and a secondary one which fills vals/vars of the primary one with calling some methods (see the example). My question is whether the order in which these methods are being called is guaranteed, i.e. whether in my example checkConsitency would always get called before extractNames.
data class LawAndOrder(val sherifs: Int, val names: List<String>) {
constructor(westerners: List<Westerner>) :
this(sherifs = westerners.checkConsistency(),
names = westerners.extractNames())
}
data class Westerner(val name: String) {
val isCriminal: Boolean
get() = name == "Jesse James"
}
private fun List<Westerner>.checkConsistency(): Int {
println("Checking consistency")
if (isEmpty()) throw IllegalArgumentException("Crime and chaos")
if (any { it.isCriminal }) throw IllegalArgumentException("Inadmissible")
return size
}
private fun List<Westerner>.extractNames(): List<String> {
println("Extracting names")
return map { it.name }
}
fun main(args: Array<String>) {
val westerners = listOf(Westerner("John Wayne"), Westerner("Limonádový Joe"))
val lawAndOrder = LawAndOrder(westerners)
println(lawAndOrder)
}
The Kotlin Language Specification has this to say about it (emphasis mine):
16.39. Order of Evaluation
Generally, the order of evaluation is left to right, non-lazy (eager). Some expressions have special rules for order of evaluation of their constituent parts (some of them may be not evaluated at all). Order of evaluation of named arguments corresponds to their order at the invocation site, not the declaration site.
TODO