Hoisted ? With a pulley and a cable ?
No, with a compiler.
"Hoisting" in computing refers to the idea of "lifting" variables or code
outside of one block into another. For example, an optimization technique
is to hoist repeated if statements outside the loop. E.g. instead of:
for i in range(1000000):
if condition:
spam(i)
else:
ham(i)
Assuming that condition doesn't change as the loop runs (spam and ham
have no side-effects), this can be optimized to:
if condition:
for i in range(1000000):
spam(i)
else:
for i in range(1000000):
ham(i)
That's called hoisting.
In Python, which has first-class functions, we can do better by avoiding
code duplication:
if condition:
func = spam
else:
func = ham
for i in range(1000000):
func(i)
But either way, the decision is lifted (hoisted) out of the loop.
The issue here is not the ability to call a function before its
declaration. It's being able to do so before its definition.
Obviously you can't call a function before it is defined.
As a language without type declarations, Python doesn't need functions to
be declared ahead of time. I can define a function that calls another:
.... return 2*spam(x)
....
and so long as I eventually define spam() before calling ham(), all is
good:
.... def spam(x):
.... return x-1
....4
I can even re-define spam at runtime, and ham will see the difference:
.... return "spam "*x
....'spam spam spam spam spam spam '
But what I can't do in Python is execute ham() BEFORE spam() is defined.
(Well, I can, but I get an error.) Even if spam() is defined lower down
in the source code, Python won't see it.
As I understand it, that's not how Javascript works. The parser does two
passes over the source file, instead of one like Python. If it sees a
function definition, it hoists it out into the global environment, and
then on the second pass executes the code as needed. Using Python syntax,
this is an error:
def ham(x):
return 2*spam(x)
print(ham(3))
def spam(x):
return x-1
but Javascript will accept it perfectly fine, and output 4.
Here's another model: Pascal. Because Pascal does type checking at
compile time, it will reject the function ham() and raise a compiler
error, because it can't test the argument and output type of spam(). So
you would need a *forward declaration*. Using a mix of Python and Pascal
syntax:
# declare spam without a definition
forward spam(x: integer): integer
# declare and define ham
def ham(x: integer): integer
return 2*spam(x)
print(ham(2))
# define spam (declaration must match the earlier one!)
def spam(x: integer): integer
return x-1
It's not either/or. Any language has to provide a way to define
functions whether or not it provides a way to declare them.
Exactly. Pascal has both; Python only has definitions.
Anyway, it seems the Python way to declare a function is
def f ():
pass
That doesn't declare a function. It defines a do-nothing function. `def`
is an executable statement which happens at runtime, not a compile-time
declaration.