1

I need to convert a bunch of functions from C++ to C#. These have method declarations like

void foo(struct input data*, double* ret1, double *ret2)
{
    // if ret1 is not NULL, return something in it
    if (ret1)
    {
         *ret1 = SomeComplexAndExpensiveMath(data);
    }

    if (ret2)
    {
         *ret2 = MoreComplexAndExpensiveMath(data);
    }
}

When I convert that to C#, out paramters would normally be the preferred choice, but passing null to an argument declared as "out double" is not allowed:


void foo(input data, out double ret1, out double ret2)
{    
    if (ret1 != null) // Error.
    {
        // ...
    }
}

Using ref double? as parameter type also looks weird and causes additional overhead.

Is there a way I can maintain the nice simple out double parameter type while still not computing return values the caller doesn't need? Is there a way to know that the caller did i.e. foo(input, out _, out b) to indicate he doesn't need ret1?

PMF
  • 14,535
  • 3
  • 23
  • 49
  • what about using the Double.NaN: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types – Clément Jean Apr 27 '20 at 12:22
  • Does it cause more overhead than the indirection you're already adding in the C++ case? – Asteroids With Wings Apr 27 '20 at 12:23
  • Have you considered breaking the function into variants with different parameter lists? – Asteroids With Wings Apr 27 '20 at 12:23
  • @AsteroidsWithWings: Thinking about it, yes. But the actual implementation basically has a bunch of methods that all end up in one "do-it-all" implementation which then uses the above approach. And splitting that one up is probably not so easy (or would cause code duplication). – PMF Apr 27 '20 at 12:30
  • Then I'd say that's the real root problem. Do-it-all implementations back you into a corner. – Asteroids With Wings Apr 27 '20 at 12:32
  • 1
    @ClémentJean: How do you mean that? I could use double.NaN as _output_, but not as an input on an out parameter. – PMF Apr 27 '20 at 12:32
  • just like `out Double ret` instead of `out double ret` – Clément Jean Apr 27 '20 at 12:34
  • @AsteroidsWithWings: I haven't written that code. It's from an existing, pretty complex library and I thought this would be a straight forward task. Seems I was wrong. – PMF Apr 27 '20 at 12:34
  • Sadly so ;) I still think `ref double?` is worth considering though – Asteroids With Wings Apr 27 '20 at 12:34
  • 1
    Also how about returning a result object rather than `void`, encapsulating the calculations that were made, and providing a policy (even if that's just some `bool`s) as arguments to tell the function what to do? – Asteroids With Wings Apr 27 '20 at 12:35
  • Yea, that sounds eligible as well. The actual do-it-all method can probably be made internal, so that any extra arguments there don't really matter. – PMF Apr 27 '20 at 12:36
  • Sort of dupe ish of https://stackoverflow.com/q/2870544/4386278 – Asteroids With Wings Apr 27 '20 at 12:53

1 Answers1

1

Check the out documentation. The interesting part is:

Variables passed as out arguments do not have to be initialized before being passed in a method call. However, the called method is required to assign a value before the method returns.

So it is assumed by the caller, that whatever you pass as a value is going to be ignored.

Latest versions of VS will tell you so if you try:

int prs = 1; // Will inform you of unessecary assignment of prs
Int32.TryParse("2", prs);

So the out declaration assumes that it will by default overwrite the value. Your best bet is to use the ref keyword if you want to simulate the same functionality.

Check C# Pointers in a Method's arguments?

What is the additional overhead compared to the C++ solution?

Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
  • If I used `ref double` I would have to assign a value by the caller. Of course, now I could define that I set it to NaN if I don't want anything back, but that's a bit an ugly assumption. If I use `ref double?` I need to write `double? tmp = null; foo(init, ref tmp); if (tmp.HasValue)... ` everywhere. – PMF Apr 27 '20 at 13:42
  • Technically, I could use pointers, but that's not so really C#ish. – PMF Apr 27 '20 at 13:44
  • Yeah, I get the frustration, but there's not much you can do. Unfortunately there are no inline declarations for `ref` parameters, so the extra lines of code seem mandatory. – Athanasios Kataras Apr 27 '20 at 13:50
  • By the way, interesting reads: https://stackoverflow.com/questions/5171781/when-to-use-pointers-in-c-net and https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/pointer-types – Athanasios Kataras Apr 27 '20 at 13:51
  • 1
    I know the pros/cons of using pointers in C#. Using them on the interface of a library that was just converted to C# to be easily usable and platform-independent is not so much on the pro side ;-) But thanks for the links anyway. – PMF Apr 27 '20 at 13:58