4

I am learning the basics of C++, coming from the .NET world (C#).

One topic i found interesting was the const keyword and its usage with pointers (const pointer/pointer to const).

I'd like to know if there's any C# language equivalent of the const pointer/pointer to const that C++ has? (I know C# doesn't have pointers, i am considering references to be the pointer-like types in C#).

Also, out of interest, if there's no such equivalent, what were the decisions behind not including such a feature?

lysergic-acid
  • 19,570
  • 21
  • 109
  • 218
  • 2
    The question was regarding C#... – lysergic-acid Dec 24 '12 at 20:07
  • Then your opening statement is mis-leading. "*I am learning the basics of C++, coming from the .NET world (C#)*" Correct that! – Alok Save Dec 24 '12 at 20:09
  • 1
    How would you get a pointer to const in C#? C# doesn’t have pointers, nor does it have C++-esque constant objects. The closest thing would be making a class immutable, I suppose. – Ry- Dec 24 '12 at 20:09
  • 5
    C# absolutely has pointers, you just must be in an unsafe block to use them: http://msdn.microsoft.com/en-us/library/y31yhkeb(v=vs.110).aspx – Preston Guillot Dec 24 '12 at 20:11
  • Do you mean a const reference? Like `const object obj`? – Lews Therin Dec 24 '12 at 20:12
  • @LewsTherin yes that is what i meant. I just updated my question to better describe my interest... – lysergic-acid Dec 24 '12 at 20:17
  • The concept of `const` as it exists in c++ does exist in neither Java nor C#. The best you can get is the equivalent of `object *const` - a constant pointer to a non-const object. – Voo Dec 24 '12 at 20:18

3 Answers3

6

There is no direct equivalent to passing references as 'const' in C#, but there are alternative ways to accomplish its purpose. The most common way to do this is to make your reference class either completely immutable (once constructed, its state should never change) or pass it as an immutable public interface. The latter is the closest to the intention of the 'const' parameter contract (I'm giving you a reference to something so you can use it, but I'm asking you not to change it.) A poorly-behaved client could 'cast away' the public interface to a mutable form, of course, but it still makes the intention clear. You could 'cast away' const in C++, as well, thought this was rarely a good idea.


One other thing in C++ is that you would often prefer to pass as const when you knew that the lifetime of the reference you were passing was limited in scope. C++ often follows the pattern where objects are created and destroyed on the stack within method scope, so any references to those objects should not be persisted outside that scope (since using them after they fall out of scope could cause really nasty stack corruption crashes.) A const reference should not be mutated, so it's a strong hint that storing it somewhere to reference later would be a bad idea. A method with const parameters is promising that it's safe to pass these scoped references. Since C# never allows storing references to objects on the stack (outside of parameters), this is less of a concern.

Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • This description covers the "pointer to const" case (reference to constant data). What about const pointer? (a reference that cannot be changed). Can the 'readonly' keyword in C# be considered as something similar? (once constructed, cannot be changed) – lysergic-acid Dec 24 '12 at 20:35
  • 1
    @lysergic-acid You can easily add objects to a `readonly List`, while you can't do the same to a `const list` in C++ (assuming the classes are written correctly). – Voo Dec 24 '12 at 20:37
  • 2
    @lysergic-acid If by "similar" you mean "completely different" than yes we agree, because I really don't see the similarity there ;) – Voo Dec 24 '12 at 20:40
  • @Voo: Compare `const list&` not to `readonly List` but to `IReadonlyListView` (a hypothetical interface Dan described in the answer, which unfortunately .NET doesn't have on the provided collections). – Ben Voigt Dec 24 '12 at 20:42
  • @Ben Yes that is one of the usual work arounds (that I also mentioned in my answer), but that doesn't change the fact that `readonly List` and `const list` are completely different beasts - which is why we have those work arounds in the first place. – Voo Dec 24 '12 at 20:44
  • @BenVoigt: But .NET *has* `ReadOnlyCollection`. You still can mutate its elements, but not add elements to, nor delete elements from it. – Joker_vD Dec 26 '12 at 12:37
2

The concept of constant objects (i.e. readonly) in C# (or Java for that matter) corresponds approximately to object *const in C++, i.e. a constant pointer to a non-constant object.

There are several reasons for it - for one specifying const correctly and making it useful in the language is quite hard. Taking c++ as an example, you have to define lots of methods twice with only small changes to the signature, there's const_cast, the fact that const is only applied shallow, etc.

So C# went for the easy solution to make the language simpler - D went the other way with transitive const correctness, etc. as I understand it (never written a single line in D, so take that with a grain of salt).

The usual solution in C#/Java is to have immutable classes, possibly using a builder pattern, or a simple wrapper that prohibits changes (e.g. all the unmodifiable collections that wrap another collection and throw exceptions for the mutating methods like add).

Voo
  • 29,040
  • 11
  • 82
  • 156
  • 1
    The closest thing to C++ `T *const` that exists in .NET is `initonly` (C# keyword `readonly`). .NET `literal` (C# keyword `const`) is something dramatically different. – Ben Voigt Dec 24 '12 at 20:40
  • @Ben Yes and in Java it's called `final`, but when speaking about the general concept of constant objects there shouldn't be a confusion of using const instead of `const/readonly` everywhere I hope. Still I rephrased the first sentence to make it clearer. – Voo Dec 24 '12 at 20:45
2

8,000,000 years later, but C# 7.2 uses the "in" keyword which is sort of like const. It tells the compiler to pass a struct or primitive variable by reference (like ref or out) but the method WILL NOT modify the variable.

public void DoSomething(in int variable){
    //Whatever
}

is functionally equivalent to C++'s

void Foo::DoSomething(int& const  variable){
    //Whatever
}

or arguably even

void Foo::DoSomething(int const * const variable){
    //Whatever
}

The main reason for doing this in C#, according to MSDN, is to tell the compiler that it can pass the variable by reference since it won't be modified. This allows for potentially better performance when passing large structs

Regarding constant pointers, see this answer: Difference between const. pointer and reference?

In other words, a reference in C++ is very similar to a const pointer for most applications. However, a reference in C# is closer to a pointer in C++ regarding how they can be used.

Reference objects passed as arguments to methods in C# can be reinstantiated (say, from Object Instance A to Object Instance B), however the B's lifetime is only within the method scope and is disposed of once returned to the caller (since the pointer itself is passed by value) and the caller's reference is always to A. In this sense, you can freely pass around references in C# and know that they cannot be made to point to different objects (unless ref/out keywords are used).

C# example -

class Foo
{
    //Stateful field
    public int x;

    //Constructor
    public Foo()
    {
        x = 6;  
    }
}

public class Program
{
    public static void Main()
    {
        var foo = new Foo();
        foo.x = 8;

        VarTestField(foo);      
        Console.WriteLine(foo.x);

        RefTestField(ref foo);
        Console.WriteLine(foo.x);       
    }   

    //Object passed by reference, pointer passed by value
    static void VarTestField(Foo whatever){

        whatever = new Foo();
    }
    //Object passed by reference, pointer passed by reference
    static void RefTestField(ref Foo whatever){
        whatever = new Foo();
    }
}

Output:

8

6

So no, you cannot declare a constant pointer in C#. Still, using proven design patterns, algorithms, and OOP fundamentals wisely, along with the built in syntax of the language, you can achieve the desired behavior.

Moe45673
  • 854
  • 10
  • 20
  • 1
    Be aware that the `in` keyword on mutable structs will create defensive copies. https://learn.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code#avoid-defensive-copies – H. Hess Jun 24 '21 at 10:00