Skip to content

What is TreeCollection for? #210

Description

@player-03

(This still isn't the big change I plan to propose, but it's related and I want to address it first.)

I recently noticed how similar TreeCollection is to ArrayHierarchicalCollection, and it got me thinking, what does it really provide? The answer is simple enough, I guess: it provides convenience. You can use AHC if you already have data in a tree structure. If not, TreeCollection provides TreeNode to help you build a tree. Useful!


But hang on, it's less useful than it could be. All its functions take and return TreeNode<T>, and you have to get item from there yourself.

public function get(location:Array<Int>):TreeNode<T>
public function set(location:Array<Int>, value:TreeNode<T>):Void
public function locationOf(item:TreeNode<T>):Array<Int>

Wouldn't it be more convenient if they took and returned T, instead? If I have an instance of a thing, and I want its position in the tree, I'd like to pass in T to locationOf(), and have it search for the node containing that item. I suppose the counterargument is that taking TreeNode<T> is more precise (if the tree has two of the same value, it at least doesn't have two of the same TreeNode), and returning TreeNode<T> lets the user call isBranch() and access children.

And of course, the API has been released, so it's basically set in stone.


A funny consequence of this particular API: there's no practical difference between TreeCollection<T> and ArrayHierarchicalCollection<TreeNode<T>>.

On realizing this, my first thought was to rewrite TreeCollection to pass everything to an internal ArrayHierarchicalCollection. Sure enough, all the tests still pass. This brings the file down from 682 lines to 242, and nearly all that remains is boilerplate. Duplicate the function signatures, pass the arguments to the wrapped function, and return its result. Rinse and repeat.

Wait a minute, that's what @:forward does! So I rewrote TreeCollection as an abstract:

@:forward
abstract TreeCollection<T>(ArrayHierarchicalCollection<TreeNode<T>>) to IHierarchicalCollection<TreeNode<T>> {
	/**
		Creates a new `TreeCollection` object with the given arguments.

		@since 1.0.0
	**/
	public function new(?array:Array<TreeNode<T>>) {
		this = new ArrayHierarchicalCollection<TreeNode<T>>(array, treeNodeItemToChildren);
	}

	private static function treeNodeItemToChildren<T>(item:TreeNode<T>):Array<TreeNode<T>> {
		return item.children;
	}
}

That's a 75 line file, with 15 lines of actual implementation, and the tests still pass!


Obviously, that kind of reduction wouldn't be possible if TreeCollection did something unique. If it took and returned T, most functions would need some custom code (especially locationOf()). But there's nothing unique yet, and that's why I thought the question was worth asking. What is TreeCollection for?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions