1

I'm trying to write the Kotlin equivalent of what could look like this in Swift:

protocol Parseable {
  static func parse(json: JSON) -> Self
}

I could not find how to define an interface with a requirement on a static method, nor how to reference to the implementing type in the interface.

Guig
  • 9,891
  • 7
  • 64
  • 126
  • What exactly does `self` mean? Is it the same as `this` in java? If yes, then there is no way to write code such as above, because static methods don't have access to a `this reference`. You can look more [here](https://stackoverflow.com/questions/51387309/returning-a-class-object-from-static-method) – Andrew Aug 05 '21 at 21:32
  • I think this is a generic interface using CRTP. – Boris the Spider Aug 05 '21 at 21:37

3 Answers3

2

I don't know Swift, but it looks like you're talking about a ‘self type’ — which represents the type of the class implementing the interface.

Unfortunately, Kotlin doesn't have self types.  (See here for a very long-lasting discussion on the prospects of it being added.)

The usual workaround in Kotlin (and Java) is to make the interface generic, and give the implementing class as a type parameter.  (I don't think there's a specific name for this pattern, but the equivalent in C++ is known as the curiously-recurring template pattern.)

However, the method in question is static, and so that pattern doesn't apply directly.

What you have there looks like a factory, and there are several ways that could be implemented — I'm not sure which best matches your Swift code, but each one can use generics.  You could have a factory class, with one instance for each type of Parseable that you want to create; in that case, the factory class could have a type parameter.  Alternatively, you might have a singleton factory object, or a companion object, or a top-level factory function; in those cases, the function itself can be generic.

Here's what factory function might look like:

fun <P : Parseable> parse(json: JSON): P {
    // Code that returns a value of type P
}

(In practice, you'd probably find you'd need access to some of the details of P, which aren't normally available at runtime due to type erasure.  But you can work around that by making P reified — which also needs the function to be inline.)

Depending on the context, the caller might need to specify the type, e.g.:

val result = parse<MyParseable>(json)

(The IDE will usually let you know if you need to provide the type, or whether the compiler can infer it.)

gidds
  • 16,558
  • 2
  • 19
  • 26
1

Instead of static, Kotlin has companion objects which are practically similar.

We can do what looks like static inheritance by extending a class or implementing an interface on a companion object. And there is no self-type, but we can use generics.

interface Parseable <T> {
    fun parse(json: Json): T
}

class Foo {
    companion object: Parseable<Foo> {
        override fun parse(json: Json): Foo {
            TODO("Not yet implemented")
        }
    }
}

fun testParsingFoo(json: Json) {
    Foo.parse(json)
}

I'm not versed well in Swift, so let me know if I'm misunderstanding the question. But I think this is the Kotlin equivalent of what you're asking.

Trevor
  • 1,349
  • 10
  • 16
0

One way you could get behavior similar to a self type, which Kotlin doesn't have, is to create an extension function outside the interface with a generic receiver.

interface Parseable {
    
}

fun <T: Parseable> T.parse(json: JSON): T {
    // implementation
    return this
}

This extension function can be called on anything that implements Parseable and will return the instance it was called on, and the compiler will recognize it as its own type, not just Parseable.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154