Вместо того, чтобы спрашивать, должно ли что-то возвращать значение или выдавать исключение, нужно спросить, что функция обещает сделать. Если функция обещает переместить узел, она должна выдать исключение, если не может. Если функция обещает переместить узел, если это возможно, или указать через возвращаемое значение, что он не может быть перемещен, а только выдать исключение, если структура данных в некоторой степени повреждена, помимо той, которая подразумевается в способности переместить узел, это должно сделать это. Иногда может быть полезно предоставить функции как «делай это», так и «попробуй это».
Относительно того, какой тип исключения генерировать, мне откровенно не нравится концепция выбрасывания большинства встроенных типов исключений из пользовательского кода, поскольку нет хорошего программного способа определить, было ли ArgumentException выброшено из вашей процедуры или из какой-либо процедуры это вызвано вашей процедурой, и большинство исключений ничего не говорят о качестве базовой структуры данных.
Если кто-то пытается, например, анализирует файл с диска и интегрирует его с существующей структурой данных и выдает исключение, не имеет значения, было ли исключение ArgumentException, или SubscriptOutOfBoundsException, или DiskReadErrorException, или что-то еще. Наиболее важным является то, была ли попытка разбора откатана таким образом, чтобы оставить структуру данных действительной; второстепенное значение имеет возможность анализа файла другим способом или при других обстоятельствах. Тип исключения действительно имеет значение только в том случае, если он может ответить на эти первые два вопроса.