Swift init problems

Arghh, this is always so annoying. What am I doing wrong?

Xcode (12b6, SPM, 5.3) says "Constant 'self.propertyDescriptors' used before being initialized" at the call to buildPropertyDecsriptors(). But I don't see it being used at all, just the attempt to assign it.

Other annoying things: I can't seem to let it default uninitialized optional properties to nil (I thought Swift used to do that?)

struct
MachineContent : Content
{
	let id: UUID
	let name: String
	let imageURL: String?
	let libraries: [LibraryContent]?
	let propertyDescriptors: [UUID : PropertyDescriptorContent]?
	
	init(id inID: UUID, name inName: String, imageURL inImageURL: String?, libraries inLibraries: [LibraryContent]? = nil)
	{
		self.id = inID
		self.name = inName
		self.imageURL = inImageURL
		self.libraries = inLibraries
		self.propertyDescriptors = nil
	}
	
	init(from inMachine: Machine, loadDescriptors inLoadDescriptors: Bool = true)
	{
		self.id = inMachine.id!
		self.name = inMachine.name
		self.imageURL = inMachine.imageURL
		
		if inLoadDescriptors
		{
			self.libraries = inMachine.toolLibraries.map { LibraryContent(from: $0) }
			self.propertyDescriptors = buildPropertyDecsriptors(machine: inMachine)    // Error here
		}
		else
		{
			self.libraries = nil
			self.propertyDescriptors = nil
		}
	}
	
	func
	buildPropertyDecsriptors(machine inMachine: Machine)
		-> [UUID : PropertyDescriptorContent]?
	{
		//	Get a unique set of PropertyDescriptors…
		
		var descriptors = Set<PropertyDescriptor>()
		inMachine.toolLibraries.forEach
		{ (inLibrary) in
			inLibrary.tools.forEach
			{ (inTool) in
				inTool.properties.forEach { descriptors.insert($0.descriptor) }
				inTool.tool?.properties.forEach { descriptors.insert($0.descriptor) }
				inTool.holder?.properties.forEach { descriptors.insert($0.descriptor) }
				inTool.insert?.properties.forEach { descriptors.insert($0.descriptor) }
			}
		}
		
		var descContent = [UUID : PropertyDescriptorContent]()
		descriptors.forEach
		{ (inDesc) in
			descContent[inDesc.id!] = PropertyDescriptorContent(from: inDesc)
		}
		
		return descContent
	}
}

Instance methods use the entire self, and require self to be fully initialized.

2 Likes

I wish there was a way around that. I ended up making the variables var.

I'd also argue the error message is confusing.

You could make the method (private) global function that takes only necessary arguments.

Sure, or make it static, but ugh.

Oh, no, that doesn't work. Why not?

What does the code look like?

func add1(_ value: Int) -> Int {
    value + 1
}

struct Foo {
    let a, b: Int
    init(a: Int) {
        self.a = a + 1
        b = add1(self.a)
    }
}

Why can't I do this?

struct Foo {
    let a, b: Int
    init(a: Int) {
        self.a = a + 1
        self.b = Self.add1(self.a)
    }
    static func add1(_ value: Int) -> Int {
        value + 1
    }
}

You can? I don't get any error. Which version are you using?

Xcode 12b6, SPM, 5.3

I added static to buildPropertyDecsriptors, and called it in init with Self. buildPropertyDecsriptors().

That should work. What error do you get? You have misspelled decsriptors. Perhaps you haven’t in all places?

My bad. That error does clear up when I make it static. The other errors (Return from initializer without initializing all stored properties) persist when I make the field let instead of var.

I thought Swift defaulted Optional types to nil.

It only applies to Optional var. There's no default value for let of any type.

Somewhat of a quirk, and some even suggest making it consistent by removing default from Optional var.