1. Pascal / Говнокод #4249

    +101

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    type
      // смотрите, как не надо делать и почему придумали ООП
      TProc = procedure;
      TGoProc = function: boolean;
      TSizeProc = function: integer;
      TGetConfigProc = function: string;
      TApplyConfigProc = procedure(SM: PStringMap);
    
      TDeviceProc = record
        InitControls: TProc;
        MoveControls: TProc;
        Go: TGoProc;
        MaxH, MinH: TSizeProc;
        GetConfig: TGetConfigProc;
        ApplyConfig: TApplyConfigProc;
      end;
    
    const
      DeviceProcs: array [TDevice] of TDeviceProc = (
        (InitControls: ETR.InitControls; MoveControls: ETR.MoveControls; Go: ETR.Go; MaxH: ETR.MaxH; MinH: ETR.MinH; GetConfig: ETR.GetConfig; ApplyConfig: ETR.ApplyConfig),
        (InitControls: TS_NSH.InitControls; MoveControls: TS_NSH.MoveControls; Go: TS_NSH.Go; MaxH: TS_NSH.MaxH; MinH: TS_NSH.MinH; GetConfig: TS_NSH.GetConfig; ApplyConfig: TS_NSH.ApplyConfig),
        (InitControls: TS_IND.InitControls; MoveControls: TS_IND.MoveControls; Go: TS_IND.Go; MaxH: TS_IND.MaxH; MinH: TS_IND.MinH; GetConfig: TS_IND.GetConfig; ApplyConfig: TS_IND.ApplyConfig),
        (InitControls: TP_NSH.InitControls; MoveControls: TP_NSH.MoveControls; Go: TP_NSH.Go; MaxH: TP_NSH.MaxH; MinH: TP_NSH.MinH; GetConfig: TP_NSH.GetConfig; ApplyConfig: TP_NSH.ApplyConfig),
        (InitControls: TP_IND.InitControls; MoveControls: TP_IND.MoveControls; Go: TP_IND.Go; MaxH: TP_IND.MaxH; MinH: TP_IND.MinH; GetConfig: TP_IND.GetConfig; ApplyConfig: TP_IND.ApplyConfig)
      );

    Вот до чего доводит ненависть к ООП.
    ОПП - это хорошо, ООП не надо ненавидеть.

    Запостил: TarasB, 14 Сентября 2010

    Комментарии (26) RSS

    • ООП - не панацея. Хотя в 99% он полезен, а в 90% просто необходим.
      Просто необходимо забывать, что есть тот 1%, где без него можно прекрасно обойтись

      нет, этот код не попадает в тот 1%
      Ответить
    • мну снедает любопытство на предмет объявления перечисляемых типов TTPKind и ТДевице...
      Ответить
    • а насчет структур с процедурными указателями - не вижу причин всё бросать и переделывать на классы, есть зиллионы случаев когда такой подход оправдан
      Ответить
      • Просто я так проблевался, зайдя отладчиком в дельфийский код вызова виртуального метода, что решил, что лучше уж ТВМ задавать руками, как тут. Но вышло всё равно ржачно.
        Ответить
        • и чем же плох код вызова виртуального метода?
          по понятности и привычности - Ваш код заметно уступает виртуальным методам.
          по производительности:
          2 лишних (по сравнению с обычным вызовом обычной процедуры) обращения к памяти (1 mov и 1 в call) против 1 лишнего (1 call) - оно того действительно стоит?
          Если уж так важна производительность...
          вызов функции сам по себе содержит много обращений к памяти - стек, переменные... тогда уж лучше те функции написать на асме - больше выиграете. И неочевидной будет не логика всей программы, а отдельных функций опять же выиграш...
          Ответить
          • Сразу видно, что ты не видел, как это делает дельфи.
            Хорошо, покажу кое-что, слабонервным не смотреть.
            procedure       GetDynaMethod;
            {       function        GetDynaMethod(vmt: TClass; selector: Smallint) : Pointer;       }
            asm
                    { ->    EAX     vmt of class            }
                    {       SI      dynamic method index    }
                    { <-    ESI pointer to routine  }
                    {       ZF = 0 if found         }
                    {       trashes: EAX, ECX               }
            
                    PUSH    EDI
                    XCHG    EAX,ESI
                    JMP     @@haveVMT
            @@outerLoop:
                    MOV     ESI,[ESI]
            @@haveVMT:
                    MOV     EDI,[ESI].vmtDynamicTable
                    TEST    EDI,EDI
                    JE      @@parent
                    MOVZX   ECX,word ptr [EDI]
                    PUSH    ECX
                    ADD     EDI,2
                    REPNE   SCASW
                    JE      @@found
                    POP     ECX
            @@parent:
                    MOV     ESI,[ESI].vmtParent
                    TEST    ESI,ESI
                    JNE     @@outerLoop
                    JMP     @@exit
            
            @@found:
                    POP     EAX
                    ADD     EAX,EAX
                    SUB     EAX,ECX         { this will always clear the Z-flag ! }
                    MOV     ESI,[EDI+EAX*2-4]
            
            @@exit:
                    POP     EDI
            end;
            Ответить
            • Тебе нравится строчка REPNE SCASW, или, по простому, перебор?
              Ответить
            • эту гадость я видел. Это вызов Dynamic-методов. К виртуальным методам это не имеет отношение:
              type test1 = class(TObject)
              procedure foo(); virtual;
              end;
              type test2 = class(test1)
              procedure foo(); override;
              end;

              var t: test1;
              ...
              t := test2.Create();
              t.foo(); // вот это развернется в:

              mov eax, [<адрес t>] // указатель на экземпляр класса
              mov edx, [eax] // получение дексриптора класса
              call [edx + <константа, определяемая компилятором>]

              если убрать virtual/override то будет:
              mov eax, [<адрес t>] // указатель на экземпляр класса
              call [<адрес процедуры>]

              вот dynamic использовать не нужно.
              Ответить
              • > вот dynamic использовать не нужно

                Весь VCL на них сделан, увы.
                Ответить
                • Мда. Надо почаще смотреть исходники... Не весь VCL, конечно, но частенько используется.
                  Ответить
                • TObject сделан через virtual - и ладно.
                  В интерфейсных компонентах не имеет большого значения. А там где нужна скорость - ну есть много решений - если уж ничего не нравится - ручками сделайте... изобретательство велосипедов конечно, но куда ж деваться :(

                  Вообще, изначально вопрос стоял про приведенный здесь код.
                  работать он будет. будет быстро, если руки не кривые.
                  В производительности разница будет не заметена по сравнению с virtual/override, но последнее привычнее - существенно, когда будете код передавать кому-то.
                  Что стоит использовать - решать автору.
                  Ответить
            • OH
              MY
              GOD
              !!!
              еще один камень в стан Ботланда
              Ответить
              • Так ли часто используются динамические методы? Ни разу не приходилось.
                Ответить
              • ну почему камень - есть же нормальный механизм.

                Virtual and dynamic methods are semantically equivalent. They differ only in the implementation of method-call dispatching at runtime. Virtual methods optimize for speed, while dynamic methods optimize for code size.
                (с) Delphi help, поиск в указателе Dynamic methods, последний абзац...
                Ответить
            • если что, в современных RTL этот код перемещен в GetDynaMethod
              Ответить
      • хороший процедурный код близок к объектно-ориентированному)
        Ответить
        • и то и другое близко к хорошей архитектуре приложения
          Ответить
    • На паскале программируют железки?
      Ответить

    Добавить комментарий