Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Unreachable code detected

Discussion in 'Scripting' started by Marscaleb, Apr 2, 2020.

  1. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    996
    This is pretty minor, but it kinda bugs me...

    I'm getting compiling warnings for "unreachable code detected." And yeah, it is currently unreachable, but they are just little bits that we are supposed to have for good practice.

    My function returns a sprite for a world map avatar. I have unreachable code in the form of my "break" lines between cases. I also have a final failsafe/default return value at the end of the function that is deemed unreachable.

    I feel a bit torn here. On one hand, I don't want to get these warnings about unreachable code every time I compile (and neither do I want to disable these in case I make unreachable code somewhere else,) and on the other hand I feel like those bits should be left in, as good practice, in case I ever make revisions that don't execute as cleanly as I want.

    Code (CSharp):
    1. Sprite FindCurrentSprite(byte thisFrame)
    2.     {
    3.  
    4.         switch (facingAngle)
    5.         {
    6.  
    7.             case float n when n >= 45 && n < 135 || (n <= -225 && n > -315):
    8.                 if (thisFrame == 1)
    9.                     return WalkingFrames.North1;
    10.                 else if (thisFrame == 3)
    11.                     return WalkingFrames.North3;
    12.                 else
    13.                     return WalkingFrames.North2;
    14.                 break;
    15.  
    16.             case float n when Mathf.Abs(n) >= 135 && Mathf.Abs(n) < 225:
    17.                 if (thisFrame == 1)
    18.                     return WalkingFrames.West1;
    19.                 else if (thisFrame == 3)
    20.                     return WalkingFrames.West3;
    21.                 else
    22.                     return WalkingFrames.West2;
    23.                 break;
    24.  
    25.             default:
    26.             case float n when (n >= 225 && n < 315) || (n <= -45 && n > -135):
    27.                 if (thisFrame == 1)
    28.                     return WalkingFrames.South1;
    29.                 else if (thisFrame == 3)
    30.                     return WalkingFrames.South3;
    31.                 else
    32.                     return WalkingFrames.South2;
    33.                 break;
    34.  
    35.             case float n when Mathf.Abs(n) >= 315 || Mathf.Abs(n) < 45:
    36.                 if (thisFrame == 1)
    37.                     return WalkingFrames.East1;
    38.                 else if (thisFrame == 3)
    39.                     return WalkingFrames.East3;
    40.                 else
    41.                     return WalkingFrames.East2;
    42.                 break;
    43.  
    44.         }
    45.  
    46.         return WalkingFrames.South2;
    47.     }
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'd ignore the warning, or rewrite it as below. It should function the same as your version without the warnings.


    Code (CSharp):
    1. Sprite FindCurrentSprite(byte thisFrame)
    2.     {
    3.  
    4.         Sprite returnSprite = WalkingFrames.South2;
    5.         switch (facingAngle)
    6.         {
    7.  
    8.             case float n when n >= 45 && n < 135 || (n <= -225 && n > -315):
    9.                 if (thisFrame == 1)
    10.                     returnSprite =  WalkingFrames.North1;
    11.                 else if (thisFrame == 3)
    12.                     returnSprite = WalkingFrames.North3;
    13.                 else
    14.                     returnSprite = WalkingFrames.North2;
    15.                 break;
    16.  
    17.             case float n when Mathf.Abs(n) >= 135 && Mathf.Abs(n) < 225:
    18.                 if (thisFrame == 1)
    19.                     returnSprite = WalkingFrames.West1;
    20.                 else if (thisFrame == 3)
    21.                     returnSprite = WalkingFrames.West3;
    22.                 else
    23.                     returnSprite = WalkingFrames.West2;
    24.                 break;
    25.  
    26.             default:
    27.             case float n when (n >= 225 && n < 315) || (n <= -45 && n > -135):
    28.                 if (thisFrame == 1)
    29.                     returnSprite = WalkingFrames.South1;
    30.                 else if (thisFrame == 3)
    31.                     returnSprite = WalkingFrames.South3;
    32.                 else
    33.                     returnSprite = WalkingFrames.South2;
    34.                 break;
    35.  
    36.             case float n when Mathf.Abs(n) >= 315 || Mathf.Abs(n) < 45:
    37.                 if (thisFrame == 1)
    38.                     returnSprite = WalkingFrames.East1;
    39.                 else if (thisFrame == 3)
    40.                     returnSprite = WalkingFrames.East3;
    41.                 else
    42.                     returnSprite = WalkingFrames.East2;
    43.                 break;
    44.  
    45.         }
    46.  
    47.         return returnSprite;
    48.     }
     
    Owen-Reynolds likes this.
  3. kasztelan

    kasztelan

    Joined:
    Nov 3, 2014
    Posts:
    11
    I think you should remove the bits that are unreachable, if in future you'll forget to return a sprite somewhere you'll get compiler error that not all code paths return a value. Same with "break"s, if your case won't handle all the scenarios (that means no else clause) then the compiler will complain about missing break statement. So you should be covered on both fronts.

    Also what is the purpose of that default in line 25 before two more cases?
     
  4. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    996
    @Joe-Censored Hmm, that's a clever way to handle it.

    Uhh, are you sure about that? If there are no "breaks" doesn't that just mean the code is expected to drop through? Isn't that a legal design?
    Maybe I'm wrong but I thought it was.

    The default result (in case it is ever sent garbage data) is identical to the "south" result. Rather than duplicate the code I just have it fall through.
     
    Last edited: Apr 2, 2020
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Yeah I ran into this myself before, and generally never return from within a switch to avoid this annoyance. I like leaving the breaks in too, because I've commented out a return before while debugging and ended up with madness :p . So now I just return after the switch like what I posted above.
     
  6. kasztelan

    kasztelan

    Joined:
    Nov 3, 2014
    Posts:
    11
    In c# you can't have fall through if the case statement is not empty, just try to remove both else statement and break, you should get compiler error

    Ahh ok now I see it, I'm used to always putting default after the case so I didn't get it at first :)
     
  7. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,926
    If you really want to keep the return-from-middle, you could replace the switch with another cascading IF. Start if off with n=facingAngle to make it nearly identical.