Object expressions, Multiple supertype specification syntax? - kotlin

I am new to Kotlin. I came across the Object Expressions section of https://kotlinlang.org
Some of the object expression syntaxes are very straight forward to understand,
Create an object of an anonymous class
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
})
Just an object
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
But I am unable to understand the "Object expression with multiple supertypes specified" example given as below:
open class A(x: Int) {
public open val y: Int = x
}
interface B { ... }
val ab: A = object : A(1), B {
override val y = 15
}
What's happening here?
${ab.y} prints 15
but syntax -> ${ab.A.y} is not valid. My understanding of ${ab.A.y} it will print 1 :)

This line here:
val ab: A = object : A(1), B {
means that the class of ab is inherited from class A and implements interface B.
Actually the code example you gave will only compile if you declare and implement the interface. This is a possible implementation:
open class A(x: Int) {
public open val y: Int = x
}
interface B {
fun hi()
}
val ab: A = object : A(1), B {
override val y = 15
override fun hi() {
println("hi")
}
}
The expression ${ab.A.y} does not make much sense in this context, because the object ab does not have any field A. A is just the inherited superclass to which you could eventually cast.

It basically creates object ab with class type A with implementation of interface B.
So, let's say your class A has some method foo() & interface B has some method bar(), you can access them both on object ab as it's of class type A with implementation of B.
Hence, here you override variable y with value 15 meaning your superclass variable y will get overridden by value 15 from 1.

Related

Kotlin: How to define a variable whose type depends on the input?

I have a function in Kotlin which takes a particular string as input. Depending on the input, I want to create a variable of a specific type and do some computations on it.
For example,
fun compute(input: String): Any{
if(input=="2d"){
var point: Point2D;// Points2D - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-1"){
var point: Point2DWithP1AsOrigin;// Point2DWithP1AsOrigin - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-2"){
var point: Point2DWithP2AsOrigin;
//initilize and do some computations
return point.findDistanceFromOrigin()
}
.
.
.
}
You can see in the above example, I want to initilize the type of point depending on the input and do computation and return.
All the if-else conditions have the same code except for the definition of the variable. How can I put all this in a single block with something like this:
var point: if(input=="2d) Point2D::class else if(input=="2d-1") Point2DWithP1AsOrigin::class.....
How can I do that?
You could do something like this
fun compute(input: String): Any{
val point: MyPoint = when(input) {
"2d" -> Point2D()
"2d-1" -> Point2DWithP1AsOrigin()
"2d-2" -> Point2DWithP2AsOrigin()
else -> Point2D() //fallback is necessary
}
//initilize and do some computations
return point.findDistanceFromOrigin()
}
But then it's essential that all those classes share the same interface. Because they need to have the same methods in order to do the same operations on them.
For example like this:
class Point2D : MyPoint {
override fun findDistanceFromOrigin() = 5
}
class Point2DWithP1AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 6
}
class Point2DWithP2AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 7
}
interface MyPoint {
fun findDistanceFromOrigin() : Int
}
You can store constructor references and then invoke required one
fun main() {
val constructors = mapOf(
"2d" to ::Point2D,
"2d-1" to ::Point2DWithP1AsOrigin,
"2d-2" to ::Point2DWithP2AsOrigin,
)
val type = "2d-2"
val constructor = constructors[type] ?: throw IllegalArgumentException("$type not supported")
val point = constructor()
println(point::class)
}
Output
class Point2DWithP2AsOrigin

Passing and Accessing Values and Functions of a Subtype that was passed into a Class Constructor requiring it's Supertype

I'll keep this as simple as possible. Let's say I have a parent class with a function as below that takes a position argument as a Point data class
open class Obj(val pos:Point) {
fun foo() : Double {
return 5.0 + pos.x * pos.y * pos.z
}
}
For sake of thoroughness, here is the Point data class
data class Point(val x:Double, val y:Double, val z:Double)
So I have multiple children that inherit from the Obj class but implement an additional function that is named the same in every child and calls a function in the parent,
class Cube(pos:Point) : Obj(pos) {
fun number() : Double {
return 10.0 * foo()
}
}
class Sphere(pos:Point) : Obj(pos) {
fun number() : Double {
return 20.0 * foo()
}
}
My question is, if I have a function somewhere that takes in objects that inherit from Obj but not Obj itself, how can I ensure they are of their own subtype rather than the Supertype?
For example, I currently have my function looking like this
fun foo2(obj:Obj) {
println(obj.number()) // throws error because obj doesn't have method number()
}
The normal approach to this sort of case would be to add an abstract method to the base class, and have the subclasses implement it. That way, whenever you have a base class reference, the compiler knows that method is available.
That would require the base class itself to be abstract, so you can't instantiate it directly. (And if foo() is only used by number() implementations, it might make sense to hide it from other classes.)
abstract class Obj(val pos: Point) {
abstract fun number(): Double
protected fun foo() = 5.0 + pos.x * pos.y * pos.z
}
class Cube(pos: Point) : Obj(pos) {
override fun number() = 10.0 * foo()
}
If, however, you need the base class to be instantiable, then that's more tricky: there's no easy way to specify 'only subclasses'. Depending on your exact requirements, you might allow the base class to be passed, and have it provide a default implementation of number():
open fun number() = foo()
Okay so using the suggestion from Animesh Sahu, I've implemented an Interface called ObjI in the base class, and required each implementation override the number() function. I combined that with the answer given by gidds, suggesting creating a function that calls another function. So the number() function in the base class just calls the foo() function
data class Point(val x:Double, val y:Double, val z:Double)
interface ObjI {
fun number() : Double
}
open class Obj(val p:Point) : ObjI {
override fun number() = foo()
fun foo() : Double {
return 5.0 + p.x * p.y * p.z
}
}
class Sphere(p:Point) : Obj(p) {
override fun number() : Double {
return 10.0 * super.foo()
}
}
class Cube(p:Point) : Obj(p) {
override fun number() : Double {
return 20.0 * super.foo()
}
}
fun main(args: Array<String>) {
val s = Sphere(Point(13.0, 6.0, 1.0))
val c = Cube(Point(13.0, 6.0, 1.0))
printem(s)
printem(c)
}
fun printem(o:Obj) {
println(o.number())
}

Scope of methods of an anonymous object - Kotlin

In Kotlin if I define a method on an anonymous object, sometimes I am able to access it, while other times I am not. This seems to have something to do with scoping rules, but I am not sure what.
In the code example below, the access to example3.field.method() will cause a compilation error. Interestingly, example2.field.method() compiles just fine.
What could be the explanation for the below behaviour?
class Example3 {
val field = object {
fun method() {}
}
}
fun showcase() {
val example1 = object {
fun method() {}
}
example1.method()
println(example1::class.qualifiedName)
class Example2 {
val field = object {
fun method() {}
}
}
val example2 = Example2()
example2.field.method()
println(example2::class.qualifiedName)
val example3 = Example3()
// example3.field.method() // won't compile
println(example3::class.qualifiedName)
}
From docs Object Expressions and Declarations:
Note that anonymous objects can be used as types only in local and
private declarations. If you use an anonymous object as a return type
of a public function or the type of a public property, the actual type
of that function or property will be the declared supertype of the
anonymous object, or Any if you didn't declare any supertype. Members
added in the anonymous object will not be accessible.
Demonstrated in code sample below:
class Example4{
val publicObj = object{
val x = 1
}
private val privateObj = object{
val x = 2
}
fun showcase(){
val scopedObj = object{
val x = 3
}
println(publicObj.x) // ERROR : unresolved reference: x
println(privateObj.x) // OK
println(scopedObj.x) // OK
}
}
Pawel gave the correct answer to your question, pointing to the documentation:
the actual type of that function or property will be the declared supertype of the anonymous object, or Any if you didn't declare any supertype.
But just adding that if you really need to access example3.field.method() you could declare a supertype to field in Example3:
interface MyInterface {
fun method()
}
class Example3 {
val field = object: MyInterface {
override fun method() {}
}
}
fun main() {
val example3 = Example3()
example3.field.method()
}

Kotlin: function delegation

I have a project that depends heavily on delegation and composition in Kotlin. Delegating properties is a breeze, but conceptually I'm not completely sure how to achieve delegation for functions in circumstances where the functions depend on other composed properties. I'd like to do something like this:
interface A {
val a: String
}
class AImpl: A {
override val a = "a"
}
interface B {
val b: String
}
class BImpl: B {
override val b = "b"
}
interface C<T> where T: A, T: B {
fun c() : String
}
class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
override fun c() = ab.a + ab.b
}
// works
class ABC : A by AImpl(), B by BImpl()
// does not work
class ABC : A by AImpl(), B by BImpl(), C<ABC> by CImpl(this)
Of course, this type of thing would be achievable with the following:
interface A {
val a: String
}
class AImpl: A {
override val a = "a"
}
interface B {
val b: String
}
class BImpl: B {
override val b = "b"
}
interface C<T> where T: A, T: B {
fun c() : String
}
class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
override fun c() = ab.a + ab.b
}
class AB : A by AImpl(), B by BImpl()
class ABC(ab: AB = AB(), c: C<AB> = CImpl<AB>(ab)) : A by ab, B by ab, C<AB> by c
but this feels clunky as it requires passing in objects for composition which bloats the size of the constructors - it would be cleaner for me to initialize the objects at the site of the class itself as they have no use outside of the class. Is there an elegant way to this with delegation and/or extensions?
You can make C extend A and B instead of passing to it a delegate. e.g.:
interface C : A, B {
fun c(): String
}
abstract class CImpl() : C {
abstract override val a: String
abstract override val b: String
override fun c(): String = a + b
}
class ABC : A by AImpl(), B by BImpl(), CImpl()
You can also do this with a default implementation in C without a CImpl:
interface C : A, B {
fun c(): String = a + b
}
class ABC : A by AImpl(), B by BImpl(), C
I don't think this is currently supported very well, but there's an issue that tracks this and related feature requests. (See Peter Niederwieser's comment on the issue.)

How to implement an abstract getter with property

I have java code:
public abstract class A {
abstract int getA()
}
I tried:
class B : A() {
val a = 0
}
Doesn't compile.
class B : A() {
override val a = 0
}
Still doesn't compile.
class B : A() {
override val a: Int get () = 1
}
Still doesn't compile.
class B : A() {
override val a: Int override get () = 1
}
Still doesn't compile.
class B : A() {
val a: Int override get () = 1
}
None of them are working. Does that mean I can only use
class B : A() {
override fun getA() = 1
}
? I think the last one(overriding the method) is ugly.
This could be worse when you have a getter-setter pair. It's expected to override getter-setter pair with a var property, but you have to write two methods.
According to #Miha_x64 ,
functions can be overriden only with a function.
Seems that I was trying something impossible.