Здравствуйте, Дарней, Вы писали:
Д>лучще приведи пример кода, где не жить не быть — но без нелокальных возвратов обойтись нельзя
Да нет такого кода. Но смысл я понял.
Там, где дотнету приходится делать два метода: FindFirst и Apply, смоллток обходится одним. Просто потому, что решение о том, продолжать итерацию или выйти "изо всего" принимается в "делегате".
В более сложных случаях давайте вспомним, как мы делали поиск по дереву. Конечно же рекурсия; и конечно же надо было обязательно оборудовать ее проверкой на продолжение и сохранением найденного элемента...
Если бы нелокальный возврат существовал бы в дотнете, это работало бы как-то так:
public interface IRecursible<T>: IEnumerable<IRecursible<T>>;
public static void ForEach<T>(T root, Action<T> action)
where T: IRecursible<T>
{
action(root);
foreach(T child in root)
ForEach(child, action);
}
Это мы так один раз объявили служебный метод. Его можно применять чтобы, например, выводить все дерево:
class MyItem: IRecursible<MyItem>
{
// тривиальная реализация интерфейса поскипана
public string Name;
}
public static PrintAll(MyItem root)
{
ForEach(root, delegate(MyItem t) { Console.WriteLine(t.Name);});
}
Тривиально, не правда ли? А теперь давайте кого-нибудь найдем:
public static MyItem FindFirstStartingWith(MyTtem root, string start)
{
ForEach(root,
delegate(MyItem t)
{
if (t.Name.StartsWith(start))
super return t;
}
);
}
Здесь я применил "новый" оператор super return, чтобы намекнуть на нелокальный возврат (в отличие от обычного return, который все равно приведет к ошибке компиляции из-за несовпадения типа получившегося анонимого делегата с Action<MyItem>).
На что стоит обратить внимание?
1. Все очевидно. Если знать, что такое супер-ретён.
2. Никакой нелокальности с точки зрения пользователя нет. Код — немногим хуже банального foreach.
3. При этом все-таки возврат может случиться с произвольной глубины стека — ведь Apply вызывает себя рекурсивно...
4. Мы обошлись без написания специального метода поиска в дереве, типа вот такого:
public static bool FindFirst(T root, Predicate<T> condition, out T result)
where T: IRecursible<T>
{
if(condition(root))
{
result = root;
return true;
}
foreach(T child in root)
{
if (FindFirst(child, condition, out result))
return true;
}
return false;
}
public static MyItem FindFirstStartingWith(MyItem root, string start)
{
MyItem result;
if (FindFirst(root, delegate(MyItem t) { return t.Name.StartsWith(start);}, out result))
return result
else
return null;
}
5. На самом деле в данном случае не нужен весь этот лишний мусор в виде FindFirst. И ForEach тоже не нужен.

ForEach уже сделан. Им и надо пользоваться в таких случаях:
public static IEnumerable<T> IterateThrough<T>(T root)
where T: IRecursible<T>
{
yield return root;
foreach(T child in root)
foreach(T grandchild in IterateThrough(child))
yield return grandchild;
}
public static void PrintAll(MyItem root)
{
foreach(MyItem item in IterateThrough(root))
Console.WriteLine(item.Name);
}
public static MyItem FindFirstStartingWith(MyItem root, string start)
{
foreach(MyItem item in IterateThrough(root))
if (item.Name.StartsWith(start)
return item;
return null;
}

1.1.4 stable rev. 510