I feel like I'm really missing something, so I wil...
# getting-started
j
I feel like I'm really missing something, so I will appreciate any insight here - I'm trying to get the "redundant else" warning to fire from the Kotlin compiler, and I can't get it to work
my understanding is that, given an exhaustive
when
on an enum, adding an
else
clause should trigger a warning
is that understanding correct?
c
able to see that warning both in IntelliJ and the compiler (via Gradle):
Copy code
w: file:///Users/chrislee/IdeaProjects/clario/clario-app/modules/frontend/phpcgi/src/main/kotlin/clario/fe/phpcgi/FastCgiDecoder.kt:166:21 'when' is exhaustive so 'else' is redundant here
do you have a code snippet of what isn’t working?
j
Copy code
when (vehicle.fuelType) {
            FuelType.DIESEL -> CaFuelTypeEnum.DIESEL
            FuelType.ELECTRIC -> CaFuelTypeEnum.ELECTRIC
            FuelType.FLEX -> CaFuelTypeEnum.FLEX_FUEL
            FuelType.GAS -> CaFuelTypeEnum.GASOLINE
            FuelType.FULL_HYBRID -> CaFuelTypeEnum.HYBRID_GASOLINE_ELECTRIC
            FuelType.PLUG_IN_HYBRID -> CaFuelTypeEnum.HYBRID_GASOLINE_ELECTRIC
            FuelType.CNG -> CaFuelTypeEnum.NATURAL_GAS_POWERED
            FuelType.LPG -> CaFuelTypeEnum.PROPANE
            FuelType.HYDROGEN -> CaFuelTypeEnum.HYDROGEN_FUEL_CELL
            else -> CaFuelTypeEnum.BUTANE
        }
language version 1.8
Kotlin plugin 231-1.8.20-IJ8109.175
c
Doing this flags the else as redundant. Kotlin 1.8 as well.
Copy code
public enum class FuelType {
    DIESEL,
    ELECTRIC
}
public class Test {
    public fun foo(fuelType : FuelType) {
        when(fuelType) {
            FuelType.DIESEL -> TODO()
            FuelType.ELECTRIC -> TODO()
            else -> {}
        }
    }
}
However, this does not - when the type is nullable:
Copy code
public enum class FuelType {
    DIESEL,
    ELECTRIC
}
public class Test {
    public fun foo(fuelType : FuelType?) {
        when(fuelType) {
            FuelType.DIESEL -> TODO()
            FuelType.ELECTRIC -> TODO()
            else -> {}
        }
    }
}
a
does
vehicle.fuelType
come from Java? Is it nullable? What happens if you try
when (vehicle.fuelType!!) {
, or adding a
null -> {}
branch?
c
adding an explicit null check does flag the else as redundant:
Copy code
public enum class FuelType {
    DIESEL,
    ELECTRIC
}
public class Test {
    public fun foo(fuelType : FuelType?) {
        when(fuelType) {
            FuelType.DIESEL -> TODO()
            FuelType.ELECTRIC -> TODO()
            null -> {}
            else -> {}
        }
    }
}
j
no Java involved in this code, and it's not nullable (so adding null generates its own warning)
!! also gets flagged as unnecessary
c
are you certain that all the enumerated values are listed?
j
well, if I remove the else, I also don't get a warning or compile failure
so yes, I'm pretty sure the
when
is exhaustive
c
In IntelliJ for an empty when it offers the option to all remaining branches - may be worth comparing against that to ensure all branches are there.
For example, this no longer generates a redundant else warning as
HYBRID
is not in the when:
Copy code
public enum class FuelType {
    DIESEL,
    ELECTRIC,
    HYBRID
}
public class Test {
    public fun foo(fuelType : FuelType) {
        when(fuelType) {
            FuelType.DIESEL -> TODO()
            FuelType.ELECTRIC -> TODO()
            else -> {}
        }
    }
}
j
if I recreate the when as empty, then have IntelliJ add all branches (which come with TODOs), and then add an else, I still do not get the warning
Copy code
when (vehicle.fuelType) {
            FuelType.CNG -> TODO()
            FuelType.DIESEL -> TODO()
            FuelType.ELECTRIC -> TODO()
            FuelType.FLEX -> TODO()
            FuelType.FULL_HYBRID -> TODO()
            FuelType.GAS -> TODO()
            FuelType.HYDROGEN -> TODO()
            FuelType.LPG -> TODO()
            FuelType.PLUG_IN_HYBRID -> TODO()
            else -> {}
        }
a
If I try recreating your example in Kotlin Playground, I get a warning on the else statement as expected https://pl.kotl.in/Gs4ouSqqj
c
@JasonB what does the source for the enum look like?
j
Copy code
data class Vehicle(
    val vehicleListingId: Int,
    val sellingPriceInCents: Int,
    val vin: String,
    val year: Int,
    val make: String,
    val model: String,
    val bodyType: BodyType,
    val condition: Condition,
    val mileage: Int,
    val priceInCents: Int,
    val fuelType: FuelType,
    val modelCode: String,
    val dealerId: Int,
    val curbWeight: Int?,
    val msrpInCents: Int?,
    val baseMsrpInCents: Int?,
    val accessoryPriceInCents: Int?,
) {

    fun getCurbWeightOrDefault(): Int = curbWeight ?: 3000

    enum class BodyType {
        CHASSIS,
        CONVERTIBLE,
        COUPE,
        HATCHBACK,
        MINIVAN,
        PICKUP,
        SEDAN,
        SUV,
        VAN,
        WAGON,
    }

    enum class FuelType {
        CNG,
        DIESEL,
        ELECTRIC,
        FLEX,
        FULL_HYBRID,
        GAS,
        HYDROGEN,
        LPG,
        PLUG_IN_HYBRID,
    }

    enum class Condition {
        NEW,
        USED,
    }
}
c
hmmm. copying that code directly does show then redundant else warning.
Not able to reproduce that, consistently get warning (unless a branch is omitted or variable is nullable). https://pl.kotl.in/CNmyn8s9X
a
have you suppressed warnings, in the build file https://kotlinlang.org/docs/compiler-reference.html#nowarn or with a
@Suppress(...)
or
@file:Suppress(...)
anywhere?
c
Something like
@Suppress("REDUNDANT_ELSE_IN_WHEN")
j
we do have autogenerated files that have their own suppressions, but never that one, and not on this file
c
does a small sample enum / when show the same behaviour?
j
ok, I think it's an issue with gradle multimodule
if I have an enum in the same module, the check works fine, but if I define the enum in a separate module, it doesn't fire
c
interesting. have a mm project here, let me try it…
yep. This code snippet:
Copy code
public class Test {
    public fun foo(fuelType : Vehicle.FuelType) {
        when(fuelType) {
            Vehicle.FuelType.CNG -> TODO()
            Vehicle.FuelType.DIESEL -> TODO()
            Vehicle.FuelType.ELECTRIC -> TODO()
            Vehicle.FuelType.FLEX -> TODO()
            Vehicle.FuelType.FULL_HYBRID -> TODO()
            Vehicle.FuelType.GAS -> TODO()
            Vehicle.FuelType.HYDROGEN -> TODO()
            Vehicle.FuelType.LPG -> TODO()
            Vehicle.FuelType.PLUG_IN_HYBRID -> TODO()
            else -> {}
        }
    }
}
warns of redundant else when in same module, but not if in different module.
that’s surprising / unexpected.
j
quite 🙂
c
…checking to see if the same happens for a sealed object.
yea. same problem.
j
ok, good to know
appreciate everyone's help, I'll see if this already exists in YouTrack
👍 2
this is intentional!
n
Wow, seems like a terrible idea 😞
c
oh ugh that’s inconsistent. now I need to review a bunch of code to add
else -> error("WTF")
it’s really an artifact of the limited module system in JVM - there’s no distinction between a nicely separated ‘multi-module’ project that is compiled together and any other random JAR dependency pulled in, as any JAR (module) could in theory be replaced at runtime.
👍 2