How to identify an inner class

Godot Version

4.5.1

Question

I have aninnerclass for packing data, and I wish to know its class name or script name during serialization. The class looks like this:

extends Node2D

class testing:
	var a:String="asd"
	var b:int=123

var c:=testing.new()

func _ready() -> void:
	var script:Script = c.get_script()
	var base_script = script.get_base_script()

	print("class ",c.get_class(),
	"\nglobal_name ",script.get_global_name(),
	"\nbase_script ",base_script,
	"\nresource_name ",script.resource_name,
	"\nresource_path ",script.resource_path,
	"\nmeta ",script.get_meta_list())

However I fail to get any information about this class “testing”. The output of the above code:

class RefCounted
global_name 
base_script <Object#null>
resource_name 
resource_path 
meta []

Is there any way to get any information about this class?

As far as I’m aware there’s no way to get that information. Inner classes are pretty limited.

1 Like

If that is the case, I guess a workaround like this would do for me:

	var s = c.get_script()
	var ref = RefCounted.new()
	ref.set_script(s)
	assert(ref is testing)
	print(ref.a,ref.b)

Above prints

asd123

I just want to know:

1.Are inner classes always child-class of RefCounted?

2. What’s the performance overhead of constructing thousands of objects like this.

Yes

You’ll have to measure it, but it really depends on what other nodes are in the uber object, and what your inner class actually looks like. Since you don’t seem to want to share your code, that’s going to be a you exercise.

In general though, an inner class that has its own member variables is going to bloat your object depending on how it is used.


Inner classes make no sense in Godot IMO. The popular argument for inner classes is, “They increase encapsulation and make code clearer by keeping it together”. In Godot, they in no way increase encapsulation because Godot does not have access modifiers. So another class can access the inner class of another object at any time because everything is public.

They do not make code clearer either in my experience, regardless of the language. Instead, they tend to be really clever ways to increase cognitive load on the developer. Especially when refactoring or fixing bugs in that containing class.

Functionally, they also typically increase memory usage, but that depends on how they are used.

Inner classes are an anti-pattern IMO within Godot. It is a neat little feature that was introduced because people wanted to use them to resolve problems with cyclic dependencies. Which again, in my opinion, is not the way to deal with cyclic dependency problems.

Inner classes were introduced to Java in 1997. They are a feature that perhaps made more sense at that time. But times change, and a personally I think they should go the way or the ternary operator.


On a separate note, Godot is really bad about identifying custom classes. The only thing you can do is use the is keyword. Trying to get the class name of a class will always return the built-in class that was extended.

Yes and no. You cannot get the name of the class as a string from the object, but you can from the script: "is_class" function for Objects of a custom class - #12 by zigg3c

Any class in Godot automatically inherits RefCounted if extends is omitted. Inner classes are no exception, but you can write class testing extends Object and thus have it not inherit RefCounted.

You can also create a new object instance directly from the script:

var t := Test.new()
var s := t.get_script() as Script
print(s.new() is Test)

It seems like Node directly inherits Object.

Class:   Node2D
Inherits:   CanvasItem <   Node <   Object

I never paid attention before, and I do wonder why it does not inherits Refcounted, but I guess that’s a bit off topic.

Personally I use inner class as a “data tuple strictly private to the containing class”. The need for which comes from the fact that godot doesn’t have a tuple built-in and using array or dictionary for packing data lacks typing. Sparing a whole file for a 3-liner tuple class also feels like an overkill: Added file management overhead; extra confusion with all that extra class names in auto-complete.

I would stick with my way of using them as tuple for the time, until godot decided to implement a tuple built-in.

True, but that was in OP’s original post so I figured they already knew they could do that. And that definitely wouldn’t work for an inner class.

RefCounted is for Objects that Godot users don’t need to memory manage. They free themselves when not in use. Nodes stick around until queue_free() is called on them or a parent node, even if they are removed from the tree completely.

Something that’s long overdue.

Whatever works for you.

Yes, if you want multiple typed pieces of data and want to enforce it, I can see your reasoning.

Agree to disagree with you both. I understand where you are coming from. However in Godot, we have the Resource class, which is specifically meant not only to provide tuple/struct functionality, it has a bunch of nice extras that are really helpful when making a game. For example, you can easily edit a Resource in the Inspector, and save them to disk when you want to as separate data files without any extra work. You can also save and load them to/from disk with a single command.

A Resource can also hold a reference to an icon so that it shows up in the Inspector clearly. They also support code so that you can create setters and getters, or more complex functions.

Personally, even if I’m only storing two or three variables, if I want to pass them around, I will stick them in a Resource. Because in my Godot experience, I typically later appreciate it being there.

1 Like

I’d just want them as a faster and more efficient alternative to arrays, especially when returning structured data.

Good implementation would also guarantee locality and increase cpu cache hits.

These days I leave optimization to compiler creators.

Besides, in most games, the bottlenecks are GPU-related, not data structure related.

In those cases where it is necessary to create optimized data structures, a Resource is just a RefCounted with a couple extra functions anyway.

Well GDScript devs are compiler creators.

I do a lot of procedural geometry generation, and that’s mostly cpu bound.

Besides performance, using a tuple is less verbose and more convenient than introducing a whole new class just to exchange some throwaway data. And high level languages like GDScript are all about convenience.

Not sure what’s the official stance on tuples. The drawback is that it’d complexify the language as tuples don’t add any new apparent functionality over arrays, unless they’re typed as proposed here

What probably irks me the most is returning pairs, which is a fairly common occurrence. Both; objects and arrays are just too heavyweight for that, but there are no other options. Tuples would be ideal.

Yes. That was my point.

Yes, but are most Godot users doing that?

I’m just imagining all the questions about, “A tutorial/AI said I could do this but I don’t get it.”

Dunno, but this discussion on struct implementation seems much more alive at this point. The team edited that tuple discussion, but never chimed in.

Fair enough, but in languages that don’t support tuples I’ve always been able to figure out a way to handle these things. Also, at least in my experience, one tends to do a lot less data returning in functions in Godot. Typically most of the data you want to manipulate is class data. And if you want to pass multiple pieces of information, typically you do so in a signal. For whatever reason, I just don’t find myself returning a lot of stuff, and when I do it’s usually a node reference (mostly for recursion).

That’s probably because you don’t do a lot of calculations :wink:

Even Godot’s API functions would benefit from a fast tuple/struct type of container. The current convention is to return string-keyed dictionaries. This looks almost comical when combined with performance critical calls like those for direct collision testing.

That, and I am a big fan of encapsulation, abstraction and SRP.

I admit there could be some benefit. But then, that’s why we have GDExtension.

Sure, if by “we” you mean whoever was able to survive the build environment setup, and is capable of using engine’s source code as an API reference :smile:

1 Like

Yes, but to be fair, the people worrying about that level of optimization are experienced developers and they have the skills to make that happen.