I have a hierarchy of classes (one abstract base c...
# getting-started
r
I have a hierarchy of classes (one abstract base class, 3 sub classes). I need all sublcasses to have a method foo(). but it needs to be static. The implementation for each subclass's method will be different, so it also needs to be abstract. How can I create foo() as an abstract static method on the base class? I have looked and it does not seem possible in kotlin to have a method as both abstract and static.
j
How would you use it? I mean what's the point of enforcing the presence of a static method via subtyping ? Could you please give an example on what you're trying to do? In Kotlin, you can make the companion object of each of these classes implement an interface, so you can achieve this static access on every class, but I'm still not sure what you're trying to do with it.
r
I will give an example soon. It is for implementing a command handler, via the chain of responsibility design pattern
I want each command to statically have a match(message: String): Boolean function
then I will do something like handlers: KClassCommandHandler for command in handlers { if command.match(message) { executor = command(some_lifetime_data) // instantiate executor.execute()
we only instantiate a command executor if the match returns true.
j
Then I really think you should use companion objects instead
r
@Joffrey I'm not sure how to get that working
Copy code
abstract class CommandHandler (
    val parts: String
) {
    companion object {
        abstract fun match(str: String): Boolean
    }
    private fun format(str: String): List<String> {
        return str.split(" ")
    }
    abstract fun execute()
}

class HelpCommand : CommandHandler() {
    companion object {
        override fun match(str: String): Boolean {
            return str.startsWith("help")
        }
    }

    override fun execute() {
        // print help stuff ...
    }
}

class Main {
    val handlers: List<KFunction<CommandHandler>> = listOf(::HelpCommand)
    val input = readln()
    for (command. in handlers) {
        if (command.match(input)) {
            command(input).execute()
        }
    }
}
further research, looks like this is just not possible
Kotlin's type system is not powerful enough to express this sort of thing
j
If your command classes don't have any constructor arguments nor state, they could even be `object`s themselves (singletons). If they do need arguments, then using companion objects would do, but you have to make the companions themselves implement an interface (if you need this)
r
the command classes take in the original message as the constructo rargument
command("goto kingdom").execute()
j
(By the way, for this use case I suggest you use Clikt, which is a very nice CLI library for Kotlin)
r
ill check it out. though this is for a student's project where i want him to get to experience all the problems that crop up in creating a CLI from scratch
j
Ah ok, then that rules out the lib
r
he's quite good at OOP so he was liking the idea of a static abstract method approach when i told him about it
guess we will just have to not do static
j
The Kotlin equivalent of static is using the companion, but indeed it's quite decoupled from the class. So there will be no real link between the companion and the class itself (besides the convenience of using the command class name to refer to the companion)
r
i see
what about
I can do stuff like command::class, could I extend that?
add my own stuff
command::match()?
j
Copy code
interface CommandType<T : CommandHandler> {
    fun matches(str: String): Boolean
    fun create(command: String): T
}

abstract class CommandHandler (
    val parts: String
) {
    private fun format(str: String): List<String> {
        return str.split(" ")
    }
    abstract fun execute()
}

class HelpCommand(parts: String) : CommandHandler(parts) {
    companion object : CommandType<HelpCommand> {
        override fun matches(str: String): Boolean = str.startsWith("help")
        override fun create(parts: String) = HelpCommand(parts)
    }

    override fun execute() {
        // print help stuff ...
    }
}

fun main() {
    val handlers: List<CommandType<*>> = listOf(HelpCommand)
    val input = readln()
    
    for (commandType in handlers) {
        if (commandType.matches(input)) {
            commandType.create(input).execute()
        }
    }
}
r
yeah that is pretty close to just doing a Factory pattern
which is what i was considering
j
Yeah it's basically that, but using companions as factories so you can get this "static" feeling by referencing command types using the command class names
w
No, abstract static members are not possible in Kotlin sadly unlike most other modern statically typed languages. In Kotlin one either uses OOP (factories) or functional (type classes) approach for this behavior.
r
@Joffrey yeah that does avoid having to create n*2 classes, where every Command class needs a corresponding CommandFactory class. I like that
@Wout Werkman :👍 sounds good, thanks
but what are functional (type classes)?
w
theSwiftSnippetIfYouAreInterestedByTheWay.cpp