Compile time constant?

Why can’t i do this?

    //Constants
        const Vector3 unsetVector = new Vector3(9999f,9999f,9999f);

    void Move(int type, Vector3 velocity = unsetVector)
    {
        //type: 0 = simpleMove, 1 = Move
        if (type == 0)
        {
            controller.SimpleMove(moveVelocity);
        }
    }

the Move function won’t compile. “Default parameter for Velocity must be a compile time constant”

Isn’t that what the const keyword is for?

I want the default value to be something unlikely to be passed in, so that if its passed a value different from the default, it will behave differently. I can’t use Vector3.zero because that is VERY likely to be passed in

Seems like it should be approached in another way, perhaps validate the magnitude of what is passed in, within the function. It is already much more expensive than a single magnitude because of the controller.SimpleMove so you don’t lose anything by

if (velocity.magnitude>9000)
{
    print("it's over 9000!");
}

Honestly 9999f isn’t a good choice either, since it’s still possible. You could use a nullable type, and check for null, or else use NaN.

–Eric

1 Like

The first problem is that Vector3 cannot be a const because const only works with a few built in primitives.
The second problem is that you can’t assign a “new” object into a constant because, by definition, a new object is not constant. The constructor you are using could create different things based on the runtime state of the program.

I think the usual solution is to set the default to null. This obviously doesn’t work for value types, so you can change to a Nullable, or Vector3? for short:

void Move(int type, Vector3? velocity = null)
{
  if (velocity == null)
    return;

  var actualVelocity = (Vector3)velocity;
  //type: 0 = simpleMove, 1 = Move
  if (type == 0)
  {
    controller.SimpleMove(actualVelocity);
  }
}
4 Likes

In this case, I would actually overload Move with a second version that doesn’t require the second parameter. It seems like setting up a situation where the wrong input means your character moves 9999 units is asking for trouble…

1 Like

In this example, I side with StarManta. Even side stepping the 9999 situation like the code I wrote, there isn’t much point in optional parameters if you are not going to do anything when the caller doesn’t provide a real value. Anyways, I assume the actual code is more complex. I realize it’s hard to make samples simple but also express the reasoning for doing something.

@hippocoder , what does the scouter say about his power level?

i can “use” NaN ? how? Could i just use Vector3 velocity = NaN ?

I think he means a Vector3(NaN, NaN, NaN).

welll, would that solution work for my problem? would i do that when declaring the constant, or write it straight into the function parameters?

(i’m looking at the other solutions too)

Yep; System.Single.NaN to be exact, assuming you haven’t imported System.Single (though I don’t think you can do that in C# anyway).

–Eric

This idea i don’t understand, i need more explanation.

Vector3 is not nullablem i think.
What would Nullable or Vector3? even do? are those some special syntax, or are you saying i should define my own variant of vector3 somewhere?

Nullable is a generic type introduced in .net 2.0.

It is a way of allowing a type which is not normally nullable (most value types) to have a null value. Nullable is a type which acts just like Vector3 except that it might be null.

Vector3? uses a special syntax introduced in C# 2.0 which is essentially a shortcut to say Nullable

1 Like

Nullable allows a primitive value to be null. Basically, it boxes the value of the primitive type.

I wouldn’t use the word “box” since that already means “moved to the heap” to a lot of programmers. Actually, Nullable is a struct, so it’s more like duplicating the value along with a special flag which indicates whether you should ignore the value and pretend it is null.

Anyways, no need to get confused. Nullable is very natural to use.

MSDN claims it boxes the value of the primitive type - so verbiage might be misleading there.

You can always just do the compilers job by hand.

    void Move(int type) {
        Move(type, unsetVector);
    }

    void Move(int type, Vector3 velocity) {
        // some random code
    }

I think what MSDN is saying is that when boxing would normally occur, the underlying value is boxed instead of the entire Nullable struct. Also, Nullable isn’t limited to primitive types, T can be any struct type.

I still prefer what StarManta and BoredMormon have suggested given the code we have to work with here.

Sorry… I probably shouldn’t dissect your sample code. But just in case it helps and since we’re digging into it a bit… I’m really suspicious of your int parameter “type” which you seem to use as a control flag. This is probably a code smell; I’d go with this one. You can use the refactoring technique “remove control flag” to get rid of it… basically it will mean going back to overloaded methods…

1 Like

if i’m understanding correctly, that seems to mostly refer to a boolean. Though i do see the point that the int value is basically a boolean here, since i’m only going to code two possible options for this function.

I’m very fond of control integers in general. I do quite a lot of if (myint == 1), else if (myint == 2) etc. Thoguh i do combine that with lists very often to smooth things along

@eisenpony I’m trying to implement your nullable solution, that’s what i like best. however, the Type or Namespace ‘Nullable’ could not be found.

What do i need to using to make this work?

whoops, I should really read the pages I link to… I messed up…

A more appropriate refactoring would be “Replace parameter with explicit method”. Basically, it’s suggesting you don’t use control integers and instead call a different method. This gives you an opportunity to name your method something meaningful instead of needing those comments like:

//type: 0 = simpleMove, 1 = Move