Kotlin: How can I call super's extension function? - kotlin

How can I call a super's extension function?
For example:
open class Parent {
open fun String.print() = println(this)
}
class Child : Parent() {
override fun String.print() {
print("child says ")
super.print() // syntax error on this
}
}

Even though the print() function is defined inside of Parent, it belongs to String, not to Parent. So there's no print function that you can call on Parent, which is what you're trying to do with super.
I don't think there's syntax support for the type of call you're trying to do in Kotlin.

It is not possible for now, and there is an issue in the kotlin issue-tracker - KT-11488
But you can use the following workaround:
open class Parent {
open fun String.print() = parentPrint()
// Declare separated parent print method
protected fun String.parentPrint() = println(this)
}
class Child : Parent() {
override fun String.print() {
print("child says ")
parentPrint() // <-- Call parent print here
}
}

Related

How to handle polymorphism in kotlin

I am working with an abstract class and two concrete ones, which implementing the abstract one. The diagram is as the next:
My classes looks as:
abstract class NavItem() {
var attributes: String = ""
var text = ""
}
class NavMenu(val items: MutableList<NavItem>) : NavItem()
class NavLink(var shortText: String) : NavItem()
The problem is when I try to work with the items which could be NavMenu or NavLinks, the NavMenus has a collection of NavLinks.
I am trying to work with the items using polymorphism as the next code:
navMenu.items.forEach{ item ->
buildNavItem(item)
}
the buildNavItem methods seems as:
private fun buildNavItem(navMenu: NavMenu){
navMenu.items
navMenu.attributes
navMenu.items
}
private fun buildNavItem(navItem: NavItem){
navItem.text
navItem.attributes
}
private fun buildNavItem(navLink: NavLink){
navLink.text
navLink.attributes
}
But the code is always getting into buildNavItem(navItem: NavItem), even when in the for each I can see sometimes that the item is NavLink, or is NavMenu.
Any suggestion?
Thanks!!
That is not how polymorphism works. You have navMenu.items list that is the type of MutableList<NavItem>, it can store NavItems or its descendants. In forEach function you go through each item, which has NavItem type, and call buildNavItem(item) function. In this case buildNavItem(navItem: NavItem) is always called. To call the same method with another parameter you need to explicitly cast it to that type. What I recommend, and that's how polymorphism works, is to create buildNavItem() function in NavItem class and implement it in descendants:
abstract class NavItem() {
var attributes: String = ""
var text = ""
abstract fun buildNavItem()
}
class NavMenu(val items: MutableList<NavItem>) : NavItem() {
override fun buildNavItem() {
// ... your concrete implementation for NavMenu
}
}
class NavLink(var shortText: String) : NavItem() {
override fun buildNavItem() {
// ... your concrete implementation for NavLink
}
}
And then you can call it in forEach function:
navMenu.items.forEach { item ->
item.buildNavItem()
}
In that case buildNavItem() function will be called for the right object, that is stored in navMenu.items, i.e. if it is an object of NavLink type then function 'buildNavItem()', overridden in NavLink class, will be called.
Problem:
navMenu.items.forEach { item ->
item.buildNavItem()
}
Since items is of type List<NavMenu>, the compiler will call the function which is appropriate for an item of type NavMenu, in this case the overload which takes a NavMenu.
Solution:
In order to call a more specific overload the compiler needs to know the type. You can smart cast the items an the appropriate function will be called:
private fun buildNavItem(navMenu: NavMenu) {
when(navMenu){
is NavItem -> buildNavItem(navMenu) // navMenu is smart casted to NavItem
is NavLink -> buildNavItem(navMenu) // navMenu is smart casted to NavLink
else -> throw IllegalStateException("Unknown subtype ${navMenu::class.simpleName} of NavMenu")
}
}
This way whenever you call buildNavItem, you delegate to the appropriate function.

Kotlin - extensible type-safe builders

I want to be able to create a custom builder-pattern DSL-type thing, and I want the ability to create new components in a clean and type-safe way. How can I hide the implementation details required for creating and extending such a builder-pattern?
The Kotlin docs give something like the following example:
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
a(href = "http://kotlinlang.org") {+"Kotlin"}
// etc...
}
}
Here, all of the possible "elements" are predefined and implemented as functions that also return objects of the corresponding types. (eg. the html function returns an instance of the HTML class)
Each function is defined so that it adds itself to its parent context's object as a child.
Suppose someone wanted to create a new element type NewElem usable as newelem. They would have to do something cumbersome such as:
class NewElem : Element() {
// ...
}
fun Element.newelem(fn: NewElem.() -> Unit = {}): NewElem {
val e = NewElem()
e.fn()
this.addChild(e)
return e
}
every time.
Is there a clean way to hide this implementation detail?
I want to be able to create a new element by simply extending Element for example.
I do not want to use reflection if possible.
Possibilities I Tried
My main problem is coming up with a clean solution. I thought of a couple other approaches that didn't pan out.
1) Create new elements with a function call that returns a function to be used in the builder style such as:
// Pre-defined
fun createElement(...): (Element.() -> Unit) -> Element
// Created as
val newelem = createElement(...)
// Used as
body {
newelem {
p { +"newelem example" }
}
}
There are obvious downsides to this, and I don't see a clear way to implement it either - probably would involve reflection.
2) Override the invoke operator in companion object
abstract class Element {
companion object {
fun operator invoke(build: Element.() -> Unit): Element {
val e = create()
e.build()
return e
}
abstract fun create(): Element
}
}
// And then you could do
class NewElem : Element() {
companion object {
override fun create(): Element {
return NewElem()
}
}
}
Body {
NewElem {
P { text = "NewElem example" }
}
}
It is unfortunately not possible to enforce "static" functions to be implemented by subclasses in a type-safe way.
Also, companion objects aren't inherited, so the invoke on subclasses wouldn't work anyway.
And we again run into problems about adding children elements to the correct context, so the builder doesn't actually build anything.
3) Override the invoke operator on Element types
abstract class Element {
operator fun invoke(build: Element.() -> Unit): Element {
this.build()
return this
}
}
class NewElem(val color: Int = 0) : Element()
Body() {
NewElem(color = 0xff0000) {
P("NewElem example")
}
}
This might have worked, except for when you immediately try to invoke on the object created by the constructor call, the compiler cannot tell that the lambda is for the "invoke" call and tries to pass it into the constructor.
This can be fixed by making something slightly less clean:
operator fun Element.minus(build: Element.() -> Unit): Element {
this.build()
return this
}
Body() - {
NewElem(color = 0xff0000) - {
P("NewElem example")
}
}
But yet again, adding children elements to the parent elements isn't actually possible without reflection or something similar, so the builder still doesn't actually build anything.
4) Calling add() for sub-elements
To try to fix the issue of the builder not actually building anything, we could implement an add() function for sub-elements.
abstract class Element {
fun add(elem: Element) {
this.children.add(elem)
}
}
Body() - {
add(NewElem(color = 0xff0000) - {
add(P("NewElem red example"))
add(P("NewElem red example 2"))
})
add(NewElem(color = 0x0000ff) - {
add(P("NewElem blue example"))
})
}
But this is obviously not clean and is just deferring the cumbersome-ness to the usage side instead of the implementation side.
I think it's unavoidable to add some sort of a helper function for each Element subclass you create, but their implementation can be simplified with generic helper functions.
For example, you can create a function that performs the setup call and adds the new element to the parent, then you only have to call into this function and create an instance of your new element:
fun <T : Element> Element.nest(elem: T, fn: T.() -> Unit): T {
elem.fn()
this.addChild(elem)
return elem
}
fun Element.newElem(fn: NewElem.() -> Unit = {}): NewElem = nest(NewElem(), fn)
Alternatively, you could create that instance via reflection to simplify even further, but since you've stated you'd like to avoid it, this will probably seem unnecessary:
inline fun <reified T : Element> Element.createAndNest(fn: T.() -> Unit): T {
val elem = T::class.constructors.first().call()
elem.fn()
this.addChild(elem)
return elem
}
fun Element.newElem(fn: NewElem.() -> Unit = {}) = createAndNest(fn)
These still leave you with having to declare a factory function with the appropriate header, but this is the only way to achieve the syntax that the HTML example achieves, where a NewElem can be created with its own newElem function.
I came up with a solution that isn't the most elegant, but it is passable and works the way I would want it to.
It turns out that if you override an operator (or create any extension function for that matter) inside a class, it has access to its parent context.
So I overrode the unary + operator
abstract class Element {
val children: ArrayList<Element> = ArrayList()
// Create lambda to add children
operator fun minus(build: ElementCollector.() -> Unit): Element {
val collector = ElementCollector()
collector.build()
children.addAll(collector.children)
return this
}
}
class ElementCollector {
val children: ArrayList<Element> = ArrayList()
// Add child with unary + prefix
operator fun Element.unaryPlus(): Element {
this#ElementCollector.children.add(this)
return this
}
}
// For consistency
operator fun Element.unaryPlus() = this
This allows me to create new elements and use them like this:
class Body : Element()
class NewElem : Element()
class Text(val t: String) : Element()
fun test() =
+Body() - {
+NewElem()
+NewElem() - {
+Text("text")
+Text("elements test")
+NewElem() - {
+Text("child of child of child")
}
+Text("it works!")
}
+NewElem()
}

Kotlin, how to assign callback implementation to a variable

I'm trying to assign a callback implementation of an interface (defined inside a class A) to a variabile defined inside another class B. Let's say that class A has the interface OnSomethingHappens which defines a doSomething method.
Inside class B I've defined my callback variable like this:
private lateinit var callback:A.OnSomethingHappens
I need to create an instance of class A passing callback variabile to the constructor in this way:
myinstanceA = A(callback)
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code:
callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
but the compiler says "expecting member declaration" for my callback variable and "name expected" for object.
What I'm doing wrong?
Instead, I'm able to define and at the same time assign the callback variable in this way:
private var callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
Why? Which are the differences and a possible solution?
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code: ...
This should work, but only inside a method:
class B {
private lateinit var callback:A.OnSomethingHappens
fun someMethod() {
callback = object : A.OnSomethingHappens { ... }
}
...
}
Given the error message and that private var compiles (which doesn't inside a method), you are trying to set it directly in the body of the class instead:
class B {
private lateinit var callback:A.OnSomethingHappens
callback = object : A.OnSomethingHappens { ... }
...
}
This is illegal: the only code you can write there is member definitions and init blocks.
Also, if you can initialize callback directly where it's defined or inside init, there's no point to lateinit in the first place.
It's not obvious from the code snippets cut down to such small pieces, but your issue is that you're writing down the assignment inside the body of a class, but not inside a function.
Here's an example of a valid declaration and immediate assignment:
class A {
var x: X? = X()
}
Here's an example of an invalid assignment, which places an arbitrary expression in the body of a class:
class A {
lateinit var x: X
x = X() // expression placed inside the class body, invalid syntax
someFunction() // extra example, calling functions here is invalid in the same way
}
Instead, you could put this initialization inside a function:
class A {
lateinit var x: X
fun initializeX() {
x = X()
}
}
Or inside an initializer block (in this case, you don't even need lateinit):
class A {
var x: X
init {
x = X()
}
}
While I couldn't explain how to solve your exact problem, because I can't quite understand what code is in which class, I hope these examples and explanation helped.
Hmm, let me propose a variant. It's more simple for me:
import android.util.Log
class SomeClass {
fun mainMethod() {
ClassWithCallback(
{ myBackValue: String ->
logMyString(myBackValue)
}
)
//simplify
ClassWithCallback({ logMyString(it) })
}
private fun logMyString(myBackValue: String) {
Log.d("SomeClass", myBackValue)
}
}
class ClassWithCallback(private val myCallBack: (myBackValue: String) -> Unit) {
init {
// we do something here and back it by callback
val myString = "Hello! Pass me back!"
myCallBack.invoke(myString.toUpperCase())
}
}
Using Kotlin lambdas. Hope this will help you.

Method References to Super Class Method

How to use method references to refer to super class methods?
In Java 8 you can do SubClass.super::method.
What would be the syntax in Kotlin?
Looking forward to your response!
Conclusion
Thanks to Bernard Rocha!
The syntax is SubClass::method.
But be careful. In my case the subclass was a generic class. Don't forget to declare it as those:
MySubMap<K, V>::method.
EDIT
It still doesn't work in Kotlin.
Hers's an example in Java 8 of a method reference to a super class method:
public abstract class SuperClass {
void method() {
System.out.println("superclass method()");
}
}
public class SubClass extends SuperClass {
#Override
void method() {
Runnable superMethodL = () -> super.method();
Runnable superMethodMR = SubClass.super::method;
}
}
I'm still not able to do the same in Kotlin...
EDIT
This is an example how I tried to achieve it in Kotlin:
open class Bar {
open fun getString(): String = "Hello"
}
class Foo : Bar() {
fun testFunction(action: () -> String): String = action()
override fun getString(): String {
//this will throw an StackOverflow error, since it will continuously call 'Foo.getString()'
return testFunction(this::getString)
}
}
I want to have something like that:
...
override fun getString(): String {
//this should call 'Bar.getString' only once. No StackOverflow error should happen.
return testFunction(super::getString)
}
...
Conclusion
It's not possible to do so in Kotlin yet.
I submitted a feature report. It can be found here: KT-21103 Method Reference to Super Class Method
As the documentation says you use it like in java:
If we need to use a member of a class, or an extension function, it
needs to be qualified. e.g. String::toCharArray gives us an extension
function for type String: String.() -> CharArray.
EDIT
I think you can achieve what you want doing something like this:
open class SuperClass {
companion object {
fun getMyString(): String {
return "Hello"
}
}
}
class SubClass : SuperClass() {
fun getMyAwesomeString(): String {
val reference = SuperClass.Companion
return testFunction(reference::getMyString)
}
private fun testFunction(s: KFunction0<String>): String {
return s.invoke()
}
}
Don't know if it is possible to get the reference to super class's function, but here is an alternative to what you want to achieve:
override fun getString(): String = testFunction { super.getString() }
According to Bernardo's answer, you might have something like this. It doesn't have remarkable changes.
fun methodInActivity() {
runOnUiThread(this::config)
}
fun config(){
}
What is more, in the incoming 1.2 version you can use just
::config

How to get kotlin function's caller

With this example:
open class Parent {
fun some():Parent {
return this;
}
}
class A : Parent(){
val name:String? = null;
}
But then this code results in an error:
val a = A().some().some()
a.name // ERROR
EDITOR NOTE: based on comments of the author to answers below, the question is NOT about referencing a.name but really is about something like "how do I get the instance of the class or its name that first started the chain of method calls". Read all comments below until the OP edits this for clarity.
my final goal is to return caller's type and can call this caller's instance property, no more as , no more override, any idea?
Just like java, you can use stackTrace's getMethodName(). Refer to the kotlin doc.
Actially your example is working(if you add open keyword because all classes in Kotlin are final by default:
A.kt
open class A {
fun some(): A {
return this
}
}
B.kt
class B : A() {
val test = "test"
}
And usage
val tmpB = (B().some().some() as B)
val test = tmpB.test
Edited:
It because function some() return parent class which doesn't have child class property. So you need to cast it to child class.(Update code)
open class Parent{
open fun foo(): Parent {
return this;
}
}
This is your Parent class. Parent class has a method named foo(). foo() is a method of class A which will return the instance of it's own class. We must have to open the class and method because by default their visibility modifier is final.
class A : Parent() {
override fun foo(): A { return this }
}
This is a class named A which extends Parent class. foo() is a method of class A which will return the instance of it's own class.
We will call it like this:
var a = A().foo().foo()
Your class always return Parent instance. This class do not have any field with the name name. To do that you have 2 ways:
The first:
open class Parent{
fun some():Parent{
return this
}
}
class A :Parent(){
val name:String? = null
}
fun main() {
val a = (A().some().some() as A)
a.name = "";
}
The second:
open class Parent{
open fun some():Parent{
return this
}
}
class A :Parent(){
override fun some():A {
return this
}
val name:String? = null
}
fun main() {
val a = A().some().some()
a.name = "";
}
i have know how to do this:
#Avijit Karmakar
#Trần Đức Tâm
use inline function
inline fun <reified T:Any> some(sql: String):T {
return this as T ;
}