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. Dismiss Notice

Question Return inside If statement

Discussion in 'Scripting' started by Artpen, Jan 5, 2021.

  1. Artpen

    Artpen

    Joined:
    Jan 24, 2015
    Posts:
    291
    Hi guys,

    Need a wee help. I have a function which has to return world position. It works.
    But Unity example suggests to use if statement for finding Raycast intersection.
    It is all good, but compiler wants me to return something at the end in case if statement is false.

    How to do it properly?
    Thank you

    Code (CSharp):
    1. //Convert touch screen position to world position
    2.     public Vector3 ScreenToWorldPosition(Vector2 screenPosition)
    3.     {
    4.         Vector3 worldPosition;
    5.         float distance = 0f;
    6.         Ray ray = Camera.main.ScreenPointToRay(screenPosition);
    7.         Plane plane = new Plane(Vector3.up,Vector3.zero);
    8.  
    9.         if(plane.Raycast(ray, out distance))
    10.         {
    11.             worldPosition = ray.GetPoint(distance);
    12.             return worldPosition;
    13.         }
    14.     }
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    After line 13 but before the closing brace on line 14 you need to either return some value if there is a value that would make sense, or throw an exception if you think it should never happen that the raycast misses.
    Code (CSharp):
    1. public Vector3 ScreenToWorldPosition(Vector2 screenPosition)
    2. {
    3.     Vector3 worldPosition;
    4.     float distance = 0f;
    5.     Ray ray = Camera.main.ScreenPointToRay(screenPosition);
    6.     Plane plane = new Plane(Vector3.up,Vector3.zero);
    7.  
    8.     if(plane.Raycast(ray, out distance))
    9.     {
    10.         worldPosition = ray.GetPoint(distance);
    11.         return worldPosition;
    12.     }
    13.  
    14.     // Either do something like this:
    15.     return Vector3.zero; // or some other value that makes sense if the raycast missed
    16.  
    17.     // Or do this...
    18.     throw new Exception("The raycast missed. This should never happen!");
    19. }
    Third option would be refactor the method with an 'out' parameter for the Vector3 position and have it return a boolean to indicate whether it hit or missed. Sort of like how the raycast call works.
     
    Last edited: Jan 6, 2021
    Bunny83, Artpen and Madgvox like this.
  3. Artpen

    Artpen

    Joined:
    Jan 24, 2015
    Posts:
    291
    Thank you @PraetorBlue
    Stumble upon this problem a couple of times before... now I now how to fix it.
    Is throw new Exception (); considered to be a good practice or is it better to refactor the method?
     
  4. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    Throwing exceptions is a very expensive thing to do at runtime. In many programs, an exception is only thrown when the program cannot continue and fails to repair the error, leading to the shutdown of the program itself. Think about a program running out of memory, a buffer overflow or other cases where the program itself doesn't, can't know what to do.

    From my modest point of view, you should avoid throwing exceptions yourself as much as possible. If you absolutly want some check and ensure that certain conditions are met, you can use assertions. While an assertion throws an exception as well, you can easily add context to it and give yourself a better understanding what is wrong, as well as handle and resolve the exception. Vanilla C# goes even further with code contracts.

    As for your current situation, you could use the out keyword to avoid throwing an exception, changing your method signature of ScreenToWorldPosition accordingly. Although the out keyword isn't inherently good and there are people arguing that one should not use it for various reasons, it allows you to write code that doesn't rely on expensive exceptions while still checking for success. In your code,
    plane.Raycast()
    actually makes use of this boolean return value and handing over the result of the method with the out keyword.
     
    Artpen likes this.
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    I don't know. It really depends on how you are planning to use this method. Are you expecting the raycast to ever miss? If there's a possibility that the raycast will miss during the normal course of gameplay, I would refactor, as you do not want to do exception handling as part of your normal game logic.

    If it's something that should never happen, an exception is good in my opinion. Performance doesn't really matter too much because it's not something that will be happening as part of the normal execution of your game. It happens in exceptional circumstances. It will also blow up your whole call stack. So it won't just stop your current method from running but also any code that comes after the call to your method and so forth. It's basically a way for your game to loudly fail in a way that is obvious so that you can go fix it if it happens. If you do get the exception, it means one of your assumptions (in this case that the raycast would never miss) was invalid, and a sign that you need to rethink your assumptions and your code. The best case scenario is that exception is never thrown.
     
    Artpen likes this.
  6. Artpen

    Artpen

    Joined:
    Jan 24, 2015
    Posts:
    291
    Thank you Guys,

    I don't think my method (Raycast) will ever fail as I have an infinite plane just now to be able to pan/zoom/orbit camera.
    In future I see it possibility to fail due to mask, but not now.

    Can this work for now?
    Code (CSharp):
    1. //Convert touch screen position to world position
    2.     public Vector3 ScreenToWorldPosition(Vector2 screenPosition)
    3.     {
    4.         Vector3 worldPosition;
    5.         float distance;
    6.         Ray ray = Camera.main.ScreenPointToRay(screenPosition);
    7.         Plane plane = new Plane(Vector3.up, Vector3.zero);
    8.  
    9.         plane.Raycast(ray, out distance);
    10.  
    11.         worldPosition = ray.GetPoint(distance);
    12.         return worldPosition;
    13.  
    14.     }