Global variables, in general, are discouraged (and have been in pretty much all programming for decades now).
In Julia, when you define your function p the compiler simply notes that when executed you want to look up whatever the value of b is at that time. You can see this by using @code_lowered:
@code_lowered p(1)
CodeInfo(
1 ─ %1 = a + Main.b
└── return %1
)
It’s not necessary to declare variables ahead of time - in fact you don’t need to declare functions or anything else. For example:
f(a) = g(a)
g(a) = a + 1
This works fine as the compiler is happy to accept that when f is called it is to use whatever definition of g that it has at the time.
This is important for multiple dispatch. The precise method to call will depend on the types of the actual arguments - and this may not be known at time of declaration.
But please, reconsider the usage of global variables. There are many alternatives depending on the exact use-case.