vinivendra / Gryphon

The Swift to Kotlin translator.
https://vinivendra.github.io/Gryphon/
Other
609 stars 46 forks source link

Support for Enum as Sealed classes #109

Closed rlinoz closed 3 years ago

rlinoz commented 3 years ago

Is your feature request related to a problem? Please describe. Today it is not possible to create more elaborated enums, for example:

enum Foo {
    case t1(value: String)
    case t2(value1: String, value2: String)

    func get() -> String {
        switch self {
        case .t1(let value):
            return value
        case .t2(let value1, let value2):
            return value1 + value2
        }
    }
}

Describe the solution you'd like I believe the equivalent in Kotlin would be a sealed class, which would look like this:

sealed class Foo {
    data class T1(val value: String) : Foo()
    data class T2(val value1: String, val value2: String) : Foo()

    fun get(): String {
        when (this) {
            is T1 -> return value
            is T2 -> return value1 + value2
        }
    }
}

and for cases where the enum has no parameter, for instance if we added a case t3, it would output object T3 : Foo()

vinivendra commented 3 years ago

Hey @rlinoz, thanks for the feedback. I'll look into it as soon as I get a chance.

vinivendra commented 3 years ago

So, I finally found time to take a look. What you're trying to do here is technically supported, just not with the syntax you're using. Try this:

// Swift

enum Foo {
    case t1(value: String)
    case t2(value1: String, value2: String)

    func get() -> String {
        switch self {
        case let .t1(value: value):
            return value
        case let .t2(value1: value1, value2: value2):
            return value1 + value2
        }
    }
}
// Kotlin translation

internal sealed class Foo {
    class T1(val value: String): Foo()
    class T2(val value1: String, val value2: String): Foo()

    fun get(): String {
        return when (this) {
            is Foo.T1 -> {
                val value: String = this.value
                value
            }
            is Foo.T2 -> {
                val value1: String = this.value1
                val value2: String = this.value2
                value1 + value2
            }
        }
    }
}

Notice that you used case .t1(let value) and I used case let .t1(value: value), so there are two main differences: the let has to be in the beginning, and the value: label has to be present. I can probably fix the first problem and allow lets in the middle of the expression, but the label has to be there (or Gryphon doesn't know what property you're trying to access). That said, the error message for a missing label could be a lot better. I'll work on that.

Thanks for bringing this to my attention :)

PS: if you use this syntax the case t3 should work too.

vinivendra commented 3 years ago

OK, I just pushed a few changes to the development branch that should add support for lets in the middle of the expression and improve the "missing label" error message. Could you check it out for me with brew install vinivendra/gryphon/gryphon --HEAD and tell me if it works?

vinivendra commented 3 years ago

The fix was released in v0.17. Feel free to open the issue again if there are any other problems!