Информация об изменениях

Сообщение Re[5]: Delphi и велосипедирование от 25.06.2024 5:01

Изменено 25.06.2024 7:15 Sinclair

Re[5]: Delphi и велосипедирование
Здравствуйте, swame, Вы писали:

S>
  типа такого (код из нашего комплекса)?
S>

S>class function TMatchAPI.outside(aNB: TNB; aMode: TOutsideMode): RArray<TNB>;
S>var
S>  lCEs: RArray<TCE>;
S>  lRules: TCEFetchRules;
S>begin
S>  Result := RArray<TNB>.init;
S>  if TCEAPI.globalId(aNB) <> '' then
S>  begin
S>    Result.add(aNB);
S>    exit;
S>  end;

S>  lRules.init;
S>  lRules := lRules +
S>    TCERules.reducerExtraTerminals +
S>    function(aTerminal: TCIMTopologyTerminal): TFetchAction
S>    begin
S>      Result := faContinue;
S>      if isBreakObject(aTerminal.Element, aMode) then
S>        Result := faBreakAndFetch;
S>    end;
S>  lRules := lRules +
S>    function (aFrom: TCIMTopologyTerminal; var aTo: RArray<TCIMTopologyTerminal>): Boolean
S>    var
S>      lNewTo: RArray<TCIMTopologyTerminal>;
S>    begin
S>      Result := True;
S>      lNewTo :=
S>        aTo.filter(
S>          function (aT: TCIMTopologyTerminal): Boolean
S>          begin
S>            Result := isBreakObject(aT.Element, aMode);
S>          end
S>        );
S>      if lNewTo.count > 0 then
S>      begin
S>        aTo := lNewTo;
S>        exit;
S>      end;

S>      lNewTo :=
S>        aTo.filter(
S>          function (aT: TCIMTopologyTerminal): Boolean
S>          var
S>            lCandle: TCE;
S>          begin
S>            lCandle := TCEAPI.candleLine(aT.Element);
S>            Result := (lCandle <> nil) and (lCandle.terminalsS.map<TCE>(TCEAPI.connectedCE).count = 1) and isBreakObject(lCandle, aMode);
S>          end
S>        );
S>      if lNewTo.count > 0 then
S>      begin
S>        aTo := lNewTo;
S>        exit;
S>      end;
S>    end;

S>  Result :=
S>    TRStream<TNB>.just(aNB)
S>      .map(TCEAPI.extractReducers)
S>      .map<TCE>(TCEAPI.ce)
S>      .map<TNB>(
S>        procedure (aCE: TCE; var aMap: TProc<TNB>)
S>        begin
S>          TCEAPI.iterateTopology(aCE, lRules)
S>                .map<TNB>(
S>                  procedure (aCE: TCE; var aMap: TProc<TNB>)
S>                  var
S>                    lNB: TNB;
S>                  begin
S>                    if aCe.IsChildOrEqual(ttcTransformerWinding) then
S>                      lNB := TCEAPI.grpFromWinding(aCe as TTransformerWinding)
S>                    else
S>                      lNB := aCE;
S>                    if isNodeObject(aCE) and ((aMode = omNearest) or (TCEAPI.globalId(lNB) <> '')) then
S>                      aMap(lNB);
S>                  end)
S>                .forEach(aMap);
S>        end
S>      )
S>      .distinct()
S>      .toArray();
S>end;
S>


Да, что-то в этом роде.
S>Ненавижу такое написание.
Ну, так видно же, что оно противоестественно для языка.

S>1. Не поддается отладке отладчиком.

Значит, такой отладчик. На шарпе или там тайпскрипте всё прекрасно поддаётся.
S>2. сложно профилировать. сложно найти "бутылочное горлышко" производительности.
Нет ничего сложного. Если профайлер вменяемый, то он покажет, какое из замыканий вызывается чрезмерно часто. Можно будет понять, как перейти от O(N2) к O(N)
S>3. сложно рефакторить, сложно определяется на каждом этапе какая там структура данных на выходе.
Рефакторить как раз очень легко. Не очень понятно, что такое "структура данных". Если речь о типе элемента коллекции, то его хорошо видно по сигнатуре функции (и IDE подсказывает, где там что). Если речь про саму коллекцию — так их там и нет, это же ленивые итераторы. Если где-то нужно применить энергичность, то она делается вручную вставкой в конвеер операции типа .ToArray(), .ToList(), ToDictionary(...) или ещё какой-нибудь трансформации, которую можно придумать совершенно отдельно от вашего конкретного конвеера.

S>4. нереально повторно использовать код, записать похожие алгоритмы.

Всё ровно наоборот. Если ваш код переписать на нормальный язык, то останется только существенная для понимания часть. А вся логика итерирования будет спрятана под капот.
Впрочем, для эксперимента можете переписать ваш же пример на "традиционный" Паскаль, безо всех этих новомодностей с генериками, .map, .filter и прочим.
Станет ли он дружелюбнее к рефакторингу и/или записи "похожих алгоритмов"?

S>5. перегружает компилятор.

Это я оставлю на совести авторов компилятора. Тот же шарп или тайпскрипт компилируют код в функциональном стиле со скоростью мысли — то есть ничуть не медленнее Delphi.

S>>На более-менее любом современном языке это будет весьма простой генератор/итератор, за которым .filter(...).map(...).reduce(...).

S>>На Delphi остаётся только пердолиться с "процедурными типами" и/или Visitor Pattern.

S>>Возможно, на современном Delphi ситуация как-то поменялась; в том, который был актуален во времена расцвета его популярности, всё это суровая правда.

Вижу, что на современном Delphi стало ещё хуже.
Re[5]: Delphi и велосипедирование
Здравствуйте, swame, Вы писали:

  типа такого (код из нашего комплекса)?
S>
S>class function TMatchAPI.outside(aNB: TNB; aMode: TOutsideMode): RArray<TNB>;
S>var
S>  lCEs: RArray<TCE>;
S>  lRules: TCEFetchRules;
S>begin
S>  Result := RArray<TNB>.init;
S>  if TCEAPI.globalId(aNB) <> '' then
S>  begin
S>    Result.add(aNB);
S>    exit;
S>  end;

S>  lRules.init;
S>  lRules := lRules +
S>    TCERules.reducerExtraTerminals +
S>    function(aTerminal: TCIMTopologyTerminal): TFetchAction
S>    begin
S>      Result := faContinue;
S>      if isBreakObject(aTerminal.Element, aMode) then
S>        Result := faBreakAndFetch;
S>    end;
S>  lRules := lRules +
S>    function (aFrom: TCIMTopologyTerminal; var aTo: RArray<TCIMTopologyTerminal>): Boolean
S>    var
S>      lNewTo: RArray<TCIMTopologyTerminal>;
S>    begin
S>      Result := True;
S>      lNewTo :=
S>        aTo.filter(
S>          function (aT: TCIMTopologyTerminal): Boolean
S>          begin
S>            Result := isBreakObject(aT.Element, aMode);
S>          end
S>        );
S>      if lNewTo.count > 0 then
S>      begin
S>        aTo := lNewTo;
S>        exit;
S>      end;

S>      lNewTo :=
S>        aTo.filter(
S>          function (aT: TCIMTopologyTerminal): Boolean
S>          var
S>            lCandle: TCE;
S>          begin
S>            lCandle := TCEAPI.candleLine(aT.Element);
S>            Result := (lCandle <> nil) and (lCandle.terminalsS.map<TCE>(TCEAPI.connectedCE).count = 1) and isBreakObject(lCandle, aMode);
S>          end
S>        );
S>      if lNewTo.count > 0 then
S>      begin
S>        aTo := lNewTo;
S>        exit;
S>      end;
S>    end;

S>  Result :=
S>    TRStream<TNB>.just(aNB)
S>      .map(TCEAPI.extractReducers)
S>      .map<TCE>(TCEAPI.ce)
S>      .map<TNB>(
S>        procedure (aCE: TCE; var aMap: TProc<TNB>)
S>        begin
S>          TCEAPI.iterateTopology(aCE, lRules)
S>                .map<TNB>(
S>                  procedure (aCE: TCE; var aMap: TProc<TNB>)
S>                  var
S>                    lNB: TNB;
S>                  begin
S>                    if aCe.IsChildOrEqual(ttcTransformerWinding) then
S>                      lNB := TCEAPI.grpFromWinding(aCe as TTransformerWinding)
S>                    else
S>                      lNB := aCE;
S>                    if isNodeObject(aCE) and ((aMode = omNearest) or (TCEAPI.globalId(lNB) <> '')) then
S>                      aMap(lNB);
S>                  end)
S>                .forEach(aMap);
S>        end
S>      )
S>      .distinct()
S>      .toArray();
S>end;
S>

Да, что-то в этом роде.
S>Ненавижу такое написание.
Ну, так видно же, что оно противоестественно для языка.

S>1. Не поддается отладке отладчиком.

Значит, такой отладчик. На шарпе или там тайпскрипте всё прекрасно поддаётся.
S>2. сложно профилировать. сложно найти "бутылочное горлышко" производительности.
Нет ничего сложного. Если профайлер вменяемый, то он покажет, какое из замыканий вызывается чрезмерно часто. Можно будет понять, как перейти от O(N2) к O(N)
S>3. сложно рефакторить, сложно определяется на каждом этапе какая там структура данных на выходе.
Рефакторить как раз очень легко. Не очень понятно, что такое "структура данных". Если речь о типе элемента коллекции, то его хорошо видно по сигнатуре функции (и IDE подсказывает, где там что). Если речь про саму коллекцию — так их там и нет, это же ленивые итераторы. Если где-то нужно применить энергичность, то она делается вручную вставкой в конвеер операции типа .ToArray(), .ToList(), ToDictionary(...) или ещё какой-нибудь трансформации, которую можно придумать совершенно отдельно от вашего конкретного конвеера.

S>4. нереально повторно использовать код, записать похожие алгоритмы.

Всё ровно наоборот. Если ваш код переписать на нормальный язык, то останется только существенная для понимания часть. А вся логика итерирования будет спрятана под капот.
Впрочем, для эксперимента можете переписать ваш же пример на "традиционный" Паскаль, безо всех этих новомодностей с генериками, .map, .filter и прочим.
Станет ли он дружелюбнее к рефакторингу и/или записи "похожих алгоритмов"?

S>5. перегружает компилятор.

Это я оставлю на совести авторов компилятора. Тот же шарп или тайпскрипт компилируют код в функциональном стиле со скоростью мысли — то есть ничуть не медленнее Delphi.

S>>На более-менее любом современном языке это будет весьма простой генератор/итератор, за которым .filter(...).map(...).reduce(...).

S>>На Delphi остаётся только пердолиться с "процедурными типами" и/или Visitor Pattern.

S>>Возможно, на современном Delphi ситуация как-то поменялась; в том, который был актуален во времена расцвета его популярности, всё это суровая правда.

Вижу, что на современном Delphi стало ещё хуже.