From 497579203b76515f048ff5b8019dc21c8838afaf Mon Sep 17 00:00:00 2001 From: Adriaan de Jongh <5611323+AdriaandeJongh@users.noreply.github.com> Date: Tue, 19 Dec 2023 14:26:16 +0100 Subject: [PATCH] added section on common unsafe operations and their safe counterparts --- .../scripting/gdscript/static_typing.rst | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tutorials/scripting/gdscript/static_typing.rst b/tutorials/scripting/gdscript/static_typing.rst index 5b09677fb7a0..cf76d95d6aae 100644 --- a/tutorials/scripting/gdscript/static_typing.rst +++ b/tutorials/scripting/gdscript/static_typing.rst @@ -396,6 +396,71 @@ if you prefer a more readable and reliable, but more verbose syntax. ``UNSAFE_*`` warnings make unsafe operations more noticeable, than unsafe lines. Currently, ``UNSAFE_*`` warnings do not cover all cases that unsafe lines cover. +Common unsafe operations and their safe counterparts +---------------------------------------------------- + +Warnings: ``UNSAFE_PROPERTY_ACCESS`` and ``UNSAFE_METHOD_ACCESS`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this example, we aim to set a property and call a method on an object +that has a script attached with ``class_name MyScript`` and that ``extends +Node2D``. If we have a reference to the object as a ``Node2D`` (for instance, +as it was passed to us by the physics system), we can first check if the +property and method exist and then set and call them if they do:: + + if "some_property" in node_2d: + node_2d.some_property = 20 # gives UNSAFE_PROPERTY_ACCESS warning + + if node_2d.has_method("some_function"): + node_2d.some_function() # gives UNSAFE_METHOD_ACCESS warning + +However, this code will return ``UNSAFE_PROPERTY_ACCESS`` and +``UNSAFE_METHOD_ACCESS`` warnings as the property and method are not present +in the referenced type - in this case a ``Node2D``. To make these operations +safe, you can first check if the object is of type ``MyScript`` using the +``is`` keyword and then declare a variable with the type ``MyScript`` on +which you can set its properties and call its methods:: + + if node_2d is MyScript: + var my_script: MyScript = node_2d + my_script.some_property = 20 + my_script.some_function() + + +Warning: ``UNSAFE_CAST`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +In this example, we would like the label connected to an object entering our +collision area to show the area's name. Once the object enters the collision +area, the physics system sends a signal with a ``Node2D`` object, and the most +straightforward (but not statically typed) solution to do what we want could +be achieved like this:: + + func _on_body_entered(body: Node2D) -> void: + body.label.text = name # gives UNSAFE_PROPERTY_ACCESS warning + +This piece of code gives a ``UNSAFE_PROPERTY_ACCESS`` warning because ``label`` +is not defined in ``Node2D``. To solve this, we could first check if the +``label`` property exist and cast it to type ``Label`` before settings its text +property like so:: + + func _on_body_entered(body: Node2D) -> void: + if "label" in body: + (body.label as Label).text = name # gives UNSAFE_CAST warning + +However, this gives an ``UNSAFE_CAST`` warning because ``body.label`` is of a +``Variant`` type. This operation can be made type safe using the +``Object.get()`` method that returns the property as a ``Variant`` (or +``null`` if the property doesn't exist), using the ``is`` keyword to determine +whether the property contains an object of the right type, and using a +variable declaration with a static type:: + + func _on_body_entered(body: Node2D) -> void: + var label_variant: Variant = body.get("label") + if label_variant is Label: + var label: Label = label_variant + label.text = name + Cases where you can't specify types -----------------------------------