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

(rhetorical) Programming headscratcher. int.loop()

Discussion in 'General Discussion' started by neginfinity, Aug 8, 2021.

  1. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    Has anyone ever wondered why this notation is not a common thing?
    Code (csharp):
    1.  
    2. 100.loop();
    3.  
    Or to be more specific:
    Code (csharp):
    1.  
    2. 100.loop(i => Debug.Log(i));
    3.  
    Currently this can be done with an extension method.
    Code (csharp):
    1.  
    2. static class IntExt{
    3.     public static void loop(this int arg, System.Action<int> callback){
    4.         for(int i = 0; i < arg; i++){
    5.             callback(i);
    6.         }
    7.     }
    8. }
    9.  
    Even though int is a primitive type, it can be extended to have "methods".

    You can also chain those.
    Code (csharp):
    1.  
    2. int a = ...;
    3. return a.min(b).min(c).min(d).max(e);
    4.  
    Now, you probably shouldn't do that in production, because the idea is uncommon, and therefore breaches principle of least astonishment, but. I sorta wonder, why this isn't a common thing somewhere.

    Although I did encounter Bjarne Stroutstroup's proposal to equal methods and functions.
    https://isocpp.org/files/papers/N4174.pdf
    Thoughts?
     
    Peter77 likes this.
  2. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    I don't see this saving me any real time so I'm not inclined to care. I can type "for", hit Tab twice to auto-complete, and then another time to input the equivalent value. 4-5 is better than ~9, but not by much, and a regular for loop gives you a lot more power if you need it.

    The main thing is that most of my loop counts are based off of other variables, or properties of other variables, like the number of agents in my simulation, and while something like
    activeAgents.Count.loop()
    could work, it doesn't seem much quicker or more readable than a traditional for loop.
     
    Socrates likes this.
  3. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    That's not the part I was thinking of. I was thinking about using method call syntax on integers.

    Full version of "for" is way too verbose, by the way, even if you autocomplete it, it'll require a condition, an incrementer and one extra variable. Meanwhile a single statement loop construct would provide it automatically.
     
    Martin_H likes this.
  4. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I actually added & use a bunch of extension methods like these just for minor convenience sake.
    It starts feeling a bit verbose to write this for clamping a minimum value, for instance...
    Code (CSharp):
    1. int x = 10;
    2. x = Mathf.Clamp(x, 25, int.MaxValue);
    ...When I could just use an extension to do this instead:
    Code (CSharp):
    1. int x = 10;
    2. x = x.Min(25);
    Or approximating floating-point numbers from this...
    Code (CSharp):
    1. float x = 0.01f;
    2. float y = 0.0099f;
    3.  
    4. bool approx = Mathf.Approximately(x, y);
    ...To this:
    Code (CSharp):
    1. float x = 0.01f;
    2. float y = 0.0099f;
    3.  
    4. bool approx = x.IsApproximately(y);
    Or comparing if a number is between two values from this...
    Code (CSharp):
    1. float x = 5f;
    2.  
    3. if(x > 2f && x < 10f) {
    4.  
    5. }
    ...To this:
    Code (CSharp):
    1. float x = 5f;
    2.  
    3. if(x.IsBetween(2f, 10f)) {
    4.  
    5. }
    And then it really starts becoming more useful when you involve something like vectors.
    Say I want to clamp a minimum value of 1 for a Vector3's (x,y,z) fields. Well to do that, I'd have to write this normally:
    Code (CSharp):
    1. Vector3 vector = new Vector3(-2f, -4f, 12f);
    2.  
    3. vector = new Vector3(
    4.   Mathf.Clamp(vector.x, 1f, float.MaxValue),
    5.   Mathf.Clamp(vector.y, 1f, float.MaxValue),
    6.   Mathf.Clamp(vector.z, 1f, float.MaxValue)
    7. );
    Or write an extension to reduce all of that to just this:
    Code (CSharp):
    1. Vector3 vector = new Vector3(-2f, -4f, 12f);
    2.  
    3. vector = vector.Min(1f);
     
    Last edited: Aug 8, 2021
  5. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    I don't think it's bad at all, I just feel like a for loop is such a fundamental thing that I don't know that I'd be saving much if any time, and I personally don't care that much about verbosity in C# (I put my curly braces on their own lines).

    Now if we were talking python I'd be on board. Maybe it's psychological.
     
  6. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    I had something similar for Dictionaries. getValueOrDefault, plus bunch of utility functions like getOrCreateComponent(), etc.

    I could've sworn that unity had an advanced vector operator syntax where | mapped to dot product or something, but apparently I'm wrong and that is actually an Unreal feature.

    Once you've written
    for(int i = 0; i < blah; i++)
    innumerable number of times, having to spell it out again might slowly start driving you nuts, and you might wonder why not
    loop(10, i => blah(i));


    Speaking of verbosity, one of the truly annoying things with C# is that it doesn't allow free floating functions.
    So you can't just declare float sin(float) it has to be a part of the class, and you'll need to spell out the name of that class every time you use it. Thankfully extension methods partially alleviate this issue.

    Another annoying thing is this construct:
    Code (csharp):
    1.  
    2. Dictionary<SomeKeyType, SomeValueTypeWithALongName> keyToValueDictionary = new Dictionary<SomeKeyType, SomeValueTypeWithALongName>()
    3.  
    Extra fun when value type is another Generic container.
    If you're in a function you can use var and shorten it.
    But if it is a field, as far as I'm aware, you'll have to type out the whole thing.
     
    EternalAmbiguity likes this.
  7. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    968
    There is using static though.

    With C# 9 you can at least do = new() so you only have to spell out the type once.
     
    april_4_short and neginfinity like this.
  8. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,848


    Sorry but that's awesome.
     
    april_4_short likes this.
  9. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    This is useful, appreciated.

    Unfortunately, unity as of now only supports C#8. Unless I'm missing something.
     
  10. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,438
    That's an interesting idea! Personally I wouldn't use it as of now, because the compiler currently emits inefficient code for it (or the last time I checked). This syntax creates a "new delegate" under the hood and then calls it, thus it adds pressure on the GC and calls more functions. Nothing I would want to execute per-frame and nothing Unity Technologies and Microsoft recommend to do in game development per-frame.
     
    april_4_short and xVergilx like this.
  11. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    968
    2021.2 has support for C# 9