ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Modern Delphi 문법 정리.
    프로그래밍/Delphi 2017. 7. 19. 06:23

    커뮤니티에서 이야기를 나누다 RAD에 대한 말이 나와 갑자기 쓰게 되었다.




    많은 델파이 유저들이 7버전에 멈춰있다는 이야기를 들었다.

    그런데 최신 버전으로 올라오면서 생각보다 많은 변화가 생겼고, 코딩에 사용하게 되면 상당히 유용한 것들이 많다.(Modern C++은 C++11/14/17이 나오며 미친듯이 확장되어 가는중..)


    새로 만들어진 컴포넌트들 또한 새로 추가된 문법들을 이용해 작성되고 있다고들 하며, 델파이를 잘 사용하기 위해서는 컴포넌트 소스들을 볼 줄 알아야 하기 때문에 추가된 문법들을 공부하는 것은 의미가 있다고 봅니다.


    여기서는 Borland Delphi 2006 ~ Embarcadero Delphi 10.2 Tokyo 버전까지 추가된 문법들을 Modern Delphi라 칭하고, 정리해보았습니다.(IDE의 기능 변화는 다루지 않습니다.)


    지금은 귀찮아서 Ctrl+C, Ctrl+P 해놨습니다.

    일단 데브기어의 자료를 바탕으로 되어있지만, 정확한 내용을 보려면 참고에 있는 엠바카데로 위키에 들어가는 것을 추천합니다.

    Borland Delphi 2006~

    - Record(구조체)에 다양한 타입 포함 가능.

     record 선언에서 클래스처럼 필드 외에도 속성, 메소드(생성자도 포함됨), 클래스 속성, 클래스 메소드, 클래스 필드, 네스티드 타입을 가질 수 있게 되었습니다.


    정의

    type
    TMyRecord = record
    type
    TInnerColorType = Integer;
    var
    Red: Integer;
    class var
    Blue: Integer;
    procedure printRed();
    constructor Create(val: Integer);
    property RedProperty: TInnerColorType read Red write Red;
    class property BlueProp: TInnerColorType read Blue write Blue;
    end;


    구현

    constructor TMyRecord.Create(val: Integer);
    begin
    Red := val;
    end;

    procedure TMyRecord.printRed;
    begin
    writeln('Red: ', Red);
    end;


    다만 델파이에서는 C++과 달리 여전히 여러부분에서 클래스와 구조체가 구분되어 사용되고 있습니다.


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Structured_Types#Records_.28advanced.29



    - 클래스 추상화(Class Abstract).

    자바의 그것과 비슷합니다.

    type
    TAbstractClass = class abstract
    procedure SomeProcedure;
    end;


    나중에 상속받아 정의하여 사용하면 됩니다.



    - 클래스 봉인(Class Sealed).

    Java, C++의 final 키워드와 비슷하게 상속을 막습니다.

    C#에서도 sealed가 있었죠.

    type
    TAbstractClass = class sealed
    procedure SomeProcedure;
    end;


    abstract와 sealed를 같이 사용할 수는 없다고 합니다.



    - 클래스 상수(Class Const).

     클래스는 클래스 상수를 가질 수 있습니다. 클래스 상수는 객체가 아닌 클래스와 연관된 상수입니다.

    type
    TClassWithConstant = class
    public
    const SomeConst = '이것은 클래스 상수입니다.';
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    ShowMessage(TClassWithConstant.SomeConst);
    end;



    - 클래스 타입(Class Type) & 클래스 변수(Class Var).

     클래스는 해당 클래스에서만 사용 가능한 타입 선언을 포함할 수 있습니다. (Class type)

     클래스는 클래스 변수를 가질 수 있습니다. 이것은 클래스의 객체가 아닌 클래스 자체에 적용되는 변수입니다.(Class var)

    type
    TClassWithClassType = class
    private
    type //- class type
    TRecordWithinAClass = record
    SomeField: string;
    end;
    public
    class var //- class var
    RecordWithinAClass: TRecordWithinAClass;
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    TClassWithClassType.RecordWithinAClass.SomeField := '이것은 클래스 타입으로 선언된 필드입니다.';
    ShowMessage(TClassWithClassType.RecordWithinAClass.SomeField);
    end;


    + 클래스 부분들 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Classes_and_Objects



    - 중첩된 클래스(Nested Class).

     클래스 선언 내에서 타입 선언이 포함될 수 있습니다. 이 방법으로 개념적으로 관계가 있는 타입들을 같이 둘 수 있으며, 이름 충돌도 피할 수 있습니다.

    type
    TOuterClass = class
    strict private
    MyField: Integer;
    public
    type
    TInnerClass = class
    public
    MyInnerField: Integer;
    procedure InnerProc;
    end;
    procedure OuterProc;
    end;

    procedure TOuterClass.TInnerClass.InnerProc;
    begin
    ...
    end;


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Nested_Type_Declarations#Declaring_and_Accessing_Nested_Classes



    - Final 지시자.

     오버라이드한 버추얼 메소드를 final로 표시하여 상속되는 클래스에서 해당 메소드를 더 이상 오버라이드하지 못하도록 막을 수 있습니다.

    TAbstractClass = class abstract
    public
    procedure Bar; virtual;
    end;

    TSealedClass = class sealed(TAbstractClass)
    public
    procedure Bar; override;
    end;

    TFinalMethodClass = class(TAbstractClass)
    public
    procedure Bar; override; final;
    end;


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Final_(Delphi)



    - 클래스 스태틱 메소드(Class Static Method).

     클래스에 스태틱 클래스 메소드를 추가할 수 있는데, 이것은 클래스 타입으로부터 호출할 수 있는 메소드입니다. 클래스 스태틱 메소드는 객체에 대한 참조 없이도 사용이 가능합니다.

     일반적인 클래스 메소드와는 달리, 클래스 스태틱 메소드는 Self 파라미터를 가지지 않습니다. 또한 객체의 멤버들을 액세스할 수도 없습니다. (클래스 필드, 클래스 속성, 클래스 메소드는 액세스할 수 있습니다) 또한 클래스 메소드와 달리 클래스 스태틱 메소드는 virtual로 선언될 수 없습니다

    type
    TMyClass = class
    strict private
    class var
    FX: Integer;
    strict protected
    // 노트: 클래스 속성을 액세스하려면 클래스 스태틱으로 선언되어야 합니다.
    class function GetX: Integer; static;
    class procedure SetX(val: Integer); static;
    public
    class property X: Integer read GetX write SetX;
    class procedure StatProc(s: String); static;
    end;

    begin TMyClass.X := 17;
    TMyClass.StatProc('Hello');

    end;



    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Fundamental_Syntactic_Elements#Directives



    - 타입 헬퍼(Type Helper)

     타입 헬퍼는 클래스, 레코드, 열거형 타입의 기능을 확장할 수 있는 문법입니다. 클래스 헬퍼는 기존의 클래스를 수정하지도 상속받지도 않고 클래스 기능을 확장할 수 있습니다.

     다음코드는 열거형에 타입헬퍼를 이용해 ToString 메소드를 확장하는 예제입니다.

    type
    TGeoDirection = (North, East, South, West);
    // 열거형을 문자열로 변환하는 기능 확장
    TGeoDirectionHelper = record helper for TGeoDirection
    function ToString: string; inline;
    end;

    function TGeoDirection.ToString: string;
    begin
    case Self of
    TGeoDirection.North: Result := '북쪽 (N)';
    TGeoDirection.East: Result := '동쪽 (E)';
    TGeoDirection.South: Result := '남쪽 (S)';
    TGeoDirection.West: Result := '서쪽 (W)';
    else
    raise Exception.Create('Unknown "TGeoDirection" value');
    end;
    end;

    var
    Direction: TGeoDirection;
    begin
    Direction := South;
    ShowMessage(Direction.ToString);

    end;

    타입헬퍼를 사용하면 수정하지 못하는 클래스에 필요한 메소드를 추가하고, 소스코드에서 반복적으로 사용되는 열거형을 문자열로 변환하는 등의 기능 메소드로 등록한다면 코드가 더 간결해지고 코딩 시 변수에 “.”을 찍으면 나오는 메소드를 이용해 더 생산성 높은 개발을 할 수 있습니다.


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE7/en/Class_and_Record_Helpers_(Delphi)


    Codegear Delphi 2007~

    - For-in 반복문.

    이제 델파이에서 컨테이너에 대해 for-요소-in-컬렉션 스타일의 반복자를 지원합니다. 컴파일러는 다음의 컨테이너 반복 패턴을 인식합니다.

    for Element in ArrayExpr do Stmt;
    for Element in StringExpr do Stmt;
    for Element in SetExpr do Stmt;
    for Element in CollectionExpr do Stmt;


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Declarations_and_Statements#Iteration_Over_Containers_Using_For_statements

    CodeGear Delphi 2009~

    - 유니코드 지원.

     이제 델파이 언어 전체적으로 유니코드가 지원이 됩니다. 기존 버전들에서는 String은 AnsiString을 의미했지만 이제는 유니코드를 완벽하게 지원하는 UnicodeString으로 바뀌었습니다.

     UnicodeString은 기존의 WideString과는 달리 AnsiString과 유사한 레퍼런스 카운팅(Reference Counting) 구조로 설계되어 훨씬 메모리 효율적이며 속도도 빠릅니다. 스트링을 버퍼로 사용해왔던 관행에 대한 대안으로 RawByteString 타입도 추가되었습니다.


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Unicode_in_RAD_Studio



    - Exit 함수.

    반환값을 갖는 빠져나오는 Exit 함수.

    Exit; 문에 반환값을 넣을 수 있어 코드가 더 짧아집니다.

    function DoSomething(aInteger: integer): string;
    begin
    if aInteger < 0 then
    begin
    Exit('Negative');
    end;
    Result := 'Positive';
    end;


    + 참고.

    http://docwiki.embarcadero.com/Libraries/XE8/en/System.Exit


    - Inline 지시자.

     델파이 컴파일러는 함수와 프로시저의 성능을 향상할 수 있는 Inline 지시자를 지정할 수 있습니다. 이 지시자는 해당 루틴을 실제로 호출하는 대신 호출하는 측에서 해당 루틴을 포함하는 코드를 생성하도록 합니다.

    function Max(const X,Y,Z: Integer): Integer; inline;


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Calling_Procedures_and_Functions#Using_the_inline_Directive



    - Strict 접근 지정자.

    델파이에서 클래스의 속성에 대한 가시성을 결정하는 2가지 옵션이 있습니다.


    strict private

    private 키워드는 같은 유닛에 포함된 클래스에서는 접근을 허용합니다. strict private 선언은 같은 유닛에 포함된 클래스에서도 접근할 수 없습니다.

     

    strict protected

    strict private과 유사하며, strict protected로 선언된 변수와 메소드는 클래스 본인과 상속한 클래스에서만 접근할 수 있습니다.


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Classes_and_Objects#Strict_Visibility_Specifiers



    - 제너릭(Generics)

    C++의 template와 비슷한 기능이다.

     클래스와 메소드에서 사용하는 데이터 타입을 사전에 정하지 않고 유연하게 사용할 수 있는 문법입니다. 구현 시 데이터 타입을 지정해 사용할 수 있어 하나의 클래스(메소드)를 다양한 데이터 타입으로 사용할 수 있습니다.


    적용전

    type
    TSIPair = class
    private
    FKey: String;
    FValue: Integer;
    public
    function GetKey: String;
    procedure SetKey(Key: String);
    function GetValue: Integer;
    procedure SetValue(Value: Integer);
    property Key: TKey read GetKey write SetKey;
    property Value: TValue read GetValue write SetValue;
    end;


    적용후

    type
    TPair<TKey,TValue> = class // declares TPair type with two type parameters
    private
    FKey: TKey;
    FValue: TValue;
    public
    function GetKey: TKey;
    procedure SetKey(Key: TKey);
    function GetValue: TValue;
    procedure SetValue(Value: TValue);
    property Key: TKey read GetKey write SetKey;
    property Value: TValue read GetValue write SetValue;
    end;


    사용

    type
    TSIPair = TPair<String,Integer>; // declares instantiated type
    TSSPair = TPair<String,String>; // declares with other data types
    TISPair = TPair<Integer,String>;
    TIIPair = TPair<Integer,Integer>;
    TSXPair = TPair<String,TXMLNode>;



    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE7/en/Overview_of_Generics



    - 익명 메소드

     이름에서 알 수 있듯이 익명메소드는 이름이 없는 프로시저나 함수입니다. 익명 메소드는 변수에 할당하거나 메소드의 파라메터로 코드 블록을 전달할 수 있습니다.


    type
    TProc = reference to procedure(Value: Integer);

    procedure Call(const AProc: TProc);
    begin
    AProc(10);
    end;

    procedure DoSimpleAnonymouseMethod;
    var
    Proc: TProc;
    begin
    proc := procedure(Value: Integer)
    begin
    ShowMessage(Value.ToString);
    end;
    Call(Proc);
    end;

      익명메소드는 다른 언어의 클로저(closures)의 구조와 유사합니다. 익명메소드는 특히 쓰레드 개발 시 사용하면 유용합니다. 쓰레드 시작 코드 구현 시 쓰레드 완료 코드를 함께 구현하면 작업흐름을 한눈에 파악할 수 있어 코드의 유지보수가 편리해 집니다.


    + 참고.

    http://tech.devgear.co.kr/delphi_news/406874

    http://docwiki.embarcadero.com/RADStudio/XE7/en/Anonymous_Methods_in_Delphi

     Embarcadero Delphi 2010~

    -  DLL 지연로딩

     Delphi 2010에서는 DLL의 로딩 방법으로서 정적(static) 로딩, 동적(dynamic) 로딩 외에 지연(delayed) 로딩이 추가되었습니다. 지연 로딩은 정적 로딩과 기본적으로 같은 구문을 사용하지만 extern 선언에서 delayed 지시어를 추가하는 것입니다.

    procedure ProcInDll; external 'DLL_name.dll' delayed;

     정적 로딩 구문에 단지 delayed 지시어를 추가한 것 뿐이지만, 이것만으로도 해당 DLL 함수가 실제로 호출될 때까지 해당 DLL을 로드하지 않습니다. 이전의 정적 로딩을 사용하면 코딩이 단순하고 편리한 반면 해당 DLL이나 함수가 존재하지 않을 경우 프로그램 시작 자체가 실패하는 치명적인 문제가 있습니다. DLL이 이런 우려가 있을 경우에 지연 로딩을 사용하면 깔끔하게 문제가 해결됩니다. 특히 Windows 7이나 Windows Vista 등 최신 버전의 Win32에서 추가된 API들을 호출할 필요가 있으면서 동시에 Windows P, 2000 등 구버전과도 호환성이 필요한 경우 더욱 유용합니다. 또한 지연 로딩을 사용하면 실제 호출할 때까지 DLL을 로드하지 않으므로 메모리 소모도 줄어드는 효과도 있습니다.



    - RTTI 강화와 어트리뷰트

      델파이 2010에서 델파이의 RTTI가 대폭 강화되었습니다. 이제 RTTI가 메소드, 필드, 속성을 지원하게 되어 동적 호출과 다른 메타 프로그래밍 방식들을 지원하게 되었습니다. 새로 추가된 RTTI.pas 유닛을 통해 강력한 RTTI 루틴들을 뒷받침합니다.

     어트리뷰트(attribute)는 이 새로운 RTTI를 기반으로 한 문법으로서, 클래스/레코드나 클래스의 멤버에 추가로 지정되는 정보이며, 실행 중에 읽어질 수 있습니다. 어트리뷰트를 활용하면 일반화된 프레임워크를 개발할 때 아주 유용합니다.


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Working_with_RTTI_Index

    Embarcadero Delphi XE2~

    - 64Bit 지원

     델파이 XE2에서 64비트 윈도우 애플리케이션 개발을 지원합니다. 64비트 애플리케이션은 더 빠른 연산과 더 많은 메모리(4G 이상)를 사용해야 하는 경우 적합 합니다.

     델파이에서는 프로젝트 매니저에서 타겟 플랫폼을 64-bit Windows로 선택 후 빌드해 64비트 애플리케이션을 개발할 수 있습니다. 만약, 여러분의 프로젝트가 VCL과 RTL만 사용한 경우 Win32와 Win64 플랫폼에서 동일한 소스코드를 사용할 수 있습니다.


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/64-bit_Windows_Application_Development


    - 유닛 범위 이름(Unit Scope Names)

     유닛 이름 앞에 범위 이름을 추가할 수 있어 유닛의 역할이 더 명확해 졌습니다. VCL과 RTL 유닛이 모두 범위이름을 포함하도록 변경되었고 여러분의 유닛에도 범위이름을 포함해 저장할 수 있습니다.

     하지만 반드시 범위이름을 지정해야 하는 것은 아닙니다. 유즈절에 유닛을 추가할 때 System.SysUtils와 SysUtils는 동일한 유닛을 사용합니다.

    uses
    Winapi.Windows, Winapi.Messages, System.SysUtils,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls


    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE8/en/Unit_Scope_Names


    Embarcadero Delphi XE7~

    - 동적배열 개선(String-Like Operations Supported on Dynamic Arrays)

     동적배열이 사용하기 쉽게 개선되었습니다.

    • 동적배열 초기화가 쉬워짐
    • 문자열과 같이 + 기호로 배열을 연결
    • Insert, Delete, Concat 함수 지원
    var
    di: array of Integer;
    i: Integer;
    begin
    di := [1, 2, 3];
    di := di + di;
    di := di + [4, 5];

    di := [1, 2, 3, 4, 5, 6];
    Insert ([8, 9], di, 4);
    Delete (di, 2, 1); // remove the third (0-based)

    for i in di do
    begin
    Memo1.Lines.Add (i.ToString);
    end;



    + 참고.

    http://docwiki.embarcadero.com/RADStudio/XE7/en/What%27s_New_in_Delphi_and_C%2B%2BBuilder_XE7#String-Like_Operations_Supported_on_Dynamic_Arrays


     Embarcadero Delphi 10.2 Tokyo

    - 델파이 리눅스 컴파일러 지원

    Ubuntu Server (Ubuntu 16.04 LTS)

    RedHat Enterprise Linux (7 버전)

    대부분의 배포판에서 작동할 것으로 예상됨.


    아직은 콘솔에서만 돌아갑니다.


    + 참고.

    http://tech.devgear.co.kr/index.php?mid=delphi_news&search_keyword=10.2+%EB%8F%84%EC%BF%84&search_target=title_content&document_srl=431377


    +

    - 기본 문법 참고.

    위키북스

    https://ko.wikibooks.org/wiki/파스칼_프로그래밍


    델파이 레퍼런스

    http://docwiki.embarcadero.com/RADStudio/Seattle/en/Delphi_Language_Reference


    - 출처

    New Delphi language features since Delphi 7

    http://edn.embarcadero.com/article/34324

    RAD Studio 버전별 신기능

    http://www.devgear.co.kr/products/rad-studio/featurelist/

    http://docwiki.embarcadero.com/RADStudio/XE7/en/What%27s_New
    http://docwiki.embarcadero.com/RADStudio/Tokyo/en/What%27s_New

    ++

     Embarcadero Delphi 10 Seattle

    C++ Builder의 기본 컴파일러가 LLVM 기반으로 대체되었습니다.

    http://docwiki.embarcadero.com/RADStudio/Seattle/en/C%2B%2B_Compiler



    +++

    나중에 델파이(Delphi or Object Pascal)에 대한 글들를 쓰긴 할건데, 일단 C, C++을 올리고 나서 Scheme와 함께 올려보도록 하겠습니다.


    오늘 글은 저의 변덕...

    전 C++ 좋아합니다. ㅎㅎ


    댓글

Designed by black7375.