Say I have a script which contains a class with a value, which in turn contains another class, then yet another, each extending the last like so:

extends Node

class Item:
	var name : String

	func _init(initial_value):
		name = initial_value
	
	class Weapon extends Item:
		
		class Sword extends Weapon:
			...

I want to create an instance of the Sword class, which supposedly inherits both the Item and and Weapon classes, so I would expect to be able to give it a name since that's a property of Item:

var cool_sword = Item.Weapon.Sword.new("Cool Sword")
print(cool_sword.name)

But this doesn't work because the class Sword doesn't have an init, so I tried doing it like this:

var cool_sword = Item.new("Cool Sword").Weapon.Sword.new()
print(cool_sword.name)

That obviously didn't work either, as the name value doesn't seem to exist in the Sword class so I can't call it.

I just want to create a parameter which is inherited between classes and can be set once the instance is created. Obviously this isn't the right way to do that - can anyone explain why and maybe tell me how to properly do what I'm trying to do?

I understand that doing this all in one script is definitely not ideal for real-world application - But just go along with me here. I'm only prototyping something and I want to keep it confined to one script, but if that's the biggest problem please do tell me.

So you can have nested classes and call them as you would expect:

extends Node

class_name Something

var some_name = "Godot Rules"

func say():
	print(some_name)

class Other:

	var other_type = "I Like Blender"

	func say():
		print(other_type)
var some = Something.new()
some.say()
var other = Something.Other.new()
other.say()

But in your case if won't work because you can't have a class inheriting from itself (cyclic reference). See for the Weapon to be initialized, Item has to be initialized first, but that won't happen until Weapon is initialized, so it will go on forever and never work. Honestly, just define them in separate files.

Yeah, nesting classes makes no sense in this case, it just creates confusion. You need to make _init() functions for inherited classes too if you want to pass argument via new(). The catch is, all super class constructors are implicitly called in inheritance order, and you need to ensure that they all get the arguments they want. There's a syntax for that:

class Item:
	var my_name
	func _init(name: String):
		self.my_name = name

class Weapon extends Item:
	func _init(name: String).(name): 
		# .(name) gives an argument to the 
		#  implicit super class constructor call
		pass

class Sword extends Weapon:
	func _init(name: String).(name):
		pass

func _ready():
	var new_sword = Sword.new("Excalibur")
	print(new_sword.my_name)

@cybereality I too thought inheriting an outter class from an inner class would cause some type of circular dependency complaint. But surprisingly - it doesn't. Looks like nesting is just a namespace thing.

#works fine
class A:
	class B extends A:
		class C extends B:		
			pass

func _init():
	A.new()
	A.B.new()
	A.B.C.new()

Interesting. It didn't work when I just tried by maybe I made an error.

It's very confusing. They should have forbid inheriting from an outer class.

Thanks. I just didn't fully understand how classes worked or how to use them, and solved my problem by separating the scripts for organization's sake and setting the member variables after creating the objects instead of in their class constructors. However, @xyz 's tip about using _init().() is just as useful.

a year later