Godot 4.3
How do I know if a variable or function should be public or private? Another script in the future might require access to a particular variable or function that I decided earlier was private.
Godot 4.3
How do I know if a variable or function should be public or private? Another script in the future might require access to a particular variable or function that I decided earlier was private.
GDScript only has public variables and functions, there is no private members like in C++
Excellent question, but I’m afraid the answer isn’t going to be black and white.
It has to do with encapsulation and coherence. There is, technically, nothing that stops you from writing a BackgroundMusicManager
that is also responsible for drawing your game’s title screen and keeping track of your high scores. You could write a class like that, but you also understand that it would be silly for the class to do anything but play music and switch between music tracks. That is to say, all of the class’ functions should be coherent i.e. share the same goal.
Likewise, you don’t want different classes to bury their fingers into each other’s internals just because they can. The BackgroundMusicManager
might one day need to do something that some other class already does. It might be tempting for the BackgroundMusicManager
to call that function. But what if one day somebody makes a tiny change to the function? It might unintentionally break the background music manager.
Public and private variables and functions help create the interface of a particular class. (Not to be confused with C#'s ‘interface’ keyword, although the concepts are related.) It’s a way for a class to declare 'anyone is allowed to know about these three functions (i.e. public functions), but these other four are purely for my own use (i.e. private functions.) That way you can help prevent unintentional dependencies from growing.
It is also a good tool for helping you reason about your code. If you have a private function and often find yourself thinking ‘hey, this other class could really use that function’ , then that’s a sign that maybe your design is a little shaky and that the function needs a different home.
If you’re working with GDScript, then it should be said there aren’t really private variables and functions. That doesn’t mean it’s not a good idea to think about how to organize your code. My convention is to do the same thing I do when working in Python (a different language that also doesn’t have a distinction between public and private members), and that is to prepend names of things that should be private with an underscore.
Okay, so technically any class can reach into any other class and fiddle with the properties and methods. But the underscore is just a reminder to the coder that the underscored variable or method is not mine to use. Do I have that right?
Yes all members are always accessable, in python it is common practice to use underscores for private variables, if you see my_table._data
then it may be unsafe.
This isn’t as common in Godot and Godot uses underscored functions to denote overrides instead like _ready
is a Node override that will be called automatically when the Node is added to the scene tree. So it may be confusing to also use underscores to denote private members, when it’s already being used for overrides.
Godot’s base nodes do have private non-accessable data through the C++ side of things that are simply not exposed to GDScript in any way. You can do the same with GDExtensions in any compiled language of your choice.
Good points. Thank you.
It sounds like you’re using C#, since gdscript doesn’t really have notions of private/public. Your question is the topic of lots of books on software design, so I’ll just recommend that you follow the Law of Demeter, which usually takes care of this sort of thing. In this specific case, that means adding setters/getters for any private variables that you later want to make public, and setting up a sort of hierarchy of these if you end up calling deep into some sub-sub-sub object. (If your method foo(x, y, z) has to call z.get_bar().get_baz().do_thing(), then Bar should have a do_baz_thing() method that forwards to get_baz().do_thing(), and Z should have a method that forwards to that). This makes modification easier/safer if it is always adhered to, and is just painful enough that if you find yourself doing it too much, you’ll be forced to think of a better abstraction.
But if your game is a single-person project and only has a few interacting modules, I personally don’t see an issue with having everything be public.