--[[
	Recalculates this Computed's cached value and dependencies.
	Returns true if it changed, or false if it's identical.
]]

function class:update()
	-- remove this object from its dependencies' dependent sets
	for dependency in self.dependencySet do
		dependency.dependentSet[self] = nil
	end
	
	-- we need to create a new, empty dependency set to capture dependencies
	-- into, but in case there's an error, we want to restore our old set of
	-- dependencies. by using this table-swapping solution, we can avoid the
	-- overhead of allocating new tables each update.
	self._oldDependencySet, self.dependencySet = self.dependencySet, self._oldDependencySet
	table.clear(self.dependencySet)
	
	local ran, newValue, newMetatable = Dependencies.captureDependencies(self.dependencySet, self._processor)
	
	if ran then
		if not self._destructor and utility.needsDestruction(newValue) then
			warn("destructorNeededComputed")
		end
		
		if newMetatable then
			warn("multiReturnComputed")
		end
		
		local value = self._value
		
		if self._destructor then
			self._destructor(value)
		end
		
		self._value = newValue
		
		-- add this object to the dependencies' dependent sets
		for dependency in self.dependencySet do
			dependency.dependentSet[self] = true
		end
		
		return not utility.isSimilar(value, newValue)
	else
		-- this needs to be non-fatal, because otherwise it'd disrupt the
		-- update process
		warn("computedCallbackError", newValue)
		
		-- restore old dependencies, because the new dependencies may be corrupt
		self._oldDependencySet, self.dependencySet = self.dependencySet, self._oldDependencySet
		
		-- restore this object in the dependencies' dependent sets
		for dependency in self.dependencySet do
			dependency.dependentSet[self] = true
		end
		
		return false
	end
end

return Computed
