Why do i get the error: "a does not exist in the current context"?

I was trying to return the int variable “a” and add one to it but it just gave me that error.

error on line 9.

The code:

[
using UnityEngine;
public class script : MonoBehaviour
{
private void Start()
{
Debug.Log(“Called”);
testfunc(5);
Debug.Log(testfunc(a));
}
int testfunc(int a)
{
Debug.Log(“Thing”);
return a++;
}
]

No ‘a’ is known to this line. You probably meant to pass a number, like you did with ‘5’ above.

Also, in the future please use code tags to post code examples and show the full error message, since that would include the line number which saves a lot of time. Have a read: http://plbm.com/?p=220

2 Likes

Yeah my bad, I’m new to this layout. But if you add a number when printing the value returned wouldn’t it be updated again? I’m trying to get the value it returned from the function “a” in this case.

The function returns a value, but the identifier is only known to that function. So you can do something like

int b = testfunction(5);

No ‘a’ exists in this scope. The variable identifier ‘a’ only exists within the scope of testfunction.

So it’s not possible to pass a value as you do not have access to it? “b” would return 5.

you either declare a variable in the context of a class (known as a ‘field’), or in the context of a function (known as a local variable). additionally, method-body argument identifiers are also considered as locally-accessible variables.

if some function refers to a variable that isn’t a known field and isn’t a locally declared variable, nor an argument, you get this error.

using UnityEngine;

public class script : MonoBehaviour
{

  // no 'a' was declared here as a field

  private void Start() // no 'a' is declared here either
  {
    Debug.Log("Called");
    testfunc(5);
    Debug.Log(testfunc(a)); // so, where is 'a' in this context?
  }

  int testfunc(int a) // a is declared here as an argument
  {
    Debug.Log("Thing");
    return a++; // a is thus recognized locally
  }

}

there are also a couple more places where you can declare local variables, namely in any code block (regardless of whether it was a method body or not), and in loop initializers.

void someMethod()
{
  int a = 7;
  {
    int b = 5;
    Debug.Log(a);
    Debug.Log(b);
  }
  Debug.Log(a);
  Debug.Log(b); // this doesn't work
}
void someMethod()
{
  for(int a = 7, b = 5; a >= 0; a--)
  {
    Debug.Log(a);
    Debug.Log(b);
  }
}
public class someClass
{
  int a = 7;

  void someMethod()
  {
    for(int b = 5; b >= 0; b--)
    {
      Debug.Log(a); // recognized at this point as a defined class field (defined means having a value)
      Debug.Log(b); // defined in loop initializer
    }
    Debug.Log(a); // still works
    Debug.Log(b); // doesn't work
  }
}

Be mindful of naming conventions. This is just an example, but private class fields are typically prefixed with an underscore or m_ (in this case either _a or m_a; m is short for ‘member’, as in class member) to make the fact that it’s not locally declared more apparent, because it won’t be discarded after the function call is over. Fields are commonly used to introduce so-called side-effects into complex behaviors and to provide backing fields for various instance properties that stay persistent for as long as the object is alive in memory.

1 Like

btw, it’s worth noting, if you declare a variable inside a loop block, it doesn’t incur any performance penalties (this isn’t the case in all languages, especially some high-level scripting languages)

for(int c = 0; c < 17; c++) {
  int x; // this won't be executed every time, compiler knows what you mean
  x = 20 - c; // this will be executed every time, as expected
  Debug.Log(x);
}

also this form int x = 5 + a; is just a compound version of two separate concepts

int x; // this is declaration (identifier 'x' holds values of type 'int')
x = 5 + a; // this is definition
// expression-wise it's an assignment preceded by addition,
// but a definition is when a valueless declared variable gets its value for the first time

compiler will yell at you if you attempt to use an undefined variable, therefore you cannot let variables stay undefined during run-time one way or the other.

this is why the compound thing makes sense most of the time, but sometimes you need to do this

int x; // I'm not sure what I will become

if(something > 0) {
  x = -1;
} else {
  x = something * 5;
  // x++; // this can't work because it was undefined
}

etc.

oh one other thing, maybe helpful, as it’s somewhat related to how variables are treated in C#, if you do compound declaration/definition then you can use ‘var’ keyword, as seen in higher scripting languages.

for example
int x = 5 + a;

can also be written as
var x = 5 + a;

because the compiler is able to infer the actual type from the expression alone.

this is especially useful if you have variables that have really long and repeating declarations, such as

Dictionary<int, MyPayloadType> myDictionary = (Dictionary<int, MyPayloadType>)MyDictionaryFactory.BuildFromArray(myArray);

with the use of generics and type inference this can look as innocuous as

var myDictionary = MyDictionaryFactory.BuildFromArray(myArray);

Explanation:

because the compiler can now look at the type of the array elements, and observe that the generic method BuildFromArray expects T[ ] and that its return type is Dictionary<int, T>, it can infer that when myArray is of type MyPayloadType[ ], the method is to be called as MyDictionaryFactory.BuildFromArray<MyPayloadType>(MyPayloadType[ ]) and the result has to be Dictionary<int, MyPayloadType> without specifying anything, thus var will declare myDictionary as intended.

however, this doesn’t work for declarations only

var x; // can't tell what this is supposed to be

or for multiple declarations like

var somePoint, someOtherPoint = Vector3.zero; // won't work

Actually b would contain 6. You pass 5 into your function, the function uses this value (internally known as ‘a’) and does stuff with it. In your case you increment it. You then later return some value (in this case also ‘a’, but doesnt have to be), which is then saved in the ‘b’ i defined in the previous example.
Maybe it makes more sense to think about it like functions in math. Some int y = f(x), so you have some input x, put it into a function, and get the resulting y.

Orion gave a lot of useful examples, but the main term you may want to look into is “Scope”. Scopes are basically these curley backets {} we use to define the areas of classes, methods, statements and so on. Within these scopes we can define variables. And a variable is only known if it’s contained inside the scope you are currently in, or a parenting scope. So a method has access to its own variables, as well as the variables defined in its own class, but not variables defined in a different method. It’s about visibility. A bit off-topic, but for visibility between different classes we have the private, public, protected, … keywords, in case you ever wondered what that’s about.

No, it would contain 5 because he used the post increment operator a++ and not the pre increment operator ++a. The difference between the two operators is when the expression value is evaluated. In the post increment operator the value is first evaluated, then the variable is incremented. Think of it like this:

return a++; is essentially equal to

int tmp = a;
a = a + 1;
return tmp;

However using the pre increment return ++a; it’s just like

a = a + 1;
return a;

So in his case, since “a” is a local variable post incrementing in a return statement is completely pointless.

True. A value is returned before it’s incremented. Now that’s just silly :slight_smile:

@OP why not simply return a + 1; ? It’s completely meaningless the way it is.
Refrain from doing fancy operations until you get a good grip what’s going on with them.

We’re using ++ and – when we want to store the changed value back.
And it matters whether it comes before or after a variable. As Bunny83 said, there is a prefix variant along with the suffix one. Obviously, because we want to store the changed value back, you can’t use any of these on the expression, because they apply only to variables.

However, even though you’ve managed to change the original variable a, you’ve failed to notice two things:

  1. As Bunny83 observed, the change was practically ignored, because it comes after return.
  2. Even if you’d change this to pre-increment, the change would be ignored, because a is declared as a primitive value, and these are passed by value.
using UnityEngine;

public class MyClass : MonoBehaviour {

  void Start() {
    int a = 5;
    MyIncrMethod(a);
    Debug.Log(a); // 5
  }

  int MyIncrMethod(int a) {
    a++;
  }
 
}

If we add return, obviously we can capture the value and get it back, but that doesn’t change the fact that a stays the same.

using UnityEngine;

public class MyClass : MonoBehaviour {

  void Start() {
    int w = 5;
    w = MyIncrMethod(w);
    Debug.Log(w); // 6
  }

  int MyIncrMethod(int a) { // the value here is just a copy, because the argument is passed by value
    a++; // this operation doesn't work on the original location in memory
    return a; // we now capture locally incremented 'a' and return it
  }

  // this will also work
  // int MyIncrMethod(int a) {
  //   return ++a;
  // }
 
}

we could’ve just as well used return a + 1 for the same result
(this is, in fact, recommended in this case, why assigning something back if it’s going to be wasted?)

using UnityEngine;

public class MyClass : MonoBehaviour {

  void Start() {
    int w = 5; // notice the different names between two contexts?
    w = MyIncrMethod(w); // any relationship ends here
    Debug.Log(w); // 6
  }

  int MyIncrMethod(int a) {
    return a + 1;
  }

}

There is a way however to change the primitive value from inside the method

using UnityEngine;

public class MyClass : MonoBehaviour {

  void Start() {
    int w = 5;
    MyIncrMethod(ref w); // the argument is now passed by reference
    Debug.Log(w); // 6
  }

  void MyIncrMethod(ref int a) {
    a++;
  }

}
1 Like

Uff i overlooked that, good thing you caught and corrected it :slight_smile:

It was for learning purposes, this is not a code used in a real game.

Because you totally wrote it much better in that other code right? :wink:
Of course, nobody here has any doubts that you can do better.

As long as you keep learning, you’re fine.