21

I'm new to C# (C++ programmer mainly, with Java as a strong second, and some others I use less often); I'm using C# with Unity, but I have a question that seems to be C# related rather than Unity.

I've been moving somewhat towards functional-style programming, i.e. instead of

// C++
int someFunction(int a) {
    int someCalculatedValue = a * a;
    someCalculatedValue /= 2;
    return someCalculatedValue * 3;
}

I'd do something like this

// Again C++
int someFunction(int a) {
    const int inputSquared = a * a;
    const int inputSquaredHalved = inputSquared / 2;
    return inputSquaredHalved * 3;
}

Now, I'd like to do that in C#, but I've tried this

// C#
const float maxGrowth = GrowthRate * Time.deltaTime;

But Mono complains, saying maxGrowth isn't being assigned a 'constant value' - so I'm assuming C#'s const keyword is actually equivalent to 'constexpr' from C++11?

If so, is there a way of doing what I want in C#? Preferably without invoking some container class (unless the compiler is good at making that efficient?).

I assume from what I've read C# is much closer to Java overall than C++ in language; immutable classes rather than const-member functions?

Doug
  • 775
  • 2
  • 11
  • 24
  • Your title talks about immutable _local_ variables, yet your question only mentions "something like this" (is that C++?) and "what I want" (what?). Can you explain what you want this code, or `const` specifically, to do? Did you read [How to declare a local constant in C#?](http://stackoverflow.com/questions/2054761/how-to-declare-a-local-constant-in-c) and [What does immutable and readonly mean in C#?](http://stackoverflow.com/questions/6849114/what-does-immutable-and-readonly-mean-in-c)? – CodeCaster Jun 24 '14 at 21:03
  • 'a question that seems to be C# related rather than C#.' Doug can you clear this up? – TheNorthWes Jun 24 '14 at 21:03
  • Almost all of c#'s primitive types are mutable in the sense they behave like a mutable container for a value. I would really suggest you to take a look at the better and more functional C#s brother - F# – AK_ Jun 24 '14 at 21:06
  • 2
    If you want to, you could use anonymous types. `var inputSquared = new { Value = a * a }; var inputSquaredHalved = new { Value = inputSquared.Value / 2 }; return inputSquaredHalved.Value * 3;` Kinda sucks syntax wise, and pushes it to an object with a readonly field. No idea how this might JIT in terms of optimization or performance. – Chris Sinclair Jun 24 '14 at 21:09
  • Apologies all, I've editted to clear up a mistake and make it clear the examples where in C++ rather than C# – Doug Jun 24 '14 at 21:13
  • @ChrisSinclair: Thanks for the tip, didn't know C# has anonymous types; still very early learning in terms of the jump between C++11 and C#, heh. – Doug Jun 24 '14 at 21:16
  • Since you're going the functional route, you could also wrap these as methods: `Func inputSquared = () => a * a; Func inputHalved = () => inputSquared() / 2; return inputSquaredHalved() / 3;` But this just kinda puts more overhead on the closure patterns being used (though this can be offset by ditching the closure entirely for a input variables on the functions) EDIT: And again, your mileage may vary in terms of performance and compiler/JIT optimizations (which in itself may differ from platform to platform) – Chris Sinclair Jun 24 '14 at 21:18
  • @ChrisSinclair Not sure how those options really save you, the local variable `inputSquared` is still assignable either way. You would just have to create a new instance of the same anonymous type or delegate. – Mike Zboray Jun 24 '14 at 21:22
  • @Doug http://fsharpforfunandprofit.com/why-use-fsharp/ – AK_ Jun 24 '14 at 21:23
  • 1
    @mikez: Hah, yeah, fair enough. In the end, there really is no analogue in C# (But they are tending to add more immutability, so maybe cross your fingers for C#7?). I should clarify: my comments are just for conceptual discussion (or for laughs); I wouldn't really be in favour of using either of them. In a C# mindset, you'll probably be best off simply having tiny pure methods. – Chris Sinclair Jun 24 '14 at 21:26
  • C# should bring in the ``let`` keyword as an alternative to ``var`` as other languages have (Swift, F#, JabbaScript). – Overlord Zurg May 17 '17 at 15:35

3 Answers3

25

You can declare your local variable as an iteration variable. Iteration variables are readonly. Yes, it is ugly.

foreach (float maxGrowth in new[] { GrowthRate * Time.deltaTime })
{
  maxGrowth = 0; // won't compile: "error CS1656: Cannot assign to 'maxGrowth' because it is a 'foreach iteration variable'"
}
ZunTzu
  • 7,244
  • 3
  • 31
  • 39
19

There is no equivalent for local variables: Declare it as a field.

readonly

When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 7
    Was that last sentence there right from the start? I could have sworn I did read it all before, but apologies if not. I don't think guidance of "make it a field" is applicable though - look at the example, where the value depends on the parameter. Unless you're suggesting turning the method call into its own class, this isn't an alternative. – Jon Skeet Jun 24 '14 at 21:08
  • @JonSkeet: Well, I don't call that a constant. I suppose we could create some special type that does that, but what for? If the method is complicated enough to need local immutability, it probably deserves its own class anyway. – Robert Harvey Jun 24 '14 at 21:10
  • I had read about readonly, but was surprised to see it wasn't applicable to local variables (abit odd really). Sad to see that the 'readonly locals' aren't available in C#, they have been useful in preventing some nonsense mistakes. Oh well. – Doug Jun 24 '14 at 21:13
  • 7
    The OP didn't call it a constant either :) But making it clear which local variables may change and which may not is a definite style from some functional languages (e.g. F# too). I think that "no, you just can't do that in C#" is probably more appropriate than referring to `readonly`, personally. – Jon Skeet Jun 24 '14 at 21:14
  • @Doug: `readonly` assumes the presence of a constructor that sets the initial value of the field. Methods don't have constructors. – Robert Harvey Jun 24 '14 at 21:29
0

I believe that a better way for this case is using statement

Sample:

using (var font = new Font("Arial", 10.0f)) 
{
    byte charset = font.GdiCharSet;
}

font variable is immutable

Reference:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

  • 1
    `float` does not implement `IDisposable`, i don't see how this answer the question. – Giulio Caccin Aug 01 '19 at 15:09
  • I understand that this question is not only about the primitive types, but I respect your comment, I think about this too – Rafael Sienna Aug 02 '19 at 13:22
  • Since this question is obviously for people learning C#, this response is valuable. Thus voted up. – Loic Aug 31 '21 at 15:08
  • Hi, this does work, however, it's just a syntax sugar for the foreach loop. Basically, `using` statements [get compiled down to foreach loops](https://weblogs.asp.net/dixin/functional-csharp-immutability-anonymous-type-and-tuple) – TDiblik May 11 '22 at 05:48