Jump to content
  • Advertisement
Sign in to follow this  
gsgeek

Unity When are method arguments evaluated in Mono's C#?

This topic is 410 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello all,

 

First of all, sorry if this is kind of a dumb question, but I can't seem to find an answer for it.

Let's say that in a c# project (in my case, a c# script inside a Unity3d game, if that changes something), I have  two methods defined as follows (in pseudo code):

int x;
int y;
​int z;
​int u;
​int v; // these ints are given values depending on the evolution of each game run, so they are not known at compile time.
bool intToBool( int x ) { /*some complex block that computes a bool from the passed argument*/}
int gdc ( int x ) { /* method that takes a int value dependent on the game run 
-that is, not known at compile time- 
and computes another int from it thorugh very complex and expensive calculations*/}

void SomeStuff(int x){} //auxiliar methods called inside myMethod
void OtherStuff(int x){}
void MoreStuff(int x){}

void myMethod(int a, int b, int c, int d, int e){
  /* here goes code that references the arguments by name multiple name, for example:*/
  SomeStuff(a); OtherStuff(b); MoreStuff(c);
  SomeStuff(d); OtherStuff(e); MoreStuff(a);
  SomeStuff(b); OtherStuff(c); MoreStuff(d);
  SomeStuff(e); OtherStuff(a); MoreStuff(b);
  SomeStuff(c); OtherStuff(d); MoreStuff(e);
}
  
 
void myMethodBis(int a, int b, int c, int d, int e){
  if( intToBool( a )) { /*execute statemens*/ }
  else if( intToBool( b )) { /*execute statemens*/ }
  else if( intToBool( x )) { /*execute statemens*/ }
  else if( intToBool( d )) { /*execute statemens*/ }
  else if( intToBool( e )) { /*execute statemens*/ }
}

Further suppose that these methods are going to be called with arguments that are not known at compile time (e.g. because they depend on the evolution of the particular run on the game), like this:

myMethod( gdc(x), gdc(y), gdc(z), gdc(u), gdc(v) );

myMethodBis( gdc(x), gdc(y), gdc(z), gdc(u), gdc(v) );

So, my question is, when are gdc(x)-gdc(v), etc. evaluated?

Are they first computed at the start of the method calls and saved as local variables internally?

Or are they computed each time they are referenced in the method's block?

So, for example, if gdc(x) - gdc(v) are going to be computed regardless of wether they are called in the method's body, and gdc is very computationally intensive, I should rather inline MyMethodBis to save four of these computation.

On the other hand, if they are computed not when the method is invoked but when they are used inside the method body, In myMethod I should first save a-e as local variables so I'm only computing them once, and use the local variables several times through the method's body.

(Bear in mind that the main aim of my question is to know how is the code executed internally, rather than having to do the optimisations I meantion. That has been only the problem that has sparkled the theoretical question).

Thank you in advance for any insight you can give regarding this topic.

Share this post


Link to post
Share on other sites
Advertisement

So, my question is, when are gdc(x)-gdc(v), etc. evaluated? Are they first computed at the start of the method calls and saved as local variables internally?

It's fully defined in the C# language specification. I grabbed a random version from the Interwebs, it seems old, but such basic concepts never change anyway:

 

https://msdn.microsoft.com/en-us/library/aa691335(v=vs.71).aspx

During the run-time processing of a function member invocation (Section 7.4.3), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows:

   ...

So it promises to start with "gdc(x)" and end with "gdc(v)" evaluation (this is relevant if the gcd calls share some data that they modify).

There are lots of complications with reference variables, and null values etc, but that all doesn't apply with "int"

 

The actual call is defined in Section 7.4.3, apparently, which is
https://msdn.microsoft.com/en-us/library/aa691340(v=vs.71).asp

  • The argument list is evaluated as described in Section 7.4.1.
  • M is invoked.

 

Again all kinds of cases for all the different kinds of functions, but the above is everywhere in some way. First evaluate the arguments, then call the method.

Of course this makes sense, the function header (technically known as "function signature") says to expect a number of integers, so if you have expressions instead, they first need to be converted to integers.

 

The above is what any C# compiler will do, at conceptual level. That means, no matter what code you write, or whatever code the compiler actually generates or executes, results that you get must be explainable from the above description. If not, it's a compiler bug.

I deliberately said "whatever code the compiler actually generates or executes" there. The compiler is free to change anything wrt code generation that it likes, except it must result in answers that can be explained from the description in the language specification. The compiler thus may inline your method call, or may conclude that it never needs to evaluate "gcd(v)" in some case. It may also decide to expand "gcd(x)" and compute whenever it is needed. All that and more is allowed, the answer just must be the same as a compiler that literally implemented the language specification.

 

Why doesn't the language description explain what the compiler really does?

Reality is, compilers change all the time. People are constantly looking for, and finding, new ways to compute things faster. Compilers quite literally not do what they claim to do. They do something else instead, which is generally performing better, but you never know it does something else, since the result cannot be distinguished from the description of the language reference.

This is why the language description is describing the execution at conceptual level. For a programmer, it's a solid foundation. If you follow the rules of the language specification, your program will now and in the future continue to work, no matter what weird tricks the compiler authors pull from their hat.

For the compiler authors, it gives freedom. They can change anything they like, as long as the result with respect to the language specification remains the same. All programs ever written will continue to work.

 

So the answer to your question is "don't know, and that's good". Tomorrows compiler may do things differently anyway, and that's fine.

Share this post


Link to post
Share on other sites

 [...]

 

 

Thank you very much for the answer! Now that begs new questions, like how come operators can be "shortcut" like && (i.e. operands are not evaluated before the body of the operator is executed) and methods seemingly can not. But then again my internal knowledge of c# operators themselves is lacking. I'll have to deep into the language specification further!

Share this post


Link to post
Share on other sites

how come operators can be "shortcut" like && (i.e. operands are not evaluated before the body of the operator is executed) and methods seemingly can not

 

Why would you say that?

 

Parameters are different than operators.  The && operator is evaluated first, returning true or false, and that true or false is evaluated as a parameter.  To evaluate && it looks at the first, then looks at the second. 

Share this post


Link to post
Share on other sites

Short-circuit evaluation is only available for relevant boolean operators, && and || (the XOR, ^, operator isn't, since you always need to evaluate both operands anyway). You could say those operators are somewhat 'special' yes, but is definitely different from what you're expecting. The conditional operators can easily be implemented within the language. For example you can have:

if (condition && otherCondition)

changed to

if (condition)
{
    if (otherCondition)
    {

which makes sense, because at run time you'll know the value of the first argument and based on that can determine whether you need to determine the second at all. Having to write those if-statements in all scenarios would become a little tiring though!

The evaluation process you describe is vastly different however. You basically want to pass the argument, which is the result of a function, and only afterwards once you have entered the function and determined you don't need that value that you asked C# to compute for you upon entering, decided to not compute it after all. More importantly, what if gdc had side-effects such as printing something as console output? You called the function, so you'd at least expect the result to show up at the time of calling it! Such side-effects make something alike near impossible and so is deciding in advance whether a function will have side-effects. However, this isn't a problem for either of the boolean operators.

What you're looking for is called lazy evaluation. There's at least one language I know supporting it, which is Haskell, a functional programming language without side-effects, making things quite a bit easier ;)

For this case, I'd simply try to modify the structure so that the function you're calling instead computes gdc and you pass the arguments you would have passed to gdc. That way, only if the function you call evaluates the arguments, will gdc be computed. Of course storing/caching the results of particular calls to gdc would help too, if performance really is a problem.

Share this post


Link to post
Share on other sites
Now that begs new questions, like how come operators can be "shortcut" like && (i.e. operands are not evaluated before the body of the operator is executed) and methods seemingly can not.

You're using knowledge about the function that in general doesn't exist, or at least, you cannot specify it as a single function.

real f(int a, int b, int c) { .. }

quite literally states "I am function f, I need three integers, and return a real to you".

It doesn't state "I need a, and b when it's in the afternoon, and c if a is more than 5 and it is high tide". The C# language also doesn't provide any means to state these things as part of the function f.

 

If you really want, you can code this of course, by making functions f1..f5, testing the usage conditions outside the function, and then call the correct f_i variation. At that point however, it's not language specification any more, but a thing coded by the programmer (user of C#).

 

The standard math (ie what mathematicians use) "and" operation is not short-circuit. It evaluates both sides, and then computes the overall result, just like any other binary operator, like + or *. This kind of "and" however is very annoying in programming.

 

Imagine you have to check for two conditions:

1) list may not be empty

2) first element must be at least 5.

With math "and", mylist.size() != 0 "and" mylist[0] == 5 fails. For the empty list, "mylist[0] == 5" cannot be computed and it throws an exception OutOfRangeError or so. The reason is that math-and first evaluates both sides, and then computes the overall result.

 

The computer-and && is specifically designed to avoid such problems. mylist.size() != 0 && mylist[0] == 5 works, because the && doesn't even consider the second operand if the first one doesn't hold. You should be able to find this in the evaluation of the && operator.

Edited by Alberth

Share this post


Link to post
Share on other sites

In addition to what others have said, let's say you have a method that looks kinda like this.  waaay over-simplified, but bear with me.

int DoStuff(bool b, int x, int y)
{
   if (b)
     return x;
   return y;
}

Pretty simple, right? Now let's assume that you're calling it like this

int x = SomeReallySlowFunction();
int y = AnotherReallySlowFunction();

int answer = DoStuff(someBoolValue, x, y);

Uggh, we've called both slow functions and we really only need one! Well, we could move the logic out of DoStuff, but let's assume that DoStuff is actually a bit more complicated and we don't want to do that. 

What are our options?

Well, you could put the parameters into a class with lazy evaluated properties, but that's kind of a pain.

But the other option is to pass delegates instead of values, i.e.

int DoStuff(bool b, Func<int> getX, Func<int> getY)
{
   if (b)
      return getX();
   return getY();
}

// called like this
int answer = DoStuff(someBoolValue, SomeReallySlowFunction, AnotherReallySlowFunction); 

Note the lack of () on the two method calls. Now, we are only calling whatever methods we actually need.

That said, passing a whole bunch of parameters into a method that probably won't need them is usually a code smell and an indication that you should refactor your method.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By Alexander_Vovk
      Hello Guys!
      Please share your experience, where is it better to find sales manager  specialists for indie team of 6 + people(remotely)?
      Maybe someone has a good experience of cooperation with finding projects through sale managers(USA and Canada)?
      Thank you
      Best Regards
      Alex Vovk
      Co-Founder of Sixteen Squares
      Alexander_Vovk@outlook.com
       
    • By RoKabium Games
      Been a bit quiet recently, but we've been busy bug fixing and tweaking things... Now we have lots more 'Particle effects' in the game, specifically here the Flamethrower and Enemy attacks!
    • By JoshuaFraser
      Hi and thanks for reading, I have an issue with this reactive crosshair script, everything works fine until I start changing the offset. Give the script a go and you will see what I mean, when I do SetOffset(0f); it doesnt always set back to the origional state, if anyone can spot a fix I'd be super appreciative!
      using System.Collections; using System.Collections.Generic; using UnityEngine; public class ReactiveCrosshair : MonoBehaviour { [SerializeField] GameObject c_limb_prefab; private float center_offset = 0f; private float current_offset = 0f; private float max_offset = .5f; private int number_of_limbs = 4; private float limb_length = .05f; private float limb_width = .005f; private List<GameObject> c_limbs = new List<GameObject>(); public void SetupCrosshair(){ for (int i = 0; i < number_of_limbs; i++) { GameObject line_go = (GameObject)Instantiate (c_limb_prefab); line_go.transform.SetParent (this.transform); Vector3 limb_pos = new Vector3 (0f,0f,0f); //line_go.transform.position = limb_pos; line_go.transform.localPosition = limb_pos; LineRenderer line = line_go.GetComponent<LineRenderer>(); line.startWidth = limb_width; line.positionCount = 2; line.SetPosition (0, line_go.transform.localPosition + new Vector3(center_offset, 0f, 0f)); line.SetPosition (1, line_go.transform.localPosition + new Vector3(center_offset + limb_length, 0f, 0f)); line.useWorldSpace = false; c_limbs.Add(line_go.gameObject); } if (c_limbs != null) { OrientLimbs (); SetOffset (0f); } } public void OrientLimbs(){ for (int i = 0; i < c_limbs.Count; i++) { float rotation_step = 360f / (float)c_limbs.Count; c_limbs [i].transform.RotateAround (c_limbs[i].transform.position, c_limbs[i].transform.forward, 90f + (rotation_step * (float)i)); } } public void SetOffset(float _current_spread){ float offset = Mathf.Lerp (0f, max_offset, _current_spread); for (int i = 0; i < number_of_limbs; i++) { if (offset > current_offset) { Vector3 pos = c_limbs [i].transform.position + (c_limbs [i].transform.TransformDirection (Vector3.right) * offset); c_limbs [i].transform.position = pos; } if (offset < current_offset) { Vector3 pos = c_limbs [i].transform.position - (c_limbs [i].transform.TransformDirection (Vector3.right) * offset); c_limbs [i].transform.position = pos; } } Debug.Log ("SetOffset() offset: " + offset.ToString () + " _current_spread: " + _current_spread.ToString() + " localPos: " + c_limbs[1].transform.localPosition); current_offset = offset; } }  
    • By Erik Nivala
      So, as the title says i am trying to figure out a good way sync all that information with other players in Unity. My problem is that i can't come up with a good solution since i am used to creating classes for everything e.g. attachments are its own class and then the weapon would save a reference to that attachment. But since you can't send custom classes over [Command] & [ClientRPC] i am a little stuck. A solution for this would be giving each attachment for a slot a unique ID and then passing the ID to other player but i feel like that is very error prone if other ppl add a new attachment or the IDs get mixed up.
      Is there a "standard" way that this is usually done that i am missing?
      I am fairly new to programming so any help is appreciated!
    • By MintyLyton
      I'm looking for any team / people that need a programmer for their project. I'm looking to expand my portfolio which you can see Here. I'm more experienced with Unity but I can spend the time to learn new Engines if that's your preference. I have worked on Unreal Engine 4 before but I might take some time to re-learn it, if the project requires it. Feel free to DM here or use the contact info on my website. 
    • By ethancodes
      I'm working on a system for my game that will allow the player to stack pick ups in a queue. As one pick up expires, the next automatically activates. I'm having an issue though where if I pick up the first one, it activates fine, but if i pick up a second directly after it, it overrides the first one, activates the second one, and then once it has run it's course, everything goes back to normal gameplay, no first pick up. I'm not sure why this is happening. Hopefully someone can spot what I'm doing wrong in my code.
      Here is the code for the pick up manager:
      // Update is called once per frame void Update () { if (pickUpQueue.Count != 0 && !pickUpActive) { pickUpActive = true; pickUpQueue[0].ActivatePickUp(); } DeactivatePickUp(); } void DeactivatePickUp () { if (pickUpQueue.Count != 0 && pickUpActive) { Destroy (pickUpQueue [0]); pickUpQueue.RemoveAt (0); pickUpActive = false; } } And here is the PickUp:
      public override void ActivatePickUp () { ball.GetComponent<Ball>().Speed = 2.0f; //increase ball speed... ball.GetComponent<Ball>().StartCoroutine(timer); //...set time that power up is active }  
      There is also a Base Pick Up:
      public void OnCollisionEnter2D (Collision2D collision) { Vector2 tweak = new Vector2 (Random.Range(0f, 0.2f),Random.Range(0f, 0.2f)); this.gameObject.GetComponent<Rigidbody2D>().velocity += tweak; //if the pickup makes contact with the paddle or ball.... if (collision.gameObject.tag == "Paddle" || collision.gameObject.tag == "Ball") { GameObject.FindObjectOfType<GameManager>().GetComponent<PickUpManager>().pickUpQueue.Add(this); Destroy(gameObject); //...and finally destroy power up object } } As a side note, I am trying to find a solution to this that will work for all of my pickups. Some pickups are ammo based, some are timed. 
    • By D34DPOOL
      Edit Your Profile D34DPOOL 0 Threads 0 Updates 0 Messages Network Mod DB GameFront Sign Out Add jobEdit jobDeleteC# Programmer for a Unity FPS at Anywhere   Programmers located Anywhere.
      Posted by D34DPOOL on May 20th, 2018
      Hello, my name is Mason, and I've been working on a Quake style arena shooter about destroying boxes on and off for about a year now. I have a proof of concept with all of the basic features, but as an artist with little programming skill I've reached the end of my abilities as a programmer haha. I need someone to help fix bugs, optomize code, and to implent new features into the game. As a programmer you will have creative freedom to suggest new features and modes to add into the game if you choose to, I'm usually very open to suggestions :).
      What is required:
      Skill using C#
      Experience with Unity
      Experience using UNET (since it is a multiplayer game), or the effort and ability to learn it
      Compensation:
      Since the game currently has no funding, we can split whatever revenue the game makes in the future. However if you would perfer I can create 2D and/or 3D assets for whatever you need in return for your time and work.
      It's a very open and chill enviornment, where you'll have relative creative freedom. I hope you are interested in joining the team, and have a good day!
       
      To apply email me at mangemason@yahoo.com
    • By davejones
      Is there a way to automatically change the start position of an animation? I have a bunch of animations set up on 3D models in unity. The issue is that I need to move the 3D models, however when I do so the animation start positions are not updated and I have to do it manually.

      Changing the transform of key frames is time consuming with the amount of animations I have, so I was wondering if there was a way to do it automatically?
    • By MoreLion
      hey all! We are looking for members for our Unity horror game! 
      Here’s the story:
      After a deadly virus plunges the world into chaos killing 85% of the human population there are now what they call “zones” these zones are watched very closely by the surviving government, people are checked every day for the virus, even if you touch the spit or any human waste or fluids of the victim who is infected, you will die. But one day, people in the west zone start to go missing, 1 woman goes outside the walls to uncover the mystery, is there more to the virus than meets the eye?, That is where your story starts.
      This game is not a long development game, I have loads other game ideas,
      I will also allow you to have a bit of creative freedom if you wish to add or share a idea!
      And no, it’s not a zombie game lol I feel like zombie games are too generic, in this game you will encounter terrifying beasts!
      There is some concept art one of our concept artists have made
      If interested email liondude12@gmail.com
    • By Canadian Map Makers
      GOVERNOR is a modernized version of the highly popular series of “Caesar” games. Our small team has already developed maps, written specifications, acquired music and performed the historical research needed to create a good base for the programming part of the project.

      Our ultimate goal is to create a world class multi-level strategic city building game, but to start with we would like to create some of the simpler modules to demonstrate proof of concept and graphical elegance.

       

      We would like programmers and graphical artists to come onboard to (initially) create:

      A module where Province wide infrastructure can be built on an interactive 3D map of one of the ancient Roman Provinces.
      A module where city infrastructure can be built on a real 3D interactive landscape.
      For both parts, geographically and historically accurate base maps will be prepared by our team cartographer. Graphics development will be using Blender. The game engine will be Unity.

       

      More information, and examples of the work carried out so far can be found at http://playgovernor.com/ (most of the interesting content is under the Encyclopedia tab).

       

      This project represents a good opportunity for upcoming programmers and 3D modeling artists to develop something for their portfolios in a relatively short time span, working closely with one of Canada’s leading cartographers. There is also the possibility of being involved in this project to the point of a finished game and commercial success! Above all, this is a fun project to work on.

       

      Best regards,

      Steve Chapman (Canadian Map Makers)

       
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631397
    • Total Posts
      2999836
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!