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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

What is Out syntax of C# and what does it actually do?

Discussion in 'Scripting' started by GTHell, May 15, 2016.

  1. GTHell

    GTHell

    Joined:
    Jan 5, 2016
    Posts:
    256
    Hi,

    I have this code from Unity in action:
    Code (CSharp):
    1. void Update (){
    2.         if (Input.GetMouseButtonDown (0)) {
    3.             Vector3 point = new Vector3 (_camera.pixelWidth / 2, _camera.pixelHeight / 2, 0);
    4.             Ray ray = _camera.ScreenPointToRay (point);
    5.             RaycastHit hit; // From here, I start to confuse with these code....
    6.             if (Physics.Raycast (ray, out hit)) {           //Out, RaycastHit.....
    7.                 StartCoroutine (SphereIndicator (hit.point));   //SphereIndicator is a function to create and delete Sphere every 1 second....
    8.             }
    9.         }
    10.     }
    I understand everything but start from RaycastHit, everything give me a headache.
    Please explain out to me as it give a me a light to understand other code.

    It would be great if you help me explain all the code started aat RaycastHit hit :D
     
  2. HellSinker

    HellSinker

    Joined:
    Apr 18, 2013
    Posts:
    65
    When you pass a variable to a function - they can be of three types, input, output, and input/output.

    Normally you send your data as input, and this requires no special keyword.

    If you use the keyword "out" then the function must set a value to that variable, i.e. it must output a value.

    If you use the keyword "ref" then the function can take a value in that slot, and alter it to a new value.

    Here is some pseudo code to explain It a little better,,,

    Code (csharp):
    1.  
    2. class StaticFunction
    3. {
    4. static bool DoMath(float a, ref float b, out float c)
    5. {
    6. c=a+b;//we initialize a new value to c using a and b, this value will be assigned to the variable.
    7. b-=a;//we change the value of b, the variable will be updated
    8. if (b>=0.0f) return true;
    9. else return false;
    10. }
    11. static void Main()
    12. {
    13. float a=1.0f;
    14. float b=2.0f;
    15. float c;//This variable has no value assigned to it....
    16. if (DoMath(a,ref b,out c)) Console.Write(a.ToString()+" "+b.ToString()+" "+c.ToString());
    17. else Console.Write("B Is below zero!");
    18. }
    19. }
    20.  
    a is for input..
    b is for input/output
    c is for output only!

    The main advantage for this is to be able to return multiple values from a single function...

    In the case of the above function which you are trying to get your head around, it returns two values - a bool indicating success/failure and possibly some other data in the Hit variable...
    http://docs.unity3d.com/ScriptReference/Physics.Raycast.html and http://docs.unity3d.com/ScriptReference/RaycastHit.html have more information on what is being passed where.... essentially out Hit will return a RaycastHit structure to the Hit variable...
     
    Last edited: May 15, 2016
  3. GTHell

    GTHell

    Joined:
    Jan 5, 2016
    Posts:
    256
    Say that if the Hit's value is 9 then the it will return the 9 to the RaycastHit structure to the Hit variable as well?
    I'm still confusing about this.
     
  4. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,739
    yes more or less, normally arguments given are used for input, and normally you would not be able to write to a struct passed in that way, but using the out keyword the method can now write to what was passed into that argument.

    when you use it with raycast it is writing out to a already existing RaycastHit struct, that you passed in.
     
  5. HellSinker

    HellSinker

    Joined:
    Apr 18, 2013
    Posts:
    65
    Something like that - except the return structure has more than one value - it is essentially a class of information.

    http://docs.unity3d.com/ScriptReference/RaycastHit.html

    Every entry listed in the Variables section of that page will be returned in the Hit Variable, you can access the data like so...

    if (Hit.distance<9.0f) return;//or do something...

    Collider ObjectHitByRay = Hit.collider;//gets the object the ray hit...

    int TriIndex = Hit.triangleIndex;//gets the exact tri/poly that the ray collided with, a usage example combined with the Hit.collider example above should be evident...
     
  6. HellSinker

    HellSinker

    Joined:
    Apr 18, 2013
    Posts:
    65
    BTW - if you want a rather verbose answer on how it works I can give you it, but its roots are buried in C++/C languages and even then the practice was commonly used with assembler before then, without trying to confuse you too much consider this;

    Code (csharp):
    1.  
    2. class ImaClass
    3. {
    4. static void Function(int a)
    5. {
    6. a=0;
    7. }
    8. }
    9.  
    When you call this function with some code, say like
    Code (csharp):
    1.  
    2. int b=2048;
    3. ImaClass.Function(b);
    4.  
    The number gets handed to the function...
    But, if you use the ref keyword, instead imagine that the memory location of b gets handed to the function, and any changes made are updated in that variable, rather than the copied version above.... Furthermore, if you use the out keyword, then b will be overwritten with the results produced by the function, a little note about out; if, in the function, you do not set a value to the out variable, your code won't compile....
     
    Shadowhunter072 and The7thNoodle like this.
  7. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    out and ref are meant as "safe replacements" for pointers.
    Code (csharp):
    1. int someNumber = 0;
    2.  
    3. // You don't actually pass someNumber, but create a copy of it.
    4. // Whatever you do with someNumber inside the method
    5. // does not change the value of someNumber here.
    6. FunctionThatDoesSomething(someNumber);
    Sometimes that's a problem. Sometimes you actually want someNumber to change. Well, then you just return it. But what if you can't? Look at the following example.
    Code (csharp):
    1. int FindANumberSomewhere(int number) {
    2.     int ret;
    3.     // Search the number in some kind of datastructure
    4.     // ...
    5.     return ret;
    6. }
    Seems fine, but what do you do, if the number isn't found? Return -1? How do you search for -1 then? The way you are forced to deal with this situation in Java is with exceptions. You just throw an exception inside the method and catch it outside. Microsoft drastically improved upon Java and one place where you can see this is here: You don't have to anymore.
    You solve the problem as you would in C and C++. You return whether you found the number.

    Code (csharp):
    1. bool FindANumberSomewhere(out int number) {
    2.     bool found;
    3.     // Search the number in some kind of datastructure
    4.     // ...
    5.     return found;
    6. }
    Code (csharp):
    1. // ...
    2. int num = 0;
    3. if(FindANumberSomewhere(out num)) {
    4.     // Do something with the found number
    5. }
    6. else {
    7.     // Handle it not being found
    8. }
    9. // ...
    This way is a) much easier to read than producing try/catch (and possibly finally) blocks left and right and b) much faster.
     
  8. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    This is a tricky one. I'll first explain it in terms of just Raycasting in Unity. Then I'll hit out specifically. Hope fully between the dozen or so explanations you'll find something.

    Short answer

    out is a way to allow a function to return two values. So a RayCast returns both a bool (did I hit something) and a RayCastHit (what did I hit).

    Why have two values instead of rolling both into a single return type? That's because you aren't always interested in what a raycast hits. If you don't need a return value you can leave it out. Unity won't bother calculating the data, making the operation more performant.

    Long answer

    out and ref both allow a parameter to be passed by reference instead of by value. Normally when a parameter is passed into a function a copy is made on the stack. For value types the whole type is copied. For reference types the reference is copied.

    When using out and ref you don't get a copy on the stack. Instead you get a reference back to an earlier location on the stack. This means you can change the value of a value type in an outer function. You can also change where a reference in an outer function points.

    The main difference between out and ref is in intent. ref indicates that the parameter has been declared and initialised outside the function, and the function can modify it. out indicates that the parameter has been declared but not initialised outside of the function, the function has the responsibility to initialise it.

    out and ref are normally to be avoided. When using out and ref the called function must make assumptions about the calling function. This breaks proper encapsulation, and generally makes things more complex. There are some cases where it makes sense to use it, but tread lightly.
     
  9. GTHell

    GTHell

    Joined:
    Jan 5, 2016
    Posts:
    256
    I think I get it 70% but I don't know when I'm going to use it again beside Raycasting because it seem a little bit hard to understand.
     
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    You'll probably use it again, because there's other parts of the API that use it as well.
     
  11. The7thNoodle

    The7thNoodle

    Joined:
    Apr 5, 2015
    Posts:
    3
    Not to resurrect a kinda dead thread, but do these posts still stand true?
    I understand how out and ref works but are they really considered bad practice?
    How important is proper encapsulation in a C# environment like Unity that's less modular with it's libraries?
    I know good practices are somewhat subjective at times but I'm kinda new to programming in Unity and while I can already see many uses in using out and ref in player behavior functions, I'm not sure if I should start to.
     
  12. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I wouldn't call out/ref bad practice. I would say though that overuse of them would be a code smell to me and I'd investigate the intent of the usages and consider a possible refactoring if it needs it. Case in point the 'Physics.Raycast' method that takes an out parameter of RaycastHit isn't "bad", it's a perfectly suitable usage of it.

    Important to use encapsulation is up to you. If you want to utilize strong OOP principles, than yeah, it's important. But if you aren't... then it's not needed. Rather instead of if it's bad/not... instead consider WHY you're using it or not.
     
  13. The7thNoodle

    The7thNoodle

    Joined:
    Apr 5, 2015
    Posts:
    3
    I understand, so for example in my game project,
    In my update() I do 4 raycasts to align my character with the ground as typical as that is, I then want to use a function to compute the new up vector, I could be passing the hit data to the function or use a ref to pass the data instead.
    Does using ref make a difference here for performance?
    Is it proper form even?
    Am I even considering it in the proper context?
     
  14. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    The primary reason you'd use 'ref' is to allow the method you've called the ability to modify what you've passed in. In the case of structs/value types, it means we can update the struct/value and the calling code has its member updated as well. In the case of a reference type (class), it means the variable will be updated.

    Give you an example of a use case for 'ref':
    Array.Resize
    https://docs.microsoft.com/en-us/dotnet/api/system.array.resize?view=netframework-4.8

    Array.Resize takes in a reference type (an array is a class, and therefore a reference type). The reason it takes it in by 'ref' is because it's not actually resizing an array. It's creating a new array of the size in question, copying the contents of the passed in array to it, and making sure that the variable you passed it in as is updated to this new reference.

    This is an example of how 'ref' to a reference type is beneficial.

    ...

    For a value/struct type you could see an example like Interlocked.Increment:
    https://docs.microsoft.com/en-us/do...g.interlocked.increment?view=netframework-4.8

    This increments an int/long as an atomic operation. It's done by 'ref' so that the variable you want incremented is done so all self contained in the method as an atomic operation. If it had returned a value the 'setting' of the variable wouldn't be part of the atomic operation and thusly could come out of sync in a threaded situation.

    To see what I mean... when you say any of these:
    Code (csharp):
    1. i++;
    2. i += 1;
    3. i = i + 1;
    (note the first 2 are really just syntax sugar for the last one)

    What the program actually sees this as, is:
    Code (csharp):
    1. copy i into operating registry r1
    2. copy 1 into operating registry r2
    3. sum r1 and r2 placing result in r1
    4. set i to r1
    In IL you can see this:
    Code (csharp):
    1.  
    2.     IL_0003: ldloc.0      // i
    3.     IL_0004: ldc.i4.1
    4.     IL_0005: add
    5.     IL_0006: stloc.0      // i
    6.  
    (note again, all 3 ways of writing that compile to the same IL)

    In a threaded situation if you did i++ simultaneously... both could interweave at any point in that statement chain.

    If you have method like so:
    Code (csharp):
    1. int Increment(int value)
    2. {
    3.     return value + 1;
    4. }
    5.  
    6. i = Increment(i);
    What the program actually sees is:
    Code (csharp):
    1. allocate stack frame for function 'Increment'
    2. copy the value of i onto call stack for 'value'
    3. copy value into operating registry r1
    4. copy 1 into operating registry r2
    5. sum r1 and r2 placing result in r1
    6. drop stack frame
    7. place result at position of stack frame
    8. set i to result
    There's even more odds of interweaving here.

    By adding in the 'ref', we're no longer copying in the value of i, we instead reference the location of i in memory. Now that Interlocked.Increment has that location/address it can create a lock on that address... while it's locked no other lock can be established until it is released. So we result in:
    Code (csharp):
    1. void Increment(ref int value) ...
    2. Increment(ref i);
    Is:
    Code (csharp):
    1. allocate stack frame for function 'Increment'
    2. copy the address of i onto call stack for 'value' ('value' and 'i' both point at the same address)
    3. lock the address of 'value'
    4. copy value into operating registry r1
    5. copy 1 into operating registry r2
    6. sum r1 and r2 placing result in r1
    7. set value to r1 (and thusly setting i to r1 as well since they're both the same address)
    8. release lock
    9. drop stack frame
    By doing this, we ensure that i isn't volatile for the duration of the operation. It's all atomic.

    If we had returned the result, the operation would become volatile, and we couldn't control the order at which i is set.
     
    Last edited: Dec 26, 2019
    The7thNoodle likes this.
  15. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    With those basic examples of use cases... to your question of:
    It can and it can't.

    So lets say you're running a 32-bit program and you take in an 'int'. Copying an int to the stack frame, or copying the address of an int to the stack frame is basically the same cost since we're talking about 4 bytes of data either way (int is 32-bits, a ref is 32-bits).

    If say it was a Vector3, well now a copy is 12 bytes of data, and a ref is 4 bytes. Is there more time to copy 12 bytes vs 4 bytes?

    Sure! It's approximately 3 times longer.

    Will you notice???

    No... likely not. You'd have to be doing this so frequently it's absurd. The frequency would have to be so high that there are most likely going to be other things you could optimize away instead... like, inlining the function/method rather than calling/allocating a stack frame for that function/method.

    Where it'd start getting noticeable is for VERY LARGE structs. But this is why Microsoft suggests you don't create very large structs.
    https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct

    Use ref for what it's intended for. Not for optimization.

    ref is used to pass the address of a variable rather than what is in the variable. (address is being used very loosely here... managed languages get a little wonky on what an address is)

    And this is why I led with an example of ref in use in the .net framework. So you can see why Microsoft chose to use it. It had nothing to do with optimization, and everything to do with what the method is attempting to accomplish.
     
    The7thNoodle likes this.
  16. The7thNoodle

    The7thNoodle

    Joined:
    Apr 5, 2015
    Posts:
    3
    Both of these responses are very much appreciated.
    I understand out and ref much better now and the examples
    gave me a better perspective on the context they should be implemented in.