Sign in Join
Wiki copytemporary

Generics/ko: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11The first thing someone who knows thie stuff needs to do is explain what a *generic* is so we understand what the issue is.
22
33## FPC에서 제너릭
44
55Generic classes are already implemented in the 2.3.1 version of FPC. 제너릭 클래스들은 이미 FPC 2.3.1 버전안에 구현되어져 있습니다.
66
77See the [FPC reference](http://www.freepascal.org/docs-html/ref/ref.html). 여기를 보세요 [FPC reference](http://www.freepascal.org/docs-html/ref/ref.html).
88
99This page contains proposals and ideas, which lead to the current implementation and for further features. 이 문서는 앞으로의 모습과 성취물을 안내하는, 제안과 아이디어를 포함하고 있습니다.
1010
1111## 왜?
1212
1313- 형 안정성 !
1414- 속도
1515- 재미있게 읽을수 있음
1616
1717See "Already existing stuff" for possible but lacking ways right now. 당장 약간 모자라지만, 가능하면 "이미 존재하는 것"을 읽어보세요
1818
1919## 관심을 갖은 사람들
2020
2121\- Almindor - dannym - fpk - giantm - oliebol - plugwash - Synopsis - tom - PublicJoke - neli - dr_evil
2222
2323## 사용 례 (분류안됨)
2424
2525TODO: combine the below stuff into one example using the \<\> syntax TODO: \<\> 문법을 사용하는 예제와 아래의 것을 결합합니다
2626
2727(tom 의 제안)
2828
29-` type`\
30-` // explicit addition of "generic" keyword. Maybe something like "uses generic <...>" `\
31-` // better use the <>-brackets because otherwise it may cause confusion with arrays `\
32-` // in the actual instantiation`\
33-` // "generic"키워드를 명시합니다. 실제 인스턴스에서 배열들과 함께 혼동을 일으킬 것이므로, `\
34-` // <>괄호를 쓰는 것보다 "generic <...>" 을 쓰는 것이 나을것입니다`\
35-` abc = class(..) generic <a, b>`\
36-` end;`\
37-` var`\
38-`       //  because they're still unused ;)`\
39-`       // 왜냐면 그것들은 아직 사용되지 않았습니다 ;)`\
40-`       xyz : abc<String, Integer>;`\
41-`       xyz2 : abc<AObj1, AObj2>;`\
42-` begin`\
43-`   // don't repeat generics in instance creation (if not necessary)`\
44-`   // 인스턴스의 초기화에 제너릭을 반복하지 마십시요(필요하지 않다면)`\
45-`   xyz := abc.Create;`\
46-`   xyz2 := abc<descendant_of_Aobj1, descendant_of_Aobj2>.Create;`\
47-` end.`
29+``` pascal
30+ type
31+ // explicit addition of "generic" keyword. Maybe something like "uses generic <...>"
32+ // better use the <>-brackets because otherwise it may cause confusion with arrays
33+ // in the actual instantiation
34+ // "generic"키워드를 명시합니다. 실제 인스턴스에서 배열들과 함께 혼동을 일으킬 것이므로,
35+ // <>괄호를 쓰는 것보다 "generic <...>" 을 쓰는 것이 나을것입니다
36+ abc = class(..) generic <a, b>
37+ end;
38+ var
39+ // because they're still unused ;)
40+ // 왜냐면 그것들은 아직 사용되지 않았습니다 ;)
41+ xyz : abc<String, Integer>;
42+ xyz2 : abc<AObj1, AObj2>;
43+ begin
44+ // don't repeat generics in instance creation (if not necessary)
45+ // 인스턴스의 초기화에 제너릭을 반복하지 마십시요(필요하지 않다면)
46+ xyz := abc.Create;
47+ xyz2 := abc<descendant_of_Aobj1, descendant_of_Aobj2>.Create;
48+ end.
49+```
4850
4951(dannym 의 새로운 제안)
5052
51-` type`\
52-` GList = generic class of T`\
53-` public`\
54-`   procedure Add(const stuff: T);`\
55-` end;`
53+``` pascal
54+ type
55+ GList = generic class of T
56+ public
57+ procedure Add(const stuff: T);
58+ end;
59+```
5660
57-` procedure GList.Add(const stuff: T); // note that here no 'of T' //'of T'가 없음을 유의하세요`\
58-` begin`\
59-`   ...`\
60-` end;`
61+``` pascal
62+ procedure GList.Add(const stuff: T); // note that here no 'of T' //'of T'가 없음을 유의하세요
63+ begin
64+ ...
65+ end;
66+```
6167
62-` var`\
63-`   intlist: GList of Integer;`\
64-` begin`\
65-`   intlist := GList.Create; // note that here the detail type is missing and `\
66-`           // needs to be deducted from the var declaration`\
67-`           // 여기에 자세한 선언형이 없으며, var 선언으로 (선언형이)빠져야만 한다는 것을 알아두세요`
68+``` pascal
69+ var
70+ intlist: GList of Integer;
71+ begin
72+ intlist := GList.Create; // note that here the detail type is missing and
73+ // needs to be deducted from the var declaration
74+ // 여기에 자세한 선언형이 없으며, var 선언으로 (선언형이)빠져야만 한다는 것을 알아두세요
75+```
6876
69-`   //or intlist := typeof(intlist).Create;`\
70-`   //intlist := GList of Integer.Create; <-- this is unclear if that works <-- 이 것이 실제 구현된 것이라면, 명확하지 않습니다`\
71-` end;`
77+``` pascal
78+ //or intlist := typeof(intlist).Create;
79+ //intlist := GList of Integer.Create; <-- this is unclear if that works <-- 이 것이 실제 구현된 것이라면, 명확하지 않습니다
80+ end;
81+```
7282
7383(dannym 의 옛 제안)
7484
75-` type`\
76-` GList<T> = class`\
77-` public`\
78-`   procedure Add(const stuff: T);`\
79-` end;`
85+``` pascal
86+ type
87+ GList<T> = class
88+ public
89+ procedure Add(const stuff: T);
90+ end;
91+```
8092
81-` procedure GList<T>.Add(const stuff: T);`\
82-` begin`\
83-`   ...`\
84-` end;`
93+``` pascal
94+ procedure GList<T>.Add(const stuff: T);
95+ begin
96+ ...
97+ end;
98+```
8599
86-` var`\
87-`   intlist: GList<Integer>;`\
88-` begin`\
89-`   intlist := GList<Integer>.Create;`\
90-` end;`
100+``` pascal
101+ var
102+ intlist: GList<Integer>;
103+ begin
104+ intlist := GList<Integer>.Create;
105+ end;
106+```
91107
92108plugwash 의 것:
93109
94-` tmycollection=template(tobject)[x]`\
95-` tintegercollection=tmycollection[integer]`
110+```text
111+ tmycollection=template(tobject)[x]
112+ tintegercollection=tmycollection[integer]
113+```
96114
97115oliebol 의 것:
98116
99-` template blaat<t:integer>(a:t);`\
100-` var x : t;`\
101-` begin`\
102-`   do something with a, and use t with it`\
103-` end;`
117+``` pascal
118+ template blaat<t:integer>(a:t);
119+ var x : t;
120+ begin
121+ do something with a, and use t with it
122+ end;
123+```
104124
105125note that we should have a generics section (like interface and implementation sections) containing the generics: 우리는 (interface와 implementation 섹션들처럼) 제너릭들을 포함하는, generics 섹션을 가져야한다는것을 알립니다
106126
107-` unit xyz;`\
108-` generics`\
109-` type`\
110-`   GList......`\
111-` procedure GList.Add(const value: T);`\
112-` ....`\
113-` end.`
127+``` pascal
128+ unit xyz;
129+ generics
130+ type
131+ GList......
132+ procedure GList.Add(const value: T);
133+ ....
134+ end.
135+```
114136
115137(eiffel의 것)
116138
117139<http://paste.lisp.org/display/6236>
118140
119141(PublicJoke 의 제안)
120142
121-` unit Unit1(TMathType);`\
122-` `\
123-` interface`\
124-` `\
125-` type`\
126-`   TMathClass = class`\
127-`   public`\
128-`     class function Add(a1, a2: TMathType): TMathType;`\
129-`   end;`\
130-` `\
131-` implementation`\
132-` `\
133-` class function TMathClass.Add(a1, a2: TMathType): TMathType;`\
134-` begin`\
135-`   Result:=a1+a2;`\
136-` end;`\
137-` `\
138-` end.`
143+``` pascal
144+ unit Unit1(TMathType);
145+
146+ interface
147+
148+ type
149+ TMathClass = class
150+ public
151+ class function Add(a1, a2: TMathType): TMathType;
152+ end;
153+
154+ implementation
155+
156+ class function TMathClass.Add(a1, a2: TMathType): TMathType;
157+ begin
158+ Result:=a1+a2;
159+ end;
160+
161+ end.
162+```
139163
140-` unit Unit2;`\
141-` `\
142-` type`\
143-`   TMathType = Longword;`\
144-` `\
145-` interface`\
146-` `\
147-` implementation`\
148-` `\
149-` end.`
164+``` pascal
165+ unit Unit2;
166+
167+ type
168+ TMathType = Longword;
169+
170+ interface
171+
172+ implementation
173+
174+ end.
175+```
150176
151-` program prog;`\
152-` `\
153-` uses`\
154-`   Unit2, `\
155-`   Unit1(Byte) as ByteMath in 'Unit1.pas',`\
156-`   Unit1(TMathType) as PolyMath in 'Unit1.pas';`\
157-` `\
158-` type`\
159-`   TByteMathClass = ByteMath.TMathClass;`\
160-`   TPolyMathClass = PolyMath.TMathClass;`\
161-` `\
162-` var`\
163-`   b: Byte;`\
164-`   p: TMathType;`\
165-` `\
166-` begin`\
167-`   b:=TByteMathClass.Add(1, 2);`\
168-`   p:=TPolyMathClass.Add(3, 4);`\
169-` end.`
177+``` pascal
178+ program prog;
179+
180+ uses
181+ Unit2,
182+ Unit1(Byte) as ByteMath in 'Unit1.pas',
183+ Unit1(TMathType) as PolyMath in 'Unit1.pas';
184+
185+ type
186+ TByteMathClass = ByteMath.TMathClass;
187+ TPolyMathClass = PolyMath.TMathClass;
188+
189+ var
190+ b: Byte;
191+ p: TMathType;
192+
193+ begin
194+ b:=TByteMathClass.Add(1, 2);
195+ p:=TPolyMathClass.Add(3, 4);
196+ end.
197+```
170198
171199(Gadnio 의 제안) I personally think the C++ way of doing this is clear enough AND will be the easiest to parse/understand: 저는 개인적으로 C++의 방법이 이것을 충분히 명확하게 하고, 해석과 이해가 쉬워질꺼라고 생각합니다
172200
173-` template <T>`\
174-`   TGenericObject< T > = record`\
175-`     Data : T;`\
176-`     OtherStuff : Pointer;`\
177-`   end;{TGenericObject}`\
178-` template <TKey, TData = TGenericObject< boolean > >`\
179-`   TGenericList = class( TWhee< TKey > )`\
180-`   public`\
181-`     function Lookup( const Key : TKey ): TData;`\
182-`     template <THihi>`\
183-`       class function DataToHihi( Data : TData ): THihi;`\
184-`   end;{TGenericList}`
201+``` pascal
202+ template <T>
203+ TGenericObject< T > = record
204+ Data : T;
205+ OtherStuff : Pointer;
206+ end;{TGenericObject}
207+ template <TKey, TData = TGenericObject< boolean > >
208+ TGenericList = class( TWhee< TKey > )
209+ public
210+ function Lookup( const Key : TKey ): TData;
211+ template <THihi>
212+ class function DataToHihi( Data : TData ): THihi;
213+ end;{TGenericList}
214+```
185215
186216Also, note that template specialization is a very, very important thing (for me especially). In C++ they've got vector\< bool \> that behaves different than the standard vector\< T \>. An example: 또한, template의 특수함은 매우, 매우 중요한 것임을 알아야 합니다(특히 나에게는). C++에서는 표준 vector\< T \>와는 다른 동작을 하는 vector\< bool \>을 가지고 있습니다. 한 예로..
187217
188-` template <T, TT>`\
189-`   TSame = class`\
190-`     class function Same: Boolean;`\
191-`   end;{TSame}`\
192-` template <T>`\
193-`   TSame = class`\
194-`     class function Same: Boolean;`\
195-`   end;{TSame}`
218+``` pascal
219+ template <T, TT>
220+ TSame = class
221+ class function Same: Boolean;
222+ end;{TSame}
223+ template <T>
224+ TSame = class
225+ class function Same: Boolean;
226+ end;{TSame}
227+```
196228
197-` template <T, TT>`\
198-` class function TSame.Same: Boolean;`\
199-` begin`\
200-`   Result := false;`\
201-` end;{TSame<T, TT>.Same}`\
202-` template <T>`\
203-` class function TSame.Same: Boolean;`\
204-` begin`\
205-`   Result := true;`\
206-` end;{TSame<T>.Same}`
229+``` pascal
230+ template <T, TT>
231+ class function TSame.Same: Boolean;
232+ begin
233+ Result := false;
234+ end;{TSame<T, TT>.Same}
235+ template <T>
236+ class function TSame.Same: Boolean;
237+ begin
238+ Result := true;
239+ end;{TSame<T>.Same}
240+```
207241
208242This allows to make a compile-time check for same types that are not TObject, e.g. 이 것은 TObject가 아닌, 같은 선언형에 대해서 compile-time 검사를 할수 있게 합니다. 예로 들면..
209243
210-` TFoo = class;`\
211-` TBar = class( TFoo );`\
212-` var`\
213-`   S : Boolean;`\
214-` begin`\
215-`   S := TSame< String, Integer >.Same; //s = false`\
216-`   S := TSame< Int64, Integer >.Same; //s = false`\
217-`   S := TSame< String, String >.Same; //s = true`\
218-`   S := TSame< TBar, TFoo >.Same;//s = false (not the same as "var x: TFoo; begin x := TBar.Create; end;" )`\
219-`                                             // "var x: TFoo; begin x := TBar.Create; end;" 가 같지 않듯이)`\
220-` end;`
244+``` pascal
245+ TFoo = class;
246+ TBar = class( TFoo );
247+ var
248+ S : Boolean;
249+ begin
250+ S := TSame< String, Integer >.Same; //s = false
251+ S := TSame< Int64, Integer >.Same; //s = false
252+ S := TSame< String, String >.Same; //s = true
253+ S := TSame< TBar, TFoo >.Same;//s = false (not the same as "var x: TFoo; begin x := TBar.Create; end;" )
254+ // "var x: TFoo; begin x := TBar.Create; end;" 가 같지 않듯이)
255+ end;
256+```
221257
222258Another thing to note: It would be very good if something like this (c++ syntax) would be implemented: 다른 한가지를 적자면, 만약 이 런것이(C++ 문법) 시행되어진다면, 매우 좋아질 겁니다
223259
224-` template <bool b>`\
225-` class h`\
226-` {`\
227-`   public:`\
228-`   static const int i = 0;`\
229-` };//h`
260+``` pascal
261+ template <bool b>
262+ class h
263+ {
264+ public:
265+ static const int i = 0;
266+ };//h
267+```
230268
231-` template <>`\
232-` class h< true >`\
233-` {`\
234-`   public:`\
235-`   static const int i = 1;`\
236-` };`
269+``` pascal
270+ template <>
271+ class h< true >
272+ {
273+ public:
274+ static const int i = 1;
275+ };
276+```
237277
238-` template <>`\
239-` class h< false >`\
240-` {`\
241-`   public:`\
242-`   static const int i = 2;`\
243-` };`
278+``` pascal
279+ template <>
280+ class h< false >
281+ {
282+ public:
283+ static const int i = 2;
284+ };
285+```
244286
245287Here 여기는 항상
246288
247-` h<false>.i = 2`\
248-` h<true>.i = 1 `
289+```text
290+ h<false>.i = 2
291+ h<true>.i = 1
292+```
249293
250294ALWAYS. 이렇게 됩니다
251295
252296## 사용 례
253297
254298If you add more syntax examples, please add equivalent to both. 만약 좀더 문법예제를 추가한다면, 두가지에 상응하는 것을 추가해 주세요. Two main syntaxes seem to be popular, "\<\>" which looks more or less like C++, c#, etc.. and adding a "generic" keyword which is more along the Pascal style of code. Go to [[Generics Vote]] to vote for one or the other syntax. 두 가지 기본 문법들은 인기있어질 것으로 보이는데, 어느 정도 C++, C# 등의 것으로 보이는 "\<\>"과 코드의 방식이 좀더 Pascal스러운, 추가된 "generic" 낱말입니다.
255299
256300### 괄호 사용하기: \<\>
257301
258-` type`\
259-`   TGenericCollection<T: TCollectionItem> = class(TComponent)`\
260-`   ...implement TCollection and use T`\
261-`   end;`
302+``` pascal
303+ type
304+ TGenericCollection<T: TCollectionItem> = class(TComponent)
305+ ...implement TCollection and use T
306+ end;
307+```
262308
263-`   TCollection = TGenericCollection<TCollectionItem>;`\
264-`   TFieldDefs = TGenericCollection<TFieldDef>; `
309+```text
310+ TCollection = TGenericCollection<TCollectionItem>;
311+ TFieldDefs = TGenericCollection<TFieldDef>;
312+```
265313
266-`   TGenericList<T: PtrInt> = class(TObject)`\
267-`   ...implement TList and use PtrInt size for code generation`\
268-`   end;`
314+``` pascal
315+ TGenericList<T: PtrInt> = class(TObject)
316+ ...implement TList and use PtrInt size for code generation
317+ end;
318+```
269319
270-`   TList = TGenericList<Pointer>;`
320+```text
321+ TList = TGenericList<Pointer>;
322+```
271323
272324Implementation of TGenericCollection can be compiled as if (T: TCollectionItem) were used. TGenericCollection의 구현은 마치 (T: TCollectionItem)이 사용된 것처럼 컴파일 되어질 것입니다
273325
274326Would this solve the circular dependency ? It seems so to me, because one knows at least as much as in current implementation of these classes, but I'm no compiler engineer. 여기서 순환참조를 해결할 수 있을까요? 저는 컴파일러 엔지니어가 아니지만, 적어도 하나가 현재 이 클래스들의 구현만큼 알기 때문에 가능하다고 봅니다
275327
276328For procedures: procedure 로써:
277329
278-` function MyFunc<T: TTreeItem>(A: T): T;`\
279-` begin`\
280-`  // do something with the tree item`\
281-`  // tree 아이템과 함께 무언가를 합니다`\
282-` end;  `
330+``` pascal
331+ function MyFunc<T: TTreeItem>(A: T): T;
332+ begin
333+ // do something with the tree item
334+ // tree 아이템과 함께 무언가를 합니다
335+ end;
336+```
283337
284-` function Max<T>(A, B: T): T;`\
285-` begin`\
286-`   if A < B then`\
287-`     Result := B`\
288-`   else`\
289-`     Result := A;`\
290-` end; `
338+``` pascal
339+ function Max<T>(A, B: T): T;
340+ begin
341+ if A < B then
342+ Result := B
343+ else
344+ Result := A;
345+ end;
346+```
291347
292348My restrictions won't allow implementing generic Max and Min, I guess. That really needs macro-alike stuff (for the compiler implementation). 제가 생각하기로, 저의 제한은 Max, Min제너릭 구현을 허용할것 같지 않습니다. 그 것은 매크로 비슷한 것이 정말 필요해집니다(컴파일러 구현으로서)
293349
294350Another example for linked lists: (ripped from mail to fpc-devel of dannym, but modified a bit) 링크드 리스트로 다른 예제가 있습니다(메일로 온 dannym의 fpc-devel에서 가져왔지만, 조금만 고쳤습니다)
295351
296-` type`\
297-`   TListItem<T> = record`\
298-`     Data: T;`\
299-`     Next: TListItem;`\
300-`   end;`\
301-`   PListItem = ^TListItem;`\
352+``` pascal
353+ type
354+ TListItem<T> = record
355+ Data: T;
356+ Next: TListItem;
357+ end;
358+ PListItem = ^TListItem;
302359
303-`   TList<T> = class`\
304-`   private`\
305-`     fHead: PListItem<T>;`\
306-`     fTail: PListItem<T>;`\
307-`   published`\
308-`     procedure Add(Item: T);`\
309-`   end;`\
360+ TList<T> = class
361+ private
362+ fHead: PListItem<T>;
363+ fTail: PListItem<T>;
364+ published
365+ procedure Add(Item: T);
366+ end;
310367
311-` procedure TList<T>.Add(Item: T);`\
312-` var`\
313-`   node: PListItem<T>;`\
314-` begin`\
315-`   New(node);`\
316-`   node^.Data := Item;`\
317-`   node^.Next := nil;`\
318-` `\
319-`   if Assigned(fTail) then begin`\
320-`     fTail^.Next := node;`\
321-`   end else begin`\
322-`     fHead := node;`\
323-`   end;`\
324-` `\
325-`   fTail := node;`\
326-` end;`\
327-` `\
328-` type`\
329-`   TApple = class`\
330-`   end;`\
331-`   TOrange = class`\
332-`   end;`\
333-` `\
334-`   TAppleList = TList<TApple>;`\
335-` `\
336-` var`\
337-`   apples: TAppleList;`\
338-`   apple: TApple;`\
339-` begin`\
340-`   apples.Add(TApple.Create); // works //잘 됨.`\
341-`   apples.Add(TOrange.Create); // compile error //컴파일 에러.`\
342-` `\
343-`   apple := apples[0]; // works //잘 됨.`\
344-`   apple := apples[1]; // not applicable //적용되지 않음`\
345-`   apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨.`\
346-`   apple := apples[1] as TApple; // not applicable //적용되지 않음`\
347-` end;`
368+ procedure TList<T>.Add(Item: T);
369+ var
370+ node: PListItem<T>;
371+ begin
372+ New(node);
373+ node^.Data := Item;
374+ node^.Next := nil;
375+
376+ if Assigned(fTail) then begin
377+ fTail^.Next := node;
378+ end else begin
379+ fHead := node;
380+ end;
381+
382+ fTail := node;
383+ end;
384+
385+ type
386+ TApple = class
387+ end;
388+ TOrange = class
389+ end;
390+
391+ TAppleList = TList<TApple>;
392+
393+ var
394+ apples: TAppleList;
395+ apple: TApple;
396+ begin
397+ apples.Add(TApple.Create); // works //잘 됨.
398+ apples.Add(TOrange.Create); // compile error //컴파일 에러.
399+
400+ apple := apples[0]; // works //잘 됨.
401+ apple := apples[1]; // not applicable //적용되지 않음
402+ apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨.
403+ apple := apples[1] as TApple; // not applicable //적용되지 않음
404+ end;
405+```
348406
349407### "generic" 낱말을 사용하기
350408
351-` type`\
352-`   TGenericCollection = generic(T: TCollectionItem) class(TComponent)`\
353-`   ...implement TCollection and use T`\
354-`   end;`
409+``` pascal
410+ type
411+ TGenericCollection = generic(T: TCollectionItem) class(TComponent)
412+ ...implement TCollection and use T
413+ end;
414+```
355415
356-`   TCollection = specialize TGenericCollection(TCollectionItem);`\
357-`   TFieldDefs = specialize TGenericCollection(TFieldDef); `
416+```text
417+ TCollection = specialize TGenericCollection(TCollectionItem);
418+ TFieldDefs = specialize TGenericCollection(TFieldDef);
419+```
358420
359-`   TGenericList = generic(T: PtrInt) class(TObject)`\
360-`   ...implement TList and use PtrInt size for code generation`\
361-`   end;`
421+``` pascal
422+ TGenericList = generic(T: PtrInt) class(TObject)
423+ ...implement TList and use PtrInt size for code generation
424+ end;
425+```
362426
363-`   TList = specialize TGenericList(Pointer);`
427+```text
428+ TList = specialize TGenericList(Pointer);
429+```
364430
365431procedure 로써:
366432
367-` function generic(T: TTreeItem) MyFunc(A: T): T;`\
368-` begin`\
369-`  // do something with the tree item`\
370-`  // tree 아이템 과 함께 무언가를 합니다`\
371-` end;  `
433+``` pascal
434+ function generic(T: TTreeItem) MyFunc(A: T): T;
435+ begin
436+ // do something with the tree item
437+ // tree 아이템 과 함께 무언가를 합니다
438+ end;
439+```
372440
373-` function generic(T) Max(A, B: T): T;`\
374-` begin`\
375-`   if A < B then`\
376-`     Result := B`\
377-`   else`\
378-`     Result := A;`\
379-` end; `
441+``` pascal
442+ function generic(T) Max(A, B: T): T;
443+ begin
444+ if A < B then
445+ Result := B
446+ else
447+ Result := A;
448+ end;
449+```
380450
381451Another example for linked lists: (ripped from mail to fpc-devel of dannym, but modified a bit) 링크드 리스트로 다른 예제가 있습니다(메일로 온 dannym의 fpc-devel에서 가져왔지만, 조금만 고쳤습니다)
382452
383-` type`\
384-`   TListItem = generic(T) record`\
385-`     Data: T;`\
386-`     Next: TListItem;`\
387-`   end;`\
388-`   PListItem = ^TListItem;`\
453+``` pascal
454+ type
455+ TListItem = generic(T) record
456+ Data: T;
457+ Next: TListItem;
458+ end;
459+ PListItem = ^TListItem;
389460
390-`   TList = generic(T) class`\
391-`   private`\
392-`     fHead: specialize PListItem(T);`\
393-`     fTail: specialize PListItem(T);`\
394-`   published`\
395-`     procedure Add(Item: T);`\
396-`   end;`\
461+ TList = generic(T) class
462+ private
463+ fHead: specialize PListItem(T);
464+ fTail: specialize PListItem(T);
465+ published
466+ procedure Add(Item: T);
467+ end;
397468
398-` procedure generic(T) TList.Add(Item: T);`\
399-` var`\
400-`   node: specialize PListItem(T);`\
401-` begin`\
402-`   New(node);`\
403-`   node^.Data := Item;`\
404-`   node^.Next := nil;`\
405-` `\
406-`   if Assigned(fTail) then begin`\
407-`     fTail^.Next := node;`\
408-`   end else begin`\
409-`     fHead := node;`\
410-`   end;`\
411-` `\
412-`   fTail := node;`\
413-` end;`\
414-` `\
415-` type`\
416-`   TApple = class`\
417-`   end;`\
418-`   TOrange = class`\
419-`   end;`\
420-` `\
421-`   TAppleList = specialize TList(TApple);`\
422-` `\
423-` var`\
424-`   apples: TAppleList;`\
425-`   apple: TApple;`\
426-` begin`\
427-`   apples.Add(TApple.Create); // works //잘 됨.`\
428-`   apples.Add(TOrange.Create); // compile error //컴파일 에러`\
429-` `\
430-`   apple := apples[0]; // works //잘 됨.`\
431-`   apple := apples[1]; // not applicable //적용 안됨`\
432-`   apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨.`\
433-`   apple := apples[1] as TApple; // not applicable //적용 안됨`\
434-` end;`
469+ procedure generic(T) TList.Add(Item: T);
470+ var
471+ node: specialize PListItem(T);
472+ begin
473+ New(node);
474+ node^.Data := Item;
475+ node^.Next := nil;
476+
477+ if Assigned(fTail) then begin
478+ fTail^.Next := node;
479+ end else begin
480+ fHead := node;
481+ end;
482+
483+ fTail := node;
484+ end;
485+
486+ type
487+ TApple = class
488+ end;
489+ TOrange = class
490+ end;
491+
492+ TAppleList = specialize TList(TApple);
493+
494+ var
495+ apples: TAppleList;
496+ apple: TApple;
497+ begin
498+ apples.Add(TApple.Create); // works //잘 됨.
499+ apples.Add(TOrange.Create); // compile error //컴파일 에러
500+
501+ apple := apples[0]; // works //잘 됨.
502+ apple := apples[1]; // not applicable //적용 안됨
503+ apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨.
504+ apple := apples[1] as TApple; // not applicable //적용 안됨
505+ end;
506+```
435507
436508Ugly things in need to be resolved: 해결이 필요한, 안좋은 점들:
437509
438-` { a generic type "TPointer" which is a pointer to type instantiated with }`\
439-` { 포인터로 생성된 "TPointer" 제너릭 선언 }`\
440-` type TPointer = generic(Type) ^Type;`\
441-` { a generic type that instantiates all the enums for Type }`\
442-` { 선언형의 모든 열거를 생성하는 제너릭 선언 }`\
443-` type TAllEnums = generic(Type)(low(Type),high(Type));`
510+``` pascal
511+ { a generic type "TPointer" which is a pointer to type instantiated with }
512+ { 포인터로 생성된 "TPointer" 제너릭 선언 }
513+ type TPointer = generic(Type) ^Type;
514+ { a generic type that instantiates all the enums for Type }
515+ { 선언형의 모든 열거를 생성하는 제너릭 선언 }
516+ type TAllEnums = generic(Type)(low(Type),high(Type));
517+```
444518
445519So, before a keyword can be real "nice" the following things need addressing: 그래서, keyword가 진짜 "멋져"지는것 보다 먼저, 아래의 목록들이 주소를 필요합니다
446520
4475211. Double brackets ()(), looks C-ish again
4485222. 다시 C같이 보여지는 두 개의 괄호 () ()
4495233. In math, one usually defines functions with the parameters on the left of the equal sign, not on the right
4505244. 수학에서, 보통 equal 기호의 왼쪽에(오른 쪽이 아닌) 인자들과 함께 함수들을 선언합니다.
451525
452526#### 제안 2
453527
454528Inspired by idea from oliebol in combination with ugly examples, in list of const, var, type sections, add "template" section: 안좋은 예제들의 결합 속에서 oliebol의 생각으로부터 영감을 얻어, const와 var, type 섹션들의 목록안에 "template" 섹션을 추가합니다
455529
456-` const`\
457-`   ThisIsAConst = 1;`\
458-` `\
459-` type`\
460-`   TMyEnum = (ab, ac);`\
461-` `\
462-` template(T: TCollectionItem)`\
463-`   TGenericCollection = class(TComponent)`\
464-`   ...implement TCollection and use T`\
465-`   end;`\
466-` `\
467-` type`\
468-`   TCollection = specialize TGenericCollection(TCollectionItem);`\
469-`   TFieldDefs = specialize TGenericCollection(TFieldDef); `\
470-` `\
471-` template(T: PtrInt)`\
472-`   TGenericList = class(TObject)`\
473-`   ...implement TList and use PtrInt size for code generation`\
474-`   end;`\
475-` `\
476-` type`\
477-`   TList = specialize TGenericList(Pointer);`
530+``` pascal
531+ const
532+ ThisIsAConst = 1;
533+
534+ type
535+ TMyEnum = (ab, ac);
536+
537+ template(T: TCollectionItem)
538+ TGenericCollection = class(TComponent)
539+ ...implement TCollection and use T
540+ end;
541+
542+ type
543+ TCollection = specialize TGenericCollection(TCollectionItem);
544+ TFieldDefs = specialize TGenericCollection(TFieldDef);
545+
546+ template(T: PtrInt)
547+ TGenericList = class(TObject)
548+ ...implement TList and use PtrInt size for code generation
549+ end;
550+
551+ type
552+ TList = specialize TGenericList(Pointer);
553+```
478554
479555For procedures: procedure 로써:
480556
481-` function generic(T: TTreeItem) MyFunc(A: T): T;`\
482-` begin`\
483-`  // do something with the tree item`\
484-`  // tree 아이템과 함께 무언가를 합니다`\
485-` end;  `
557+``` pascal
558+ function generic(T: TTreeItem) MyFunc(A: T): T;
559+ begin
560+ // do something with the tree item
561+ // tree 아이템과 함께 무언가를 합니다
562+ end;
563+```
486564
487-` function generic(T) Max(A, B: T): T;`\
488-` begin`\
489-`   if A < B then`\
490-`     Result := B`\
491-`   else`\
492-`     Result := A;`\
493-` end; `
565+``` pascal
566+ function generic(T) Max(A, B: T): T;
567+ begin
568+ if A < B then
569+ Result := B
570+ else
571+ Result := A;
572+ end;
573+```
494574
495575Another example for linked lists: (ripped from mail to fpc-devel of dannym, but modified a bit) 링크드 리스트로 다른 예제가 있습니다(메일로 온 dannym의 fpc-devel에서 가져왔지만, 조금만 고쳤습니다)
496576
497-` template(T)`\
498-`   TListItem = record`\
499-`     Data: T;`\
500-`     Next: TListItem;`\
501-`   end;`\
502-`   PListItem = ^specialize TListItem(T);`\
577+``` pascal
578+ template(T)
579+ TListItem = record
580+ Data: T;
581+ Next: TListItem;
582+ end;
583+ PListItem = ^specialize TListItem(T);
503584
504-`   TList = class`\
505-`   type`\
506-`     PItem = specialize PListItem(T);`\
507-`   private`\
508-`     fHead: PItem;`\
509-`     fTail: PItem;`\
510-`   published`\
511-`     procedure Add(Item: T);`\
512-`   end;`\
585+ TList = class
586+ type
587+ PItem = specialize PListItem(T);
588+ private
589+ fHead: PItem;
590+ fTail: PItem;
591+ published
592+ procedure Add(Item: T);
593+ end;
513594
514-` ...implementation...`\
515-` `\
516-` procedure generic(T) TList.Add(Item: T);`\
517-` var`\
518-`   node: PItem;`\
519-` begin`\
520-`   New(node);`\
521-`   node^.Data := Item;`\
522-`   node^.Next := nil;`\
523-` `\
524-`   if Assigned(fTail) then begin`\
525-`     fTail^.Next := node;`\
526-`   end else begin`\
527-`     fHead := node;`\
528-`   end;`\
529-` `\
530-`   fTail := node;`\
531-` end;`\
532-` `\
533-` type`\
534-`   TApple = class`\
535-`   end;`\
536-`   TOrange = class`\
537-`   end;`\
538-` `\
539-`   TAppleList = specialize TList(TApple);`\
540-` `\
541-` var`\
542-`   apples: TAppleList;`\
543-`   apple: TApple;`\
544-` begin`\
545-`   apples.Add(TApple.Create); // works //잘 됨.`\
546-`   apples.Add(TOrange.Create); // compile error //컴파일 에러`\
547-` `\
548-`   apple := apples[0]; // works //잘 됨`\
549-`   apple := apples[1]; // not applicable //적용 안 됨`\
550-`   apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨`\
551-`   apple := apples[1] as TApple; // not applicable //적용 안 됨`\
552-` end;`
595+ ...implementation...
596+
597+ procedure generic(T) TList.Add(Item: T);
598+ var
599+ node: PItem;
600+ begin
601+ New(node);
602+ node^.Data := Item;
603+ node^.Next := nil;
604+
605+ if Assigned(fTail) then begin
606+ fTail^.Next := node;
607+ end else begin
608+ fHead := node;
609+ end;
610+
611+ fTail := node;
612+ end;
613+
614+ type
615+ TApple = class
616+ end;
617+ TOrange = class
618+ end;
619+
620+ TAppleList = specialize TList(TApple);
621+
622+ var
623+ apples: TAppleList;
624+ apple: TApple;
625+ begin
626+ apples.Add(TApple.Create); // works //잘 됨.
627+ apples.Add(TOrange.Create); // compile error //컴파일 에러
628+
629+ apple := apples[0]; // works //잘 됨
630+ apple := apples[1]; // not applicable //적용 안 됨
631+ apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨
632+ apple := apples[1] as TApple; // not applicable //적용 안 됨
633+ end;
634+```
553635
554636#### 제안 3
555637
556-` { Chu Jetcheng, 2008-07-24 }`
638+```text
639+ { Chu Jetcheng, 2008-07-24 }
640+```
557641
558-` program Generics;`
642+``` pascal
643+ program Generics;
644+```
559645
560-` type`\
561-`   { The compiler should maintain a global table storing each specialized type for each generic.  The `\
562-``      `of' operator is used to create a specialization for a specified generic type.  Specialized types  ``\
563-``      of the same `type layout' (no other words) point to the same entry in the table of specializations ``\
564-`     of the specialized generic type, and thus are compatible.  Generic objects and records should also `\
565-`     be allowed. }`\
566-``    { 컴파일러는 각 제너릭들을 위해 특별화된 선언형을 저장하는 전역 테이블을 유지해야만 합니다. `of' 연산자는 열거된 제너릭 선언들을 위해 ``\
567-``      특별하게 생성하려 사용되어졌습니다. 같은 `type layout'(다른 단어)의 특별화된 선언형들이 특별화된 제너릭 선언형의 테이블 안에 같은 ``\
568-`     entry를 가리키므로, 호환될 수 있습니다. 또한 제너릭 객체들과 레코드들은 허용해야 합니다}`
646+``` pascal
647+ type
648+ { The compiler should maintain a global table storing each specialized type for each generic. The
649+ `of' operator is used to create a specialization for a specified generic type. Specialized types
650+ of the same `type layout' (no other words) point to the same entry in the table of specializations
651+ of the specialized generic type, and thus are compatible. Generic objects and records should also
652+ be allowed. }
653+ { 컴파일러는 각 제너릭들을 위해 특별화된 선언형을 저장하는 전역 테이블을 유지해야만 합니다. `of' 연산자는 열거된 제너릭 선언들을 위해
654+ 특별하게 생성하려 사용되어졌습니다. 같은 `type layout'(다른 단어)의 특별화된 선언형들이 특별화된 제너릭 선언형의 테이블 안에 같은
655+ entry를 가리키므로, 호환될 수 있습니다. 또한 제너릭 객체들과 레코드들은 허용해야 합니다}
656+```
569657
570-`   TGeneric = generic class(TAncestorClass) of T1, T2`\
571-`   private`\
572-`     FData1: T1;`\
573-`     FData2: T2;`\
574-`   public`\
575-`     property Data1: T1 read FData1 write FData1;`\
576-`     property Data2: T2 read FData2 write FData2;`\
577-`     constructor Create(const A: T1; const B: T2);`\
578-`     procedure WriteData; virtual;`\
579-`   end;`
658+``` pascal
659+ TGeneric = generic class(TAncestorClass) of T1, T2
660+ private
661+ FData1: T1;
662+ FData2: T2;
663+ public
664+ property Data1: T1 read FData1 write FData1;
665+ property Data2: T2 read FData2 write FData2;
666+ constructor Create(const A: T1; const B: T2);
667+ procedure WriteData; virtual;
668+ end;
669+```
580670
581-`   TGenericDescendent = generic class(TGeneric of Integer, T3) of T3`\
582-`   private`\
583-`     FData3: T3;`\
584-`     FObjectOfSameType: TGenericDescendent of T3;`\
585-`   public`\
586-`     property Data3: T3 read FData3 write FData3;`\
587-`     property ObjectOfSameType: TGenericDescendent of T3 read FObjectOfSameType write FObjectOfSameType;`\
588-`     constructor Create(const C: T3);`\
589-`     procedure WriteData; override;`\
590-`   end;`
671+``` pascal
672+ TGenericDescendent = generic class(TGeneric of Integer, T3) of T3
673+ private
674+ FData3: T3;
675+ FObjectOfSameType: TGenericDescendent of T3;
676+ public
677+ property Data3: T3 read FData3 write FData3;
678+ property ObjectOfSameType: TGenericDescendent of T3 read FObjectOfSameType write FObjectOfSameType;
679+ constructor Create(const C: T3);
680+ procedure WriteData; override;
681+ end;
682+```
591683
592-`   TGenericIR = TGeneric of Integer, Real;`\
593-`   TGenericIRClass = class of TGenericIR;`
684+```text
685+ TGenericIR = TGeneric of Integer, Real;
686+ TGenericIRClass = class of TGenericIR;
687+```
594688
595-`   TGenericISClass = class of (TGeneric of Integer, string);`
689+```text
690+ TGenericISClass = class of (TGeneric of Integer, string);
691+```
596692
597-`   PGenericObj = generic ^TGenericObj; `\
598-`   TGenericObj = generic object of T `\
599-`     MyField: T;`\
600-`     procedure WriteData;`\
601-`   end;`
693+``` pascal
694+ PGenericObj = generic ^TGenericObj;
695+ TGenericObj = generic object of T
696+ MyField: T;
697+ procedure WriteData;
698+ end;
699+```
602700
603-` { TGeneric }`
701+```text
702+ { TGeneric }
703+```
604704
605-` { Use the same syntax for method implementations as with immediate classes. }`\
606-` { 직접 클래스들과 함께로써 method 구현들을 위해 똑같은 문법을 사용합니다 }`
705+```text
706+ { Use the same syntax for method implementations as with immediate classes. }
707+ { 직접 클래스들과 함께로써 method 구현들을 위해 똑같은 문법을 사용합니다 }
708+```
607709
608-` constructor TGeneric.Create(const A: T1; const B: T2);`\
609-` begin`\
610-`   FData1 := A;`\
611-`   FData2 := B;`\
612-` end;`
710+``` pascal
711+ constructor TGeneric.Create(const A: T1; const B: T2);
712+ begin
713+ FData1 := A;
714+ FData2 := B;
715+ end;
716+```
613717
614-` procedure TGeneric.WriteData;`\
615-` begin`\
616-`   Writeln(FData1);`\
617-`   Writeln(FData2);`\
618-` end;`
718+``` pascal
719+ procedure TGeneric.WriteData;
720+ begin
721+ Writeln(FData1);
722+ Writeln(FData2);
723+ end;
724+```
619725
620-` { TGenericDescendent }`
726+```text
727+ { TGenericDescendent }
728+```
621729
622-` constructor TGenericDescendent.Create(const C: T3);`\
623-` begin`\
624-`   inherited Create(16, C);`\
625-`   FData3 := C;`\
626-` end;`
730+``` pascal
731+ constructor TGenericDescendent.Create(const C: T3);
732+ begin
733+ inherited Create(16, C);
734+ FData3 := C;
735+ end;
736+```
627737
628-` procedure TGenericDescendent.WriteData;`\
629-` begin`\
630-`   inherited;`\
631-`   Writeln(FData3);`\
632-`   if Assigned(FObjectOfSameType) then FObjectOfSameType.WriteData;`\
633-` end;`
738+``` pascal
739+ procedure TGenericDescendent.WriteData;
740+ begin
741+ inherited;
742+ Writeln(FData3);
743+ if Assigned(FObjectOfSameType) then FObjectOfSameType.WriteData;
744+ end;
745+```
634746
635-` { TGenericObj }`
747+```text
748+ { TGenericObj }
749+```
636750
637-` procedure TGenericObj.WriteData;`\
638-` begin`\
639-`   Writeln(MyField);`\
640-` end;`
751+``` pascal
752+ procedure TGenericObj.WriteData;
753+ begin
754+ Writeln(MyField);
755+ end;
756+```
641757
642-` var `\
643-`   Obj1: TGeneric of Integer, Real;`\
644-`   Obj2, Obj3: TGenericDescendent of string;`\
645-`   OldStyleObj: TGenericObj of Integer;`\
646-`   OldStyleObjPtr: PGenericObj of Integer;`
758+``` pascal
759+ var
760+ Obj1: TGeneric of Integer, Real;
761+ Obj2, Obj3: TGenericDescendent of string;
762+ OldStyleObj: TGenericObj of Integer;
763+ OldStyleObjPtr: PGenericObj of Integer;
764+```
647765
648-` begin`\
649-`   Obj1 := TGeneric.Create(32, 3.14);`\
650-`   Obj1.WriteData;`\
651-`   Writeln(#9, Obj1 is TGenericIR);`\
652-`   Writeln(#9, Obj1 is TGenericIS);`
766+``` pascal
767+ begin
768+ Obj1 := TGeneric.Create(32, 3.14);
769+ Obj1.WriteData;
770+ Writeln(#9, Obj1 is TGenericIR);
771+ Writeln(#9, Obj1 is TGenericIS);
772+```
653773
654-`   Obj2 := TGenericDescendent.Create('Generic test.');`\
655-`   Obj2.WriteData;`\
656-`   Writeln(#9, Obj2 is TGenericIR);`\
657-`   Writeln(#9, Obj2 is TGenericIS);`
774+``` pascal
775+ Obj2 := TGenericDescendent.Create('Generic test.');
776+ Obj2.WriteData;
777+ Writeln(#9, Obj2 is TGenericIR);
778+ Writeln(#9, Obj2 is TGenericIS);
779+```
658780
659-`   Obj3 := TGenericDescendent.Create('Another generic test.');`\
660-`   Obj3.ObjectOfSameType := Obj2;`\
661-`   Obj3.WriteData;`
781+``` pascal
782+ Obj3 := TGenericDescendent.Create('Another generic test.');
783+ Obj3.ObjectOfSameType := Obj2;
784+ Obj3.WriteData;
785+```
662786
663-`   Obj3.Free;`\
664-`   Obj2.Free;`\
665-`   Obj1.Free;`
787+```text
788+ Obj3.Free;
789+ Obj2.Free;
790+ Obj1.Free;
791+```
666792
667-`   OldStyleObj.MyField := 100;`\
668-`   OldStyleObj.WriteData;`
793+``` pascal
794+ OldStyleObj.MyField := 100;
795+ OldStyleObj.WriteData;
796+```
669797
670-`   OldStyleObjPtr := New(PGenericObj of Integer);`\
671-`   with OldStyleObjPtr^ do begin`\
672-`     MyField := 202;`\
673-`     WriteData;`\
674-`   end;`\
675-`   Dispose(ObjStyleObjPtr);`\
676-` end.`
798+``` pascal
799+ OldStyleObjPtr := New(PGenericObj of Integer);
800+ with OldStyleObjPtr^ do begin
801+ MyField := 202;
802+ WriteData;
803+ end;
804+ Dispose(ObjStyleObjPtr);
805+ end.
806+```
677807
678808## Terms
679809
680810type user:
681811
682812- the function in the compiler that defines a variable or return type and thus 'uses a (already defined) type'.
683813
684814immediate type:
685815
686816- not generic and not specialized, i.e. 'normal type'
687817
688818generic type:
689819
690820- template for a class with some unspecified types, never to be filled in into this class type. Only by specialisation.
691821
692822specialization:
693823
694824- copy generic type class to new specialized type class
695825
696826type parameters:
697827
698828- T and Q, the unknown types for the generic TSomeGeneric\<T,Q\>
699829
700830specialized type:
701831
702832- a generic type with all type parameters know, written into a real class type (tree) and reused if possible
703833
704834## 변화들
705835
706836### class/record선언 표현 의 변화들
707837
708838Each class definition representation has added fields for:
709839
710-` - class instantiation mode`\
711-`    0  immediate type`\
712-`    1  generic type, no instantiation, just generate specialized type`\
713-`    2  specialized type`
840+``` pascal
841+ - class instantiation mode
842+ 0 immediate type
843+ 1 generic type, no instantiation, just generate specialized type
844+ 2 specialized type
845+```
714846
715-` - when mode 2:`\
716-`     generic type uplink (XXXX, what, unitname, typename?)`\
717-`   when mode 1:`\
718-`     list of specialized types known so far (and where),`\
719-`     XXXX list items`\
720-`   when mode 0: `\
721-`     nothing`
847+``` pascal
848+ - when mode 2:
849+ generic type uplink (XXXX, what, unitname, typename?)
850+ when mode 1:
851+ list of specialized types known so far (and where),
852+ XXXX list items
853+ when mode 0:
854+ nothing
855+```
722856
723857### Changes in 'type user' compilation (for class/record types only)
724858
725859Each class type user will have to check mode of the class type.
726860
727861For the used class type, If mode is immediate
728862
729-` - proceed as always till now.`
863+```text
864+ - proceed as always till now.
865+```
730866
731867If mode is specialized
732868
733-` - proceed as always till now `\
734-` - keep in mind the generic type for some checks later (and debugging).`
869+``` pascal
870+ - proceed as always till now
871+ - keep in mind the generic type for some checks later (and debugging).
872+```
735873
736874If mode is generic, this:
737875
738-` - check 'list of specialized types' for the type parameter to use.`\
739-`   If there is already a specialized type, use that.`\
740-`   (given that it is compatible with 'compile parameters' XXXX)`
876+``` pascal
877+ - check 'list of specialized types' for the type parameter to use.
878+ If there is already a specialized type, use that.
879+ (given that it is compatible with 'compile parameters' XXXX)
880+```
741881
742-` - If not available, clone the generic type in the tree, and fill in the`\
743-`   type params with the actual types to use.`\
744-`   Generate machine code as normal.`\
745-`   Remember the new specialized type for later in the list by the `\
746-`   generic type and type params used.`
882+``` pascal
883+ - If not available, clone the generic type in the tree, and fill in the
884+ type params with the actual types to use.
885+ Generate machine code as normal.
886+ Remember the new specialized type for later in the list by the
887+ generic type and type params used.
888+```
747889
748890(the generic type is best written to some ppu as parse tree so that it can be refetched for cloning somewhen. To keep it easy, initially it should be limited to having its .pas file around when wanting to use a generic)
749891
750892### type params
751893
752894Generics store a list of the type params (names).
753895
754-` ('T', 'Q')`
896+```text
897+ ('T', 'Q')
898+```
755899
756900And Specializations store a list of type mappings from the real types to the type params, in the way of
757901
758-` type`\
759-`   T = Integer;`\
760-`   Q = Boolean;`
902+``` pascal
903+ type
904+ T = Integer;
905+ Q = Boolean;
906+```
761907
762908of course these are local to this class/record specialization.
763909
764910## Other things to note (for *later*)
765911
766912### What if a method implementation depends on the type used to know how the implementation should look like ?
767913
768-` procedure GList<T is TObject>.Add(const value: T);`\
769-` procedure GList<T is Integer>.Add(const value: T);`\
770-` ?`
914+``` pascal
915+ procedure GList<T is TObject>.Add(const value: T);
916+ procedure GList<T is Integer>.Add(const value: T);
917+ ?
918+```
771919
772920or more cryptic like
773921
774-` procedure GList<TObject>.Add(const value: T);`\
775-` procedure GList<Integer>.Add(const value: T);`\
776-` ?`
922+``` pascal
923+ procedure GList<TObject>.Add(const value: T);
924+ procedure GList<Integer>.Add(const value: T);
925+ ?
926+```
777927
778928or like
779929
780-` procedure GList<T>.Add(const value: Integer);`\
781-` procedure GList<T>.Add(const value: TObject);`
930+``` pascal
931+ procedure GList<T>.Add(const value: Integer);
932+ procedure GList<T>.Add(const value: TObject);
933+```
782934
783935the latter would need extra compiler support but would be nicer, overall. Potentially clashing with normal overloads though.
784936
785937### How to do internal storage classes
786938
787-` type`\
788-` PNode<T> = ^TNode<T>;`\
789-` TNode<T> = record`\
790-`   prev,next: PNode<T>;`\
791-`   data: T;`\
792-` end;`
939+``` pascal
940+ type
941+ PNode<T> = ^TNode<T>;
942+ TNode<T> = record
943+ prev,next: PNode<T>;
944+ data: T;
945+ end;
946+```
793947
794-` type`\
795-` GList<T> = class`\
796-` private`\
797-`   head, tail: PNode<T>;`\
798-`   cnt: Integer;`\
799-` public`\
800-`   procedure Add(const stuff: T);`\
801-` end;`\
802-` ?`
948+``` pascal
949+ type
950+ GList<T> = class
951+ private
952+ head, tail: PNode<T>;
953+ cnt: Integer;
954+ public
955+ procedure Add(const stuff: T);
956+ end;
957+ ?
958+```
803959
804960This implies that generics are best implemented both for records and for classes alike! Also implies that pointer types need to support generic too.
805961
806962Also one specialization should chain other specializations (probably also when deriving from a generic).
807963
808964### How to derive from the generic type
809965
810966It would be good if generic types could be derived from.
811967
812-` type`\
813-` TGenericEventyList<T> = class(TGenericList<T>)`\
814-` public`\
815-`   procedure Add(value: T); override;`\
816-` end;`\
817-` ...`
968+``` pascal
969+ type
970+ TGenericEventyList<T> = class(TGenericList<T>)
971+ public
972+ procedure Add(value: T); override;
973+ end;
974+ ...
975+```
818976
819977### Interfaces should support generics too
820978
821-` type`\
822-` IBa<T> = interface`\
823-`   procedure Add(value: T);`\
824-` end;`\
825-` TBa<T> = class(...,IBla<T>,IInterface)`\
826-` end;`
979+``` pascal
980+ type
981+ IBa<T> = interface
982+ procedure Add(value: T);
983+ end;
984+ TBa<T> = class(...,IBla<T>,IInterface)
985+ end;
986+```
827987
828988(what to do about the guids of the specializations? probably just generate whatever, they dont have any real meaning after all)
829989
830990Of course this has limitations to check, like
831991
832992- the generic interface cannot be used, just its specializations
833993- the specialized interface cannot be used in a generic class interface list
834994- (the generic interface can be used in a generic class interface list)
835995- the generic interface itself is invalid to use anywhere (just as generic classes are) except for specializing and deriving from
836996- normal interfaces cannot derive from generic interfaces
837997- (generic interfaces can derive from generic interfaces) - given the type params are the same
838998- specialized interfaces cannot be derived from
839999
8401000### Limitation of possible specialisations
8411001
842-` type`\
843-` TGenericList<T: TObject or Integer> = ...`\
844-` end;`
1002+``` pascal
1003+ type
1004+ TGenericList<T: TObject or Integer> = ...
1005+ end;
1006+```
8451007
8461008Probably useful...
8471009
8481010### What to do with class functions
8491011
8501012I dont know a whole lot of how class functions are stored internally. What happens to class functions in generics?
8511013
8521014### 'class of'
8531015
8541016\<Almindor\> don't forget class of, we need class of compatibility for dynamic class factories
8551017
8561018\<Almindor\> There are possible problems with 'class of'
8571019
8581020## Implementation details
8591021
8601022### Sanity checks
8611023
8621024- Generic types cannot be instantiated from
8631025- (Generic types can be derived from)
8641026- Specialized types cannot be derived from
8651027- Normal types cannot use generic types in its definition
8661028- (Normal types can use specialized types in its definition)
8671029- There are no half specialized types (one type param specified, the other not)
8681030- prevent loops while 'unpacking' specializations (loop counter field in every specialization)
8691031
8701032### Things to note and not forgot
8711033
8721034- class와 record 제너릭은 그 선언 안에서 그 자신을 선언형으로 사용할 수 있습니다
8731035
8741036예:
8751037
876-` type`\
877-` TBla<T> = class`\
878-`   parent: TBla<T>;`\
879-` end;`
1038+``` pascal
1039+ type
1040+ TBla<T> = class
1041+ parent: TBla<T>;
1042+ end;
1043+```
8801044
8811045- class와 record 제너릭은 그 선언 안에서 다른 제너릭을 선언형으로 사용할 수 있습니다
8821046
883-` type`\
884-` TBla<T> = class`\
885-`   parent: TBlo<T>;`\
886-` end;`
1047+``` pascal
1048+ type
1049+ TBla<T> = class
1050+ parent: TBlo<T>;
1051+ end;
1052+```
8871053
8881054## Implementation steps
8891055
8901056### Extend parser to support '\<T\>' and '\<T: bla or bla or bla\>' and '\<T,Q\>' notation
8911057
8921058Easy to do. Done.
8931059
8941060## Different ways to do it, one excluding the other
8951061
8961062### Way 1
8971063
8981064#### Change class/record/object/pointertype/interface parser to mark if it is a generic, a specialization or normal
8991065
9001066Mediate to do. Have done it for class/object and pointertype. Needs all kinds of clone functions for the defs and syms. fpk says he has patches. waiting.
9011067
9021068#### insert dummy symbols (typesym + typedef) for the type params in the generic
9031069
9041070Cannot be inserted into the object because parsing of types within objects has been disabled to make that possible:
9051071
906-` type`\
907-` Row = Cardinal;`\
908-` TBla = class `\
909-`   Row: Integer;`\
910-` end;`
1072+``` pascal
1073+ type
1074+ Row = Cardinal;
1075+ TBla = class
1076+ Row: Integer;
1077+ end;
1078+```
9111079
9121080weird.. (function searchsym_type, is not possible to have type definitions in records, objects, parameters)
9131081
9141082#### parse implementation section methods *for the generic*
9151083
9161084Is harder than it sounds, because the class/object the method is member of has to be searched for the type symbol for the type params (and these *not* derefed but just used as is).
9171085
9181086#### when parsing generics, use a dummy type in place of the type params
9191087
9201088For that, defer the type checking of the compiler in that case to 'as late as possible' or 'never for the generic' \<--- TODO... hard...
9211089
9221090#### Change derivation handlers to do the sanity checks
9231091
9241092Should pose no problems other than finding all the places.
9251093
9261094#### Add error messages for it
9271095
9281096#### Change pexpr (tnode creating)
9291097
9301098\<Synopsis+\> see the do_resulttypepass() calls in pexpr.pas But the compiler needs to known for example if it allows a . after the type
9311099
9321100- add a new tnode type for postfix operators (instead of resolving the operators into the fields/methods they reference) and defer type checking until later (just before binary generation - which is not done for the generic type).
9331101
9341102Examples for postfix operators are:
9351103
9361104- '\[\]' array member access (normal array, class default array property?)
9371105
9381106- '.' record/class member method/variable access
9391107
9401108- '^' pointer dereference
9411109
9421110- (automatic pointer dereference)
9431111
9441112\<Synopsis\> grep for m_auto and you'll find the places where it is used \<Synopsis\> only in pexpr.pas
9451113
9461114#### Change ppu streaming routines to save the tree of generics to the ppu
9471115
9481116#### Change type user to instantiate specialized types for generics when used
9491117
9501118Somewhat hard to do. (main work here :))
9511119
9521120For the instantiation
9531121
9541122- there is a dummy type sym needed (ok),
9551123- a new objectdef
9561124- clone of all the syms and defs (at least proc and property) of the original class/object
9571125- and replacing all the type params by the correct types.
9581126- Store that into the module as def (not on disk).
9591127- (\<Synopsis+\> an additional symtable shall be added to tmodule: tempsymtable; all temporary tdef's shall be stored in that symtable)
9601128- Then resume compiling for the class/object.
9611129
9621130### Way 2
9631131
9641132just keep the source code of the generic around and do blind replacing of the type params and then compile a specialization from that as 'source'
9651133
9661134#### Notes
9671135
9681136\<Synopsis+\> but the code to generate the specialization at runtime can be generated at the time the specialization is created. It doesn't need to be stored in ppu. all information is available to generate the tree at that time.
9691137
9701138\<Synopsis+\> In the 2.1.x development series a rewrite of the ppu loading is planned to make it more clean and more maintainable. Currently it is risky to fix bugs without introducing new bugs
9711139
9721140\<plugwash-\> It needs to be stored in some form so that the specialisations can be generated from it. \<Synopsis+\> but you can't store them in the ppu. Or with the same limitations as inlining. No references to the implementation symtable.
9731141
9741142fpk has patches to make cloning defs possible.
9751143
976114401:28:24 \<Synopsis+\> users will complain; things like:
9771145
978-` interface`\
979-`   generictype declar`\
980-` implementation`\
981-`   procedure helper;`\
982-`   begin`\
983-`   end`\
984-`   constructor generictype.create`\
985-`   begin`\
986-`     helper`\
987-`   end`\
988-` end.`
1146+``` pascal
1147+ interface
1148+ generictype declar
1149+ implementation
1150+ procedure helper;
1151+ begin
1152+ end
1153+ constructor generictype.create
1154+ begin
1155+ helper
1156+ end
1157+ end.
1158+```
9891159
9901160Will not be allowed.
9911161
9921162Another problem:
9931163
994-` unit a;`\
995-` interface`\
996-`   generictypeA`\
997-` implementation`\
998-` uses B`\
999-` end.`
1164+``` pascal
1165+ unit a;
1166+ interface
1167+ generictypeA
1168+ implementation
1169+ uses B
1170+ end.
1171+```
10001172
1001-` unit b;`\
1002-` interface`\
1003-` uses a`\
1004-` implemenation`\
1005-` begin`\
1006-`   generictypeA<integer>.craete`\
1007-` end.`
1173+``` pascal
1174+ unit b;
1175+ interface
1176+ uses a
1177+ implemenation
1178+ begin
1179+ generictypeA<integer>.craete
1180+ end.
1181+```
10081182
10091183At the time that the implementation of B is parsed it needs already the code of generictypeA. but that is not yet parsed! The compiler doesn't know anything yet. It only knows that generictypeA exists.
10101184
10111185\<fpk-\> dannym, Synopsis: we can simply forbid such code in generics which cause the problem
10121186
10131187\<fpk-\> i.e. everything used by generics must be already included in the interface uses clause ... or forbid references to units used only in the implementation section :)
10141188
10151189\<Synopsis+\> fpk had a good idea that can solve some of the issues: unit bla; interface ... generics ... implementation ... initialisation ... finalizatrion end.
10161190
10171191\<Synopsis+\> The generics delcarations shall be put in a separate section before implementation is parsed
10181192
10191193\<dannym\> at 'procedure TTest.Add(x: T);', T needs to be known. but it doesnt seem that the object symtable is searched for the class method parameters. correct ?
10201194
10211195\<Synopsis+\> dannym: correct, object symtables can not contain types, because that created problems. there is special code for that: remove the objectsymtable before parsing type declarations.
10221196
1023-` { for records, don't search the recordsymtable for the symbols of the types }`\
1024-` oldsymtablestack:=symtablestack;`\
1025-` symtablestack:=symtablestack.next;`
1197+``` pascal
1198+ { for records, don't search the recordsymtable for the symbols of the types }
1199+ oldsymtablestack:=symtablestack;
1200+ symtablestack:=symtablestack.next;
1201+```
10261202
10271203Because you can have a field with the same name as a type
10281204
1029-` type`\
1030-` Wrd = Word;`\
1031-` R = Record`\
1032-`   Wrd : Wrd;`\
1033-` end`
1205+``` pascal
1206+ type
1207+ Wrd = Word;
1208+ R = Record
1209+ Wrd : Wrd;
1210+ end
1211+```
10341212
10351213this is allowed. To support this the record or object symtable is remvoed from the symtablestack when the type is parsed.
10361214
10371215## 이미 존재하는 것
10381216
10391217### 메타 클래스
10401218
1041-` type`\
1042-` TObjectClass = class of TObject;`\
1043-` TTypedList = class`\
1044-` private`\
1045-`   Fwanttype: TObjectClass;`\
1046-`   ...`\
1047-` public`\
1048-`   constructor Create(itemtype: TObjectClass);`\
1049-`   procedure Add(item: TObject);`\
1050-`   ...`\
1051-` end;`\
1052-` constructor TTypedList.Create(itemtype: TObjectClass);`\
1053-` begin`\
1054-`   Fwanttype := itemtype;`\
1055-`   ...`\
1056-` end;`\
1057-` procedure TTypedList.Add(item: TObject);`\
1058-` begin`\
1059-`   assert(item.Class = Fwanttype);`\
1060-`   ...`\
1061-` end;`
1219+``` pascal
1220+ type
1221+ TObjectClass = class of TObject;
1222+ TTypedList = class
1223+ private
1224+ Fwanttype: TObjectClass;
1225+ ...
1226+ public
1227+ constructor Create(itemtype: TObjectClass);
1228+ procedure Add(item: TObject);
1229+ ...
1230+ end;
1231+ constructor TTypedList.Create(itemtype: TObjectClass);
1232+ begin
1233+ Fwanttype := itemtype;
1234+ ...
1235+ end;
1236+ procedure TTypedList.Add(item: TObject);
1237+ begin
1238+ assert(item.Class = Fwanttype);
1239+ ...
1240+ end;
1241+```
10621242
1063-` ...`\
1064-` TSomeStuff = class`\
1065-` end;`\
1066-` ...`\
1067-` Flist := TTypedList.Create(TSomeStuff);`
1243+``` pascal
1244+ ...
1245+ TSomeStuff = class
1246+ end;
1247+ ...
1248+ Flist := TTypedList.Create(TSomeStuff);
1249+```
10681250
10691251장점
10701252
10711253- 이미 구현되어 있음
10721254
10731255단점
10741256
10751257- runtime 때 느림
10761258- 간단한 선언형을 만들 수 없음.
10771259- 지원되는 선언형들에서도 모든 time에 변환(type-casting)이 필요합니다(다시말하면, 읽을때에도)
10781260
10791261## 여기서 부터 통합됩니다
10801262
10811263### 채팅 내용
10821264
10831265\<Synopsis\> <http://www.eleforum.com/cgi-bin/eleweb_lift?action=3&script=wall&num=18&reversesort=true&type=today&starttime=00:00&endtime=23:59&startdate=01-02-05&enddate=01-02-05> \<Synopsis\> or \<Synopsis\> <http://neli.hopto.org:3980/~micha/irc-fpc/2005/01/%23fpc.20050102.log>
10841266
10851267---
10861268*From the Free Pascal wiki, page "Generics/ko", as it stood on 2010-09-03 after a change by Hwiorn, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history