c# Ambiguous methods. Works in dotnetfiddle but not in unity?

I hope this post is in the correct location.

I am having a hard time seeing what I am doing wrong here. I am getting the following error but as far as I can tell everything looks right. The error is directed at the return value in the GenerateSmoothNoise function.

Assets/ITerrain/Libs/ITNoiseLib/CoherentNoise.cs(48,33): error CS0121: The call is ambiguous between the following methods or properties: ITNoiseLib.CoherentNoise.GetNoise(byte, int, int, int)' and ITNoiseLib.CoherentNoise.GetNoise(byte, float, ITMathLib.MathUtils.InterpolationMode)’

I am pretty new to c# so I am sure I am overlooking something simple but have looked all over the web for a solution but have not found anything yet.

Any insight would be appreciated.

public static float GetNoise(byte seed, int x, int y = 0, int z = 0) {
       ...
}
  
public static float GenerateSmoothNoise(byte seed, int x) {
       // x is an int so I would assume it would call the above GetNoise function.  I have also tried casting it to a int with (int) x, (int) (x-1), ... with the same results.

        return (GetNoise(seed, x) / 2.0f + (GetNoise(seed, x - 1) / 4.0f) + (GetNoise(seed, x + 1) / 4.0f)); // Error here
}
  
public static float GetNoise(byte seed, float x, MathUtils.InterpolationMode interpolation_mode = MathUtils.InterpolationMode.LERP) {
      ...
}

This is really odd. If I cast x to a float in the GenerateSmoothNoise function it does not have any problems. but when I cast it to an int its still ambiguous. I am at a complete loss.

I have broken this problem down into the simplest form.

The following fails with the same ambiguous error inside the Bar function.

public static float Foo(byte seed, int x) {
    ...
}
     
public static float Bar(byte seed, int x) {
    return (Foo (seed,x));
}

public static float Foo(byte seed, float x, short t=1) {
    ... 
}

But if I remove the t parameter in the bottom Foo function is has no problems.

The following works fine

public static float Foo(byte seed, int x) {
    ...
}
     
public static float Bar(byte seed, int x) {
    return (Foo (seed,x));
}

public static float Foo(byte seed, float x) {
    ... 
}

The code has no errors in dotnetfiddle

Is this a limitation with unity?

Your error is in GenerateSmoothNoise:
When you do this: GetNoise(seed, x) it gives you an error.
Since you have 2 functions called GetNoise each with the same required parameters (only the optional ones are different and you don’t pass any) then it doesn’t know which GetNoise function it should call.

Thanks for your reply.

I thought since I passed an int it would call the version of GetNoise that accepts ints.

I guess I need to revisit method overloading in C#.

As it seems you are unable to have default values on overloaded methods.

I got around this with the following solution.

public static float Foo(byte seed, int x) {
    ...
}
    
public static float Bar(byte seed, int x) {
    return (Foo (seed,x));
}

public static float Foo(byte seed, float x, short t) {
    ...
}

public static float Foo(byte seed, float x) {
    return (Foo(seed, x, 1)); // call the above Foo function with default t value of 1
}

If you only want to call the one that accepts ints, have you tried casting x as int? Such as GetNoise(seed, (int) x)?

A better question is. Why would you even want an overloaded method with optional parameters?

It’s possible this is a Unity-specific bug, because Unity doesn’t support C# 4, which is when they introduced optional parameters. Instead, Unity implemented its own workaround to allow optional parameters which does some weirdness under the hood to create hidden overloaded functions for each of the versions of the function with and without the optional parameter supplied. So it might be one of those that is actually conflicting. There are a few other bugs with the way Unity handles optional parameters that you should watch out for too if you use them a lot. For example:

int Add(int x, int y = 3) { return x + y; }
Add(5, 0);  //returns 5 in .NET (correct answer) but returns 8 in Unity (wrong answer)

This is because Unity’s workaround with the hidden overload is checking to see if the optional parameter is the default value of its type (0 for an int) and if so, converts it to the optional parameter default (3).

2 Likes

Thanks for the heads up … that’s a doozie :slight_smile: