Обработка StackOverflow

Через Stack<T>, насколько понял, Вы это имели ввиду.

Нет. Я имел ввиду, что рекурсию, как правило, описывают неэффективным способом, т.к. он проще. Я бы вообще отказался от неё. Овчинка выделки не стОит.

Значит, я неправильно Вас понял.

<личное мнение>Я думал Вы про Stack<T>, так как под «вручную» я именно это и подразумевал.</личное мнение>

Я под ручным подразумевал тот код, который приведён выше. Как делать через Stack<T> я не знаю.

Под одним и тем же понятием понимали совсем разное… :slight_smile: Что-ж, бывает.

1 лайк

Я вообще не понимаю о чем вы говорите. Ручная реализация рекурсивных вызовов подпрограмм через библиотечный Stack<> на .NET? :thinking: Это вообще как? Можете привести пример?

Такое, наверное, возможно, только если писать свой собственный интерпретатор с другого скриптового языка, да и то это будет очень неудобно и неэффективно. Да и не будут это настоящие “вызовы”, а только поверхностная эмуляция передачи управления.

Поддержка же нативных рекурсивных вызовов в виде команд работы с аппаратным стеком в ОЗУ существует в системе команд любого универсального процессора (PUSH / POP / RET / IRET).

Это смотря какие у вас приоритеты в конкретном случае: простота и изящество кода (а значит, он и пишется быстрее, и понимать/поддерживать его потом проще) или же максимальная производительность в рантайме. Тут нет универсальных критериев для всех и каждого.

Да, у рекурсии (особенно множественной) есть свои существенные недостатки – сложность отладки в нетривиальных случаях, риск исчерпания стека в рантайме и меньшая скорость работы по сравнению с циклическими аналогами. Но даже это не всегда так (см. ниже).

Не во всех. В функциональных, и особенно, логических ЯП (типа Пролога) рекурсия используется очень активно, как внутри (на уровне библиотечных функций и среды исполнения), так и снаружи (на уровне кода пользователя). Но там активно применяются различные оптимизации на низком уровне, типа гарантированной раскрутки концевой рекурсии в цикл.

Кстати, это можно было бы реализовать и в компиляторе Паскаля. @Admin, не думали над этим?

3 лайка

да, прямо страдаем от этой невозможности.

2 лайка

Чего только тут не начитаешься… От рассказов, что не надо использовать рекурсию, до советов употреблять волшебный Stack < T> и рассуждений, что стек - это аппаратно реализованная быстрая память. Как все запущено, однако…

Ответ на первоначальный вопрос получен: это глюк .NET. PascalABC.NET его лишь воспроизводит. Но было бы правильно убрать из документации (несуществующую) возможность обработки StackOverflowException.

Скорее всего, путают внутренние регистры/стеки возврата и данных или кэш процессора с разной архитектурой, и хотя можно извратиться с внешней структурой, ограничить параметры или отказаться от рекурсии, но как правильно решить проблему возврата управления? Насколько я понял, даже при известном размере итерации проверка доступной памяти перед следующим циклом не всегда сработает

Через Stack<T> действительно можно имитировать рекурсию вручную самому. Ограничение на переполнение в такой реализации, разумеется, будет снято. Я и не говорил, что это будет настоящие вызовы, поэтому и употреблял слово «имитировать».

Код, думаю, можно было бы улучшить, но выкладываю оригинал:

uses GraphABC; 
const
  Angle = -Pi / 4;

type
  EdgeData = auto class
    A, B, C: Point;
    R: integer;
  end;

var
  DataStack: Stack<EdgeData>;

function RotatePoint(pA: Point; r, angle: integer): Point;
begin
  var angle2 := DegToRad(angle);
  Result := new Point(Round(pA.X + r * Cos(angle2)), Round(pA.Y + r * Sin(angle2)));
end;

procedure PushTreePart(pB: Point; r: integer) := DataStack.Push(new EdgeData(RotatePoint(pB, r, -135), pB, RotatePoint(pB, r, -45), r));

function RIsBig(dt: EdgeData) := dt.R > 5;

begin
  LockDrawing();
  
  DataStack := new Stack<EdgeData>();
  
  PushTreePart(new Point(300, 300), 200);
  while DataStack.Count > 0 do
  begin
    var dt := DataStack.Pop();
    Line(dt.A.X, dt.A.Y, dt.B.X, dt.B.Y);
    Line(dt.B.X, dt.B.Y, dt.C.X, dt.C.Y);
    if RIsBig(dt) then
    begin
      var r2 := dt.R div 2;
      PushTreePart(dt.A, r2);
      PushTreePart(dt.C, r2);
    end;
  end;
  Redraw();
end.

. Про подобное применение Stack<T> и шла речь в моих сообщениях.

1 лайк

Очень странно наблюдать, как вы разъясняете азбучную истину о том, что рекурсия эквивалентна итерации, ссылаясь исключительно на библиотечную реализацию стека в конкретной системе.

Меня попросили привести пример кода с Stack<T>, я его и привёл. Ничего больше. Кроме того, я не говорил, что этот подход наилучший.

То, что рекурсия эквивалентна итерации доказано строго математически. В частности, на этом основано лямбда-исчисление. Математика утверждает, что рекурсию можно преобразовать в итерацию и наоборот, но не рассказывает, как именно это надо делать. Вот практика - она дает множество советов, когда заменять, а когда информирует, что программист и дальше будет “колоться, плакать,но продолжать лезть на кактус”.(с)

1 лайк

Что-то я не припомню чтобы у нас в документации была такая гадость

2 лайка

И к чему это ёрничание, а?! Я написал это применительно к возможности эффективного использования рекурсивных алгоритмов, чья глубина может потребовать бОльшего стека. Понятно, что вам лично и вашим школьникам это до лампочки. Но не о вас лично же шла речь.

@c3c, в справке сказано про StackOverflowException, но нигде не написано, что его возможно обработать.

Я боюсь, что вы обращаетесь не по адресу. @ibond живёт и работает в Германии.

А так, да - 1 Мб в .NET на стек и изменить это нельзя. Правда, можно изменить в создаваемом потоке.

Что же касается сожаления по тому или иному поводу, то позволю высказать своё: жаль, что в Ростове выпадает так мало снега.

2 лайка

Уточню: в Ростове-на-Дону. В Ростове-то его выпадает обычно больше, чем надо…

2 лайка

А мне бы понравилось.

<личное мнение>Не думаю, что высказывание в лицо своих мыслей, направленных на конкретную личность, не приведёт к неконструктивной беседе. Лучше не стоит. Тем более с поднятой темой это никак не коррелирует.</личное мнение>

@spectatorBH, @Admin, @Gleb, @RAlex, давайте вернёмся к изначальной теме. Ростов-на-Дону и снег можно пообсуждать через личные сообщения.