OOP에 대한 흥미로운 해석 - 페이지 11

 
Georgiy Merts :

"Apotheosis" 나는 fxsaber의 한 표현을 고려하는데, 그 자신이 어떻게 작동하는지 말할 수 없었고 단순히 "코드가 반복적으로 테스트되었고 작동합니다."라고 말했습니다. 제 생각에는 다음과 같이 되어서는 안 됩니다.

이 코드는 otfFilingType 순서 를 채울 수 있는지 확인하고 strSymbol 기호에서 사용할 수 있으면 반환하고 그렇지 않으면 올바른지 확인합니다.


나는 그것이 어떻게 작동하는지 잘 이해할 수 없습니다. 그리고 저는 fxsaber의 권위에만 의존합니다.

누군가 설명해줄까요?

이해하려면 반환에서 구성 요소로 이 성가신 표현을 구문 분석하는 것으로 충분합니다.

 
Igor Makanu :

"목적이 수단을 정당화합니다"의 예

그건 그렇고, 이 코드는 그냥 스파게티처럼 보이지만 이것이 아마도 지금 코드 기반에서 가장 유용한 작성자이고 나 자신이 그의 코드를 있는 그대로 사용한다는 사실을 감안할 때 다른 사람이 비판하게 하십시오.

 
Andrei Trukhanovich :

그건 그렇고, 이 코드는 그냥 스파게티처럼 보이지만 이것이 아마도 지금 코드 기반에서 가장 유용한 작성자이고 나 자신이 그의 코드를 있는 그대로 사용한다는 사실을 감안할 때 다른 사람이 비판하게 하십시오.

나는 비판에 대해 말하는 것이 아니라 그것이 줄 수 있는 것을 알아내려고 노력하고 있습니다. 하지만 대화에서 알 수 있듯이 @fxsaber 자신도 솔직히 인정했습니다.


추신: 작은 괴물 의 원래 버전이 더 시각적으로 보였을 가능성이 큽니다.)

 
Igor Makanu :

추신: 작은 괴물 의 원래 버전이 더 시각적으로 보였을 가능성이 큽니다.)

ZIP 에서 가져옴(최초 릴리스 포함).

   static bool VirtualOrderSelect( const TICKET_TYPE Index, const int Select, const int Pool = MODE_TRADES )
  {
     return (VIRTUAL::SelectOrders ? VIRTUAL::SelectOrders. OrderSelect (Index, Select, Pool) :
           #ifdef __MQL5__
             #ifdef __MT4ORDERS__
               :: OrderSelect (Index, Select, Pool)
             #else // __MT4ORDERS__
               false
             #endif // __MT4ORDERS__
           #else // __MQL5__
             :: OrderSelect (Index, Select, Pool)
           #endif // __MQL5__
           );
  }

그러나 그 후, 점점 더 많은 기능이 필요했고 코드는 천천히 고기로 무성해졌습니다. 채우기 기능에서는 달랐습니다. 거기에는 아무것도 자라지 않았고 바로 기록되었습니다.

 
Vasiliy Sokolov :

컴파일러가 정확히 어떻게 할 것인지는 그 자신만이 알고 있습니다. 최신 컴파일러에는 놀라운 휴리스틱이 내장되어 있습니다. 그들은 평균적인 코더에 적응하고 그가 필요로 하는 것을 이미 더 잘 알고 있습니다. 컴파일러가 할 수 있는 최선의 방법은 짧은 함수 로 간단하고 명확한 코드를 작성하는 것입니다. 컴파일러가 많은 노드 함수로 구성된 소스 코드 그래프를 분석하여 최종 프로그램을 빌드하는 것이 훨씬 쉽고 효율적입니다. 필요한 기능이 올바른 위치에 인라인되기 때문에 이는 성능에 긍정적인 영향을 미칠 뿐입니다.

확실히 맞아.

MQL5에 대해 이야기하면 10-20-30년 전의 "최적화" 방법을 잊을 수 있습니다. 가능한 한 읽기 쉬운 코드를 작성해야 합니다. 품질의 척도는 해커의 종소리와 휘파람과 순수한 과시가 아니라 바로 그 사람입니다.

왜요?

예, 컴파일러는 5-10주기의 코드 재정렬을 거치기 때문에 수십 가지 최적화 패턴의 사용은 말할 것도 없고 놀랍도록 명확하고 간략하게 그래프의 끝 부분을 표시합니다.

MQL5 컴파일러는 종소리와 휘파람으로 +2% 속도를 만들려는 인간의 시도에서 재미있다는 것을 알게 되었습니다.


관심 있는 사람들을 위해 4개의 어셈블러 명령어 수학적 계산 은 분기 없이 진행되며 하나의 명령(128비트 데이터)에 대해 두 개의 근이 한 번에 계산됩니다.

이 코드는 다음 어셈블러 SSE 코드로 바뀝니다.

         D1= sqrt ((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y));
         D2= sqrt ((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y));
         D3= sqrt ((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y));
         D4= sqrt ((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y));
         D5= sqrt ((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y));
         D6= sqrt ((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y));
         D7= sqrt ((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y));
         D8= sqrt ((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y));
        ...
         sqrtsd   xmm1, xmm1
        unpcklpd        xmm4, xmm4
        movapd  xmm3, xmmword ptr [rsp + 432 ]
        unpcklpd        xmm3, xmmword ptr [rsp + 384 ]
        subpd   xmm3, xmm4
        mulpd   xmm3, xmm3
        unpcklpd        xmm0, xmm0
        movapd  xmm5, xmmword ptr [rsp + 416 ]
        unpcklpd        xmm5, xmmword ptr [rsp + 400 ]
        subpd   xmm5, xmm0
        mulpd   xmm5, xmm5
        addpd   xmm5, xmm3
        sqrtpd   xmm8, xmm5
        movapd  xmm5, xmmword ptr [rsp + 464 ]
        subpd   xmm5, xmm4
        mulpd   xmm5, xmm5
        movapd  xmm7, xmm9
        subpd   xmm7, xmm0
        mulpd   xmm7, xmm7
        addpd   xmm7, xmm5
        movapd  xmm6, xmm10
        unpcklpd        xmm6, xmm11
        subpd   xmm6, xmm4
        movapd  xmm3, xmmword ptr [rsp + 368 ]
        unpcklpd        xmm3, xmmword ptr [rsp + 352 ]
        subpd   xmm3, xmm0
        movapd  xmm4, xmm8
        shufpd  xmm4, xmm4, 1
        sqrtpd   xmm5, xmm7
        mulpd   xmm6, xmm6
        mulpd   xmm3, xmm3
        addpd   xmm3, xmm6
        sqrtpd  xmm15, xmm3
        movapd  xmm0, xmm14
        unpcklpd        xmm0, xmmword ptr [rsp + 336 ]
        subpd   xmm0, xmm2
        mulpd   xmm0, xmm0
        movapd  xmm2, xmm0
        shufpd  xmm2, xmm2, 1
        addsd   xmm2, xmm0
        movapd  xmm0, xmm15
        shufpd  xmm0, xmm0, 1
         sqrtsd   xmm12, xmm2
이것은 결국 예술 작품입니다. 어셈블러 명령어의 4번 호출에 대해 8개의 루트가 계산됩니다. 한 번의 호출로 두 개의 이중 숫자가 계산되었습니다.

  • 배열을 통한 작업 중에 이중 -> 정수 인덱스 변환에 대한 검사, 분기 및 손실과 함께 모든 것이 정상적으로 진행됩니다.

  • 이 예에서 어레이로 작업할 때 FPU/ALU가 지속적으로 혼합되어 성능에 매우 나쁜 영향을 미칩니다.

  • 동적 어레이에 대한 액세스 최적화는 칭찬을 넘어 탁월합니다. 그러나 FPU/ALU 연산을 혼합 + 이중 변환 -> 정수 + 분기는 시간을 낭비합니다.

  • 일반적인 결론: MQL5의 수학은 완벽한 최적화 덕분에 승리했습니다. 지는 것은 배열이 아니라 수학이 이깁니다.


     
    Georgiy Merts :

    왜 그런 겁니까 ?

    반대의 경우 두 개의 "if"가 있습니다. "or" 연산자보다 훨씬 쉽습니다.

    분명히 하나의 조건을 먼저 추적하고 실행의 경우 함수를 종료한 다음 다른 조건을 확인하고 실행의 경우 떠나는 것이 더 쉽습니다. 논리적 "또는"("and"와 쉽게 혼동될 수 있음)을 통해 복잡한 조건의 결과로 어떤 일이 발생하는지 파악하고 두 반환 옵션을 모두 추적하는 것보다.

    아래에서 "디버깅에 대한 정당화"를 읽는 것이 매우 재미있습니다. 왜냐하면 이것은 그러한 코드가 훨씬 더 이해하기 쉽다는 것을 의미하기 때문입니다(그렇지 않으면 디버깅에 있는 이유는 무엇입니까?).

    "Apotheosis" 나는 fxsaber의 한 표현을 고려하는데, 그 자신이 어떻게 작동하는지 말할 수 없었고 단순히 "코드가 반복적으로 테스트되었고 작동합니다."라고 말했습니다. 제 생각에는 다음과 같이 되어서는 안 됩니다.

    이 코드는 otfFilingType 순서 를 채울 수 있는지 확인하고 strSymbol 기호에서 사용할 수 있으면 반환하고 그렇지 않으면 올바른지 확인합니다.


    나는 그것이 어떻게 작동하는지 잘 이해할 수 없습니다. 그리고 저는 fxsaber의 권위에만 의존합니다.

    누군가 설명해줄까요?

    한 번 앉아서 단계적으로 분해했는데 종이가있는 펜이 필요했던 것 같습니다)

    이 분석이 유용한 이유 - 열거형의 구조가 변경되면 모든 것이 깨질 것이라는 것을 깨달았습니다. 열거 값의 정수 비율이 사용됩니다(열거 개념에 따라 캡슐화되어야 함). 나는 이것을 스스로 피하려고 노력합니다. 최대 관계는 다소간입니다. WinAPI를 다루는 사람들에게는 아마도 익숙할 것입니다.

     
    Andrey Khatimlianskii :

    이해하려면 반환에서 구성 요소로 이 성가신 표현을 구문 분석하는 것으로 충분합니다.

    네, 제가 시도한 것입니다. 하지만 분해할 동기가 충분하지 않았습니다...

     
    Renat Fatkhullin :

    확실히 맞아.

    MQL5에 대해 이야기하면 10-20-30년 전의 "최적화" 방법을 잊을 수 있습니다. 가능한 한 읽기 쉬운 코드를 작성해야 합니다. 품질의 척도는 해커의 종소리와 휘파람과 순수한 과시가 아니라 바로 그 사람입니다.

    정확히. 나는 오래전에 이런 결론에 도달했다. 그러나 컴파일러가 더 잘할 것이라고 생각하기 때문이 아닙니다. 그리고 코드에서 문제의 주요 원인은 사람 자신이기 때문에 가능한 한 코드를 작성해야 코드가 최대한 단순하고 투명해집니다.

    "투명하게" 수행할 수 없는 경우에는 자세한 설명이 필요하며, 그렇지 않은 경우에는 해당되지 않습니다.

    글쎄요, 컴파일러는... 충분히 효율적이지 못하더라도 프로그램 작업의 일부 측면을 고려하지 않는다는 사실 때문에 잠재적인 버그보다 문제가 덜합니다.

     
    fxsaber :

    코드는 매우 간단하고 짧습니다( description ). FP에 쓰면 비교해보는 재미가 쏠쏠하다.

    물론이죠. FP 스타일의 C#:


    using System;
    using System.Linq;
    using System.Collections.Generic;
    using static FeesCalculator.FeesCalcs;
    using System.Text;
    using static System.Math;
    
    namespace FeesCalculator
    {
         public static class EnumerableExt
        {
             /// <summary>
             /// Call of function 'action' for each element if sequence (mapping).
             /// </summary>
             /// <typeparam name="T"></typeparam>
             /// <param name="seq">Enumerable sequence</param>
             /// <param name="action">Need action</param>
             public static void Map<T>( this IEnumerable<T> seq, Action<T> action)
            {
                foreach (var item in seq)
                    action(item);
            }
        }
         /// <summary>
         /// Инвестиционный результат
         /// </summary>
         public record AccountRecord
        {
             public double Investor { get; init; }
             public double Manager { get; init; }
             public double Summary { get; init; }
    
             public static AccountRecord operator *(AccountRecord r, double v)
            {
                 return new AccountRecord
                {
                    Investor = r.Investor * v,
                    Manager = r.Manager * v,
                    Summary = r.Summary * v
                };
            }
             public override string ToString()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(nameof(Investor)).Append( " = " ).Append(Investor.ToString( "F4" )).Append( ' ' );
                sb.Append(nameof(Manager)).Append( " = " ).Append(Manager.ToString( "F4" )).Append( ' ' );
                sb.Append(nameof(Summary)).Append( " = " ).Append(Summary.ToString( "F4" ));
                 return sb.ToString();
            }
        }
         /// <summary>
         /// Параметры оферты
         /// </summary>
         public record PammSet
        {
             /// <summary>
             /// Доходность за расчетный период
             /// </summary>
             public double Perfomance { get; init; }
             /// <summary>
             /// Вознаграждение управляющего
             /// </summary>
             public double Gift { get; init; }
             /// <summary>
             /// Количество расчетных периодов
             /// </summary>
             public int N { get; init; }
             /// <inheritdoc/>
             public override string ToString()
            {
                StringBuilder str = new StringBuilder();
                str.Append( "Доходность за расчетный период: " ).Append((Perfomance * 100.0 ).ToString( "F1" )).Append( "%\t\n" );
                str.Append( "Вознаграждение управляющего: " ).Append((Gift * 100.0 ).ToString( "F1" )).Append( "%\t\n" );
                str.Append( "Количество расчетных периодов: " ).Append(N);
                 return str.ToString();
            }
    
        }
         /// <summary>
         /// Формулы расчета
         /// </summary>
         public class FeesCalcs
        {
             /// <summary>
             /// Если управляющий снимает деньги в конце каждого расчетного периода
             /// </summary>
             /// <param name="Performance"></param>
             /// <param name="Gift"></param>
             /// <param name="N"></param>
             /// <returns></returns>
             public static AccountRecord Set1(PammSet set)
            {
                Func< double > investor = () => Pow( 1 + (set.Perfomance) * ( 1 - set.Gift), set.N);
                Func< double > manager = () => (investor() - 1 ) * set.Gift / ( 1 - set.Gift);
                AccountRecord ac = new AccountRecord
                {
                    Investor = investor(),
                    Manager = manager(),
                    Summary = investor() + manager()
                };
                 return ac;
            }
             /// <summary>
             /// Если ничего не делалось в расчетные периоды
             /// </summary>
             /// <param name="Performance"></param>
             /// <param name="Gift"></param>
             /// <param name="N"></param>
             /// <returns></returns>
             public static AccountRecord Set2(PammSet set)
            {
                Func< double > summary = () => Pow(set.Perfomance + 1 , set.N);
                Func< double > manager = () => (summary() - 1 ) * set.Gift;
                 double s = summary();
                 double d = manager();
                AccountRecord ac = new AccountRecord
                {
                    Summary = summary(),
                    Manager = manager(),
                    Investor = summary() - manager()
                };
                 return ac;
            }
             /// <summary>
             /// Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их
             /// </summary>
             /// <param name="Performance"></param>
             /// <param name="Gift"></param>
             /// <param name="N"></param>
             /// <returns></returns>
             public static AccountRecord Set3(PammSet set)
            {
                Func< double > summary = () => Pow(set.Perfomance + 1 , set.N);
                Func< double > investor = () => Pow( 1 + (set.Perfomance) * ( 1 - set.Gift), set.N);
                 return new AccountRecord
                {
                    Summary = summary(),
                    Investor = investor(),
                    Manager = summary() - investor()
                };
            }
             /// <summary>
             /// Сопостовление: описание - функция расчета
             /// </summary>
             public static readonly Dictionary< string , Func<PammSet, AccountRecord>> DescrToAccountRecord = new Dictionary< string , Func<PammSet, AccountRecord>>
            {
                { "Если управляющий снимает деньги в конце каждого расчетного периода (1)" , Set1 },
                { "Если ничего не делалось в расчетные периоды (2)" , Set2 },
                { "Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их (3)" , Set3 },
            };
        }
         class Program
        {
             static void Main( string [] args)
            {
                var _ = args.Select((a) => double .Parse(a)).Take( 3 ).ToList();
                PammSet pamm = new PammSet
                {
                    Perfomance = _[ 0 ]/ 100.0 ,
                    Gift = _[ 1 ]/ 100.0 ,
                    N = ( int )_[ 2 ]
                };
                Console.WriteLine($ "Данные для инвестиционного счета со следующими характеристиками:\n\n{pamm}\n" );
                Console.WriteLine( "Конечный результат для Инвестора, Управляющего и Суммарно:\n" );
                Func<KeyValuePair< string , Func<PammSet, AccountRecord>>, string > f = (kvp) => kvp.Key + ".\n" + kvp.Value(pamm).ToString() + "\n" ;
                Enumerable.Select(DescrToAccountRecord, f).Map((s) => Console.WriteLine(s));
                Console.WriteLine(pamm);
                Func< int , PammSet> toPamm = (n) => new PammSet { Perfomance = pamm.Perfomance, Gift = pamm.Gift, N = n };
                Func<PammSet, IEnumerable<AccountRecord>> toAccs = (n) => DescrToAccountRecord.Select((s) => s.Value(n));
                var accounts = Enumerable.Repeat( 1 , pamm.N).Select((a, b) => a + b).Select(toPamm).Select(toAccs);
                Func<AccountRecord, string > toString = (ar) => ar.Investor.ToString( "F2" ) + "\t" +
                                                               ar.Manager.ToString( "F2" ) + "\t" +
                                                               ar.Summary.ToString( "F2" ) + "\t" ;
                 int period = default ;
                accounts.Map
                (
                    (en) => 
                    {
                        Console.Write($ "{++period}:\t" );
                        en.Map((ar) =>
                            Console.Write(toString(ar)));
                        Console.WriteLine();
                    }
                );
            }
        }
    }
    

    FP는 물론 매우 비뚤어져 있습니다.(FP 코더가 비뚤어진 코더를 열등한 FP 언어 C #으로 작성했기 때문에) 그러나 목표는 현대 OOP YaP에서 FP에서 가능하다는 것을 보여주는 것입니다. 물론 제한적이지만 F #이나 Haskell은 아니지만 FP 스타일로 쓰는 것을 금지하는 사람은 없습니다. 불변성, 고차 함수, 클로저, 매핑 등을 사용하십시오. - 모든 것이 가능합니다. 이 코드 만이 어떤 이유로 이상적이지 않습니다.

    추신 코드의 일반적인 구조는 의도적으로 원본을 모방합니다. FP에서 좋은 방법은 완전히 다른 방식으로 필요하지만 복잡한 개체와 foreach가 지도를 모방하지 않고 아티스트는 최선을 다해 그렸습니다.

     
    Vasiliy Sokolov :

    물론이죠. FP 스타일의 C#:

    문법에 대한 습관과 지식의 문제라는 것은 이해하지만, 제가 원저작자인데도 코드를 입력하는 것이 매우 어렵습니다.

    거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼

    OOP에 대한 흥미로운 해석

    fxsaber , 2021.01.29 13:39

    깔개.

     #property strict
    #property script_show_inputs
    
    input double inPerformance = 100 ; // Сколько процентов дает система за период
    input double inGift = 50 ;         // Награда управляющего в процентах (< 100)
    input int inN = 12 ;               // Сколько расчетных периодов
    
    struct BASE
    {
       double Investor;
       double Manager;
       double Summary;
    
       // Если управляющий снимает деньги в конце каждого расчетного периода.
       void Set1( const double Performance, const double Gift, const int N )
      {
         this .Investor = :: MathPow ( 1 + (Performance - 1 )* ( 1 - Gift), N);
         this .Manager = ( this .Investor - 1 ) * Gift / ( 1 - Gift);
         this .Summary = this .Investor + this .Manager;
    
         return ;
      }
    
       // Если ничего не делалось в расчетные периоды.
       void Set2( const double Performance, const double Gift, const int N )
      {
         this .Summary = :: MathPow (Performance, N);
         this .Manager = ( this .Summary - 1 ) * Gift;
         this .Investor = this .Summary - this .Manager;
    
         return ;
      }
    
       // Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их.
       void Set3( const double Performance, const double Gift, const int N )
      {
         this .Summary = :: MathPow (Performance, N);
         this .Investor = :: MathPow ( 1 + (Performance - 1 )* ( 1 - Gift), N);
         this .Manager = this .Summary - this .Investor;
    
         return ;
      }
    
       void operator *=( const double Deposit = 1 )
      {
         this .Investor *= Deposit;
         this .Manager *= Deposit;
         this .Summary *= Deposit;
    
         return ;
      }
    #define TOSTRING(A) #A + " = " + :: DoubleToString (A, 4 ) + " "
       string ToString( const bool FlagName = true ) const
      {
         return (FlagName ? TOSTRING(Investor) + TOSTRING(Manager) + TOSTRING(Summary)
                        : :: StringFormat ( "||%-12.4f||%-12.4f||%-12.4f||" , this .Investor, this .Manager, this .Summary));
      }
    #undef TOSTRING
    
    };
    
    struct PAMM
    {
       double Performance; // Доходность за расчетный период
       double Gift;         // Вознагражение управляющего.
       int N;               // Сколько расчетных периодов.
    
      BASE Base1; // Если управляющий снимает деньги в конце каждого расчетного периода.
      BASE Base2; // Если ничего не делалось в расчетные периоды.
      BASE Base3; // Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их.
    
       void Set( const double dPerformance, const double dGift, const int iN )
      {
         this .Performance = dPerformance;
         this .Gift = dGift;
         this .N = iN;
    
         this .Base1.Set1( 1 + this .Performance / 100 , this .Gift / 100 , this .N);
         this .Base2.Set2( 1 + this .Performance / 100 , this .Gift / 100 , this .N);
         this .Base3.Set3( 1 + this .Performance / 100 , this .Gift / 100 , this .N);
      }
    
       void operator *=( const double Deposit = 1 )
      {
         this .Base1 *= Deposit;
         this .Base2 *= Deposit;
         this .Base3 *= Deposit;
    
         return ;
      }
    
       string GetDescription( void ) const
      {
         return ( "Доходность за расчетный период " + :: DoubleToString ( this .Performance, 1 ) + "%\n" +
               "Вознагражение управляющего " + :: DoubleToString ( this .Gift, 1 ) + "%\n" +
               "Количество расчетных периодов. " + ( string ) this .N);
      }
    
       string ToString( const bool FlagName = true , const bool FlagDescription = true ) const
      {
         return (FlagDescription ? "Данные для инвестиционного счета со следующими характеристиками:\n\n" + this .GetDescription() +
                                 "\n\nКонечный результат для Инвестора, Управляющего и Суммарно:"
                                 "\n\nЕсли управляющий снимает деньги в конце каждого расчетного периода (1).\n" + this .Base1.ToString(FlagName) +
                                 "\n\nЕсли ничего не делалось в расчетные периоды (2).\n" + this .Base2.ToString(FlagName) +
                                 "\n\nЕсли управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их (3).\n" + this .Base3.ToString(FlagName)
                               : this .Base1.ToString(FlagName) + this .Base2.ToString(FlagName) + this .Base3.ToString(FlagName));
      }
    };
    
    void OnStart ()
    {
      PAMM Pamm;
    
      Pamm.Set(inPerformance, inGift, inN);
    
       Print (Pamm.ToString());
    
       string Str = Pamm.GetDescription() + "\n   " ;
    
       for ( int i = 1 ; i <= 3 ; i++ )
        Str += :: StringFormat ( "||%-12s||%-12s||%-12s||" , "Investor" + ( string )i, "Manager" + ( string )i, "Summary" + ( string )i);
    
       for ( int i = 1 ; i <= inN; i++ )
      {
        Pamm.Set(inPerformance, inGift, i);
    
        Str += StringFormat ( "\n%-2d:" , i) + Pamm.ToString( false , false );
      }
    
       Print (Str);
    }

    공식적으로 이것은 OOP입니다. 그러나 가장 원시적인 부분입니다. 그러나 그는 그녀 없이는 살 수 없었습니다. 아마도 어리석게도 뇌가 다른 것으로 바뀌었고 나는 이것을 리벳으로 고정합니다.