This code raises a parsing error:
func foo():
func bar():
pass
pass
Error pasing expression, misplaced: func
Is there a special keyword or other trick to define an inner function?
Not in Godot 3.x. This is supported in Godot 4.0, with the given syntax. This was the proposal: "Add lambda functions in GDScript".
Addendum: I should mention that the convention is that whatever stars with underscore ("_") is to be considered private. And accessing them externally is at your own risk. This approach has worked well for Python for a long time.
There are some things you can do…
As you would know, you can use setget
to have getters and setters which will run every time you access a field externally, or using self
. Well, you can write getters and setter that just fail.
For example:
var _value setget noset, noget
func noset(_new_value):
push_error("Invalid access.")
func noget():
push_error("Invalid access.")
This results in an error when used from another script. Also results in an error when used from the same script with self._value
, but not using _value
from the same script (without self). Thus we have a "private" field.
Similarly, by only specifying the setter, we can have a readonly property:
var value setget noset
func noset(_new_value):
push_error("Invalid access.")
Following the same idea, we can store a token in a private field. And use it as access check. We will use a new object, so that it is impossible match it by chance. This is similar to having a monitor (as understood in threading), holding the lock, and doing try_enter… Except without the threading part.
var _token setget noset, noget
func noset(_new_value):
push_error("Invalid access.")
func noget():
push_error("Invalid access.")
func _method(token):
if token != _token: # try enter
push_error("Invalid access") # did fail to enter
return
# did enter
pass
func _init():
_token = ClassDB.instance("Object") # hold lock
From the same script, you have access to _token
. Thus, you can call the method like this:
_method(_token)
However, _token
is "private", and passing anything else will result in an error. Thus, it will not be possible to use the method from another script.
This is an improved version of a comment by me2beats. On the proposal "Add public/private access modifiers to GDScript and autocompletion improvements".
Something else you can do is create a script in from code (think "eval"). This is done with the GDScript
class.
You can create your script like this:
var script = GDScript.new()
script.source_code = "func run():print('hello world')" # create code at runtime
script.reload()
Instantiate it like this:
var script_instance = script.new()
And, of course, you could hold the instance in a "private" field. You might also be interested in FuncRef
.
Then use whatever you declared in there, in this case the run
function:
script_instance.call("run")
If you don't to create code at runtime, you might instead load a script with load
. Or use an Inner class.
If you don't need a whole script, you might use Expression
instead.