Search code examples
androidkotlincase-when

How to cope with when exhaustive issue if i don't have nothing to return i case of else?


I have a code that logically can have only 3 values. But the when assignment is on a Int variable type. What can i do, if i don't have a RecyclerView.ViewHolder object to return if non of the "cases" in the when expression won't happen (a situation that can't be). I can solve it with "ugly" solution that if 'else' so return of one of the RecyclerView.ViewHolder that i'm returning in the existing cases, but i want to know if there is more elegant way to deal with this situation. I have the following code:

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType)
     {
         DataTypesEnum.COUNTRY_ITEM.ordinal -> CountryDataItem.onCreateViewHolder(parent)
         DataTypesEnum.LEAGUE_ITEM.ordinal -> LeagueDataItem.onCreateViewHolder(parent)
         DataTypesEnum.GAME_ITEM.ordinal ->  GameDataItem.onCreateViewHolder(parent)
     }
}

the compiler says that :

when' expression must be exhaustive, add necessary 'else' branch


Solution

  • [I] want to know if there is more elegant way to deal with this situation.

    If you're absolutely sure that the viewType index will be in the right range, you can get the enum from the list. Then you'll just need to switch on that enum.

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
      return when (DataTypesEnum.values()[viewType])
      {
        DataTypesEnum.COUNTRY_ITEM -> CountryDataItem.onCreateViewHolder(parent)
        DataTypesEnum.LEAGUE_ITEM -> LeagueDataItem.onCreateViewHolder(parent)
        DataTypesEnum.GAME_ITEM ->  GameDataItem.onCreateViewHolder(parent)
      }
    }
    

    I agree with J. Hegg's response in that you should be cautious!


    Update 2020-11-23 with further context:

    I'm just very curious how the line (DataTypesEnum.values()[viewType]) makes all the when return statement to be exhaustive and prevent from the compiler to complain on exhaustive issue?

    In your initial example you switch on an Int type.

    when (viewType) {
      // ...
    }
    

    Therefore, to make the complier happy with viewTypes, you either need to cover all possible values of Int, or include an else statement in the when block.

    My suggestion maps the Int type to the corresponding DataTypesEnum before switching on it. That way, the when block only needs all DataTypesEnum options accounted for to be exhaustive.

    DataTypesEnum.values() returns an Array<DataTypesEnum> of all of the DataTypesEnum in order which is very similar to using the #ordinal values in your solution.

    The next step is to get the value from the array, which I use the index access operator [ ].

    DataTypesEnum.values()[viewType]
    // is the same as
    DataTypesEnum.values().get(viewType)
    

    That should do the trick!

    If you're not sure if viewType will fall into the right range, you might want to check the value so you don't hit an IndexOutOfBoundsException.

    Hopefully that answers your question!