2

If I pass an object in C++ like so:

template<typename MyType>
[public] MyType myMethodOrFunction(const MyObject& obj) {}

Would the following be equivalent in C#:

[public] MyType myMethodOrFunction<T>(MyObject obj) {}

?

Exactly the same question was asked here: Const function parameter in C#

Andrew
  • 197
  • 2
  • 3
  • 16
  • 3
    You found **one of** C# biggest mistakes (in my opinion). Huge source of bugs. – Noel Widmer Jun 01 '17 at 18:34
  • @NoelWidmer, I think there is a specific reason for this, don't think it's a bug. – Andrew Jun 01 '17 at 18:39
  • 2
    I didn't say it is a bug. It is a language design *mistake* in my opinion. Java didn't had const references so C# doesn't have them as well. If we just could go back and fix it... – Noel Widmer Jun 01 '17 at 18:42
  • 2
    @NoelWidmer as I pointed out in one of the answers, there is a [proposal to add readonly reference parameters](https://github.com/dotnet/csharplang/blob/master/proposals/readonly-ref.md) (which is apparently currently being implemented) – UnholySheep Jun 01 '17 at 18:43
  • 1
    @Ðаn Immutable interfaces **won't fix the problem at all!** It simply **hides** the mutability. You can just cast to the real type and mutate the instance. – Noel Widmer Jun 01 '17 at 18:43
  • @UnholySheep It doesn't look like that proposal would work for reference types. I can't imagine how it could since C# has absolutely no concept of `const` methods (and that proposal makes no suggestion to add them), so how could the compiler know what methods you could call on a reference type and be safe from mutating it? – Kyle Jun 01 '17 at 18:59
  • 4
    @NoelWidmer I wouldn't say that casting something to a real type and mutating it is necessarily a problem compared to C++ because C++ allows you to do essentially the same thing with `const_cast`. At that point the developer is doing something intentionally naughty. – Kyle Jun 01 '17 at 19:03
  • @Kyle Disagree, it is. Const_cast only succeeds if the original instance was no declared const. So everytime you perform a const_cast on a const reference parameter you write bug prone code because you cannot make sure what the instance's declaration looks like. I see the reason why const_cast was introduced but I don't think it added to c++'s value. – Noel Widmer Jun 01 '17 at 19:09
  • @NoelWidmer What does it mean for `const_cast` to succeed or fail? [Here's a sample](https://ideone.com/NklVYM) which uses `const_cast` to mutate an rvalue. So I'm not sure what you mean when you indicate that it can fail. – Kyle Jun 01 '17 at 19:28
  • @Kyle We are getting close to my c++ limits. A const cast will not fail, my bad. But modification of a const casted instance can result in UB. See the *Notes* section in: [const_cast conversion](http://en.cppreference.com/w/cpp/language/const_cast) – Noel Widmer Jun 01 '17 at 20:06
  • 1
    @NoelWidmer Sure, and if you write code that accepts an interface, and then tries to cast that code to what you think the underlying implementation is, so you can mutate that underlying implementation *that* code can fail, if you don't actually pass in an instance of the underlying implementation the object expects. In both cases, whether using the C++ code or the C# code you need to be actively trying to do something you know is wrong to mutate the value, and in both cases it can fail if the caller doesn't do what you want them to do. – Servy Jun 01 '17 at 20:28
  • @Ðаn Read my last comment again. I said *A const cast will not fail, my bad*. And then my next sentence was exactly what you just said. – Noel Widmer Jun 01 '17 at 20:51
  • @Servy That's exactly my point. As I have pointed out in my third comment on this post. Kyle said those two cases (C# and C++) aren't *necessarily a problem* which I didn't agreed with. – Noel Widmer Jun 01 '17 at 20:55
  • 2
    @NoelWidmer You said that interfaces don't fix the problem. They fix the problem well enough, at least insofar as someone needs to actively try to do something they can clearly see is wrong to try to change the value, and their attempts may not even work. That's as much as `const` in C++ gives you. In both cases it's a useful feature that's sufficient for most purposes. – Servy Jun 01 '17 at 21:10

2 Answers2

0

No, it won't have exactly the same semantics. The C# code you showed would have the same semantics as passing a pointer by value in C++, rather than passing a value by reference. You can pass a parameter by reference in C# using ref or out, but you cannot pass a read only reference; such references will always be mutable, thus there is no way of providing identical semantics to that C++ code in C#. That said, while the semantics aren't identical, that should probably be a class (having value types is quite rare in C#) and it should probably be passed by value, it's again rare to need otherwise, just realize that it won't have exactly the same semantics.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 2
    Note that there is a proposal to include [`ref readonly`/`in`](https://github.com/dotnet/csharplang/blob/master/proposals/readonly-ref.md) parameters in C#, so that may change in the future – UnholySheep Jun 01 '17 at 18:23
  • So what happens behind the scenes if I pass an object by value in C#? – Andrew Jun 01 '17 at 18:27
  • 2
    @AndrewIgumenoff The same thing that happens conceptually when you pass a pointer by value in C++. Mutations to the reference/pointer itself aren't observed by the caller, changes to the object being referenced (or pointed to) will be observable through the caller's reference. – Servy Jun 01 '17 at 18:28
  • @Servy, so is there no standard way of how to make that object immutable within the scope of the method or function? – Andrew Jun 01 '17 at 19:02
  • 1
    @AndrewIgumenoff Sure, have a readonly interface that the object implements, or wrapping object that only exposes the read only operations, and pass that. – Servy Jun 01 '17 at 19:03
0

Not exactly.

I think the closest you are going to get is this:

public T myMethodOrFunction<T>(ref MyObject obj) {}

You don't have const in this context in C#. And it is important to note that obj could be a reference or a value type. The difference, in C++ terms, is that a reference type is essentially a pointer (MyObject*) whereas a value type would just be the value (MyObject). So if obj is a value type, then that is closer to the C++ version.

  • 1
    Considering the name of `MyObject` I think it's a rather safe assumption to make that it's an object, not a struct, and so is not a value type. – Servy Jun 01 '17 at 18:27
  • Okay. But he is asking about how to write the equivalent so I think elaborating on the reference type vs value type is helpful here since a struct (value type) would be closer to the C++ version. – Jeffrey McCullen Jun 01 '17 at 18:31