Sign in Join
Wiki copytemporary

Generics/ko: what changed

Revision 1 to 2. 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
2929` type`\
3030` // explicit addition of "generic" keyword. Maybe something like "uses generic <...>" `\
3131` // better use the <>-brackets because otherwise it may cause confusion with arrays `\
3232` // in the actual instantiation`\
3333` // "generic"키워드를 명시합니다. 실제 인스턴스에서 배열들과 함께 혼동을 일으킬 것이므로, `\
3434` // <>괄호를 쓰는 것보다 "generic <...>" 을 쓰는 것이 나을것입니다`\
3535` abc = class(..) generic <a, b>`\
3636` end;`\
3737` var`\
3838`       //  because they're still unused ;)`\
3939`       // 왜냐면 그것들은 아직 사용되지 않았습니다 ;)`\
4040`       xyz : abc<String, Integer>;`\
4141`       xyz2 : abc<AObj1, AObj2>;`\
4242` begin`\
4343`   // don't repeat generics in instance creation (if not necessary)`\
4444`   // 인스턴스의 초기화에 제너릭을 반복하지 마십시요(필요하지 않다면)`\
4545`   xyz := abc.Create;`\
4646`   xyz2 := abc<descendant_of_Aobj1, descendant_of_Aobj2>.Create;`\
4747` end.`
4848
4949(dannym 의 새로운 제안)
5050
5151` type`\
5252` GList = generic class of T`\
5353` public`\
5454`   procedure Add(const stuff: T);`\
5555` end;`
5656
5757` procedure GList.Add(const stuff: T); // note that here no 'of T' //'of T'가 없음을 유의하세요`\
5858` begin`\
5959`   ...`\
6060` end;`
6161
6262` var`\
6363`   intlist: GList of Integer;`\
6464` begin`\
6565`   intlist := GList.Create; // note that here the detail type is missing and `\
6666`           // needs to be deducted from the var declaration`\
6767`           // 여기에 자세한 선언형이 없으며, var 선언으로 (선언형이)빠져야만 한다는 것을 알아두세요`
6868
6969`   //or intlist := typeof(intlist).Create;`\
7070`   //intlist := GList of Integer.Create; <-- this is unclear if that works <-- 이 것이 실제 구현된 것이라면, 명확하지 않습니다`\
7171` end;`
7272
7373(dannym 의 옛 제안)
7474
7575` type`\
7676` GList<T> = class`\
7777` public`\
7878`   procedure Add(const stuff: T);`\
7979` end;`
8080
8181` procedure GList<T>.Add(const stuff: T);`\
8282` begin`\
8383`   ...`\
8484` end;`
8585
8686` var`\
8787`   intlist: GList<Integer>;`\
8888` begin`\
8989`   intlist := GList<Integer>.Create;`\
9090` end;`
9191
9292plugwash 의 것:
9393
9494` tmycollection=template(tobject)[x]`\
9595` tintegercollection=tmycollection[integer]`
9696
9797oliebol 의 것:
9898
9999` template blaat<t:integer>(a:t);`\
100100` var x : t;`\
101101` begin`\
102102`   do something with a, and use t with it`\
103103` end;`
104104
105105note that we should have a generics section (like interface and implementation sections) containing the generics: 우리는 (interface와 implementation 섹션들처럼) 제너릭들을 포함하는, generics 섹션을 가져야한다는것을 알립니다
106106
107107` unit xyz;`\
108108` generics`\
109109` type`\
110110`   GList......`\
111111` procedure GList.Add(const value: T);`\
112112` ....`\
113113` end.`
114114
115115(eiffel의 것)
116116
117117<http://paste.lisp.org/display/6236>
118118
119119(PublicJoke 의 제안)
120120
121121` unit Unit1(TMathType);`\
122122` `\
123123` interface`\
124124` `\
125125` type`\
126126`   TMathClass = class`\
127127`   public`\
128128`     class function Add(a1, a2: TMathType): TMathType;`\
129129`   end;`\
130130` `\
131131` implementation`\
132132` `\
133133` class function TMathClass.Add(a1, a2: TMathType): TMathType;`\
134134` begin`\
135135`   Result:=a1+a2;`\
136136` end;`\
137137` `\
138138` end.`
139139
140140` unit Unit2;`\
141141` `\
142142` type`\
143143`   TMathType = Longword;`\
144144` `\
145145` interface`\
146146` `\
147147` implementation`\
148148` `\
149149` end.`
150150
151151` program prog;`\
152152` `\
153153` uses`\
154154`   Unit2, `\
155155`   Unit1(Byte) as ByteMath in 'Unit1.pas',`\
156156`   Unit1(TMathType) as PolyMath in 'Unit1.pas';`\
157157` `\
158158` type`\
159159`   TByteMathClass = ByteMath.TMathClass;`\
160160`   TPolyMathClass = PolyMath.TMathClass;`\
161161` `\
162162` var`\
163163`   b: Byte;`\
164164`   p: TMathType;`\
165165` `\
166166` begin`\
167167`   b:=TByteMathClass.Add(1, 2);`\
168168`   p:=TPolyMathClass.Add(3, 4);`\
169169` end.`
170170
171171(Gadnio 의 제안) I personally think the C++ way of doing this is clear enough AND will be the easiest to parse/understand: 저는 개인적으로 C++의 방법이 이것을 충분히 명확하게 하고, 해석과 이해가 쉬워질꺼라고 생각합니다
172172
173173` template <T>`\
174174`   TGenericObject< T > = record`\
175175`     Data : T;`\
176176`     OtherStuff : Pointer;`\
177177`   end;{TGenericObject}`\
178178` template <TKey, TData = TGenericObject< boolean > >`\
179179`   TGenericList = class( TWhee< TKey > )`\
180180`   public`\
181181`     function Lookup( const Key : TKey ): TData;`\
182182`     template <THihi>`\
183183`       class function DataToHihi( Data : TData ): THihi;`\
184184`   end;{TGenericList}`
185185
186186Also, 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 \>을 가지고 있습니다. 한 예로..
187187
188188` template <T, TT>`\
189189`   TSame = class`\
190190`     class function Same: Boolean;`\
191191`   end;{TSame}`\
192192` template <T>`\
193193`   TSame = class`\
194194`     class function Same: Boolean;`\
195195`   end;{TSame}`
196196
197197` template <T, TT>`\
198198` class function TSame.Same: Boolean;`\
199199` begin`\
200200`   Result := false;`\
201201` end;{TSame<T, TT>.Same}`\
202202` template <T>`\
203203` class function TSame.Same: Boolean;`\
204204` begin`\
205205`   Result := true;`\
206206` end;{TSame<T>.Same}`
207207
208208This allows to make a compile-time check for same types that are not TObject, e.g. 이 것은 TObject가 아닌, 같은 선언형에 대해서 compile-time 검사를 할수 있게 합니다. 예로 들면..
209209
210210` TFoo = class;`\
211211` TBar = class( TFoo );`\
212212` var`\
213213`   S : Boolean;`\
214214` begin`\
215215`   S := TSame< String, Integer >.Same; //s = false`\
216216`   S := TSame< Int64, Integer >.Same; //s = false`\
217217`   S := TSame< String, String >.Same; //s = true`\
218218`   S := TSame< TBar, TFoo >.Same;//s = false (not the same as "var x: TFoo; begin x := TBar.Create; end;" )`\
219219`                                             // "var x: TFoo; begin x := TBar.Create; end;" 가 같지 않듯이)`\
220220` end;`
221221
222222Another thing to note: It would be very good if something like this (c++ syntax) would be implemented: 다른 한가지를 적자면, 만약 이 런것이(C++ 문법) 시행되어진다면, 매우 좋아질 겁니다
223223
224224` template <bool b>`\
225225` class h`\
226226` {`\
227227`   public:`\
228228`   static const int i = 0;`\
229229` };//h`
230230
231231` template <>`\
232232` class h< true >`\
233233` {`\
234234`   public:`\
235235`   static const int i = 1;`\
236236` };`
237237
238238` template <>`\
239239` class h< false >`\
240240` {`\
241241`   public:`\
242242`   static const int i = 2;`\
243243` };`
244244
245245Here 여기는 항상
246246
247247` h<false>.i = 2`\
248248` h<true>.i = 1 `
249249
250250ALWAYS. 이렇게 됩니다
251251
252252## 사용 례
253253
254254If 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" 낱말입니다.
255255
256256### 괄호 사용하기: \<\>
257257
258258` type`\
259259`   TGenericCollection<T: TCollectionItem> = class(TComponent)`\
260260`   ...implement TCollection and use T`\
261261`   end;`
262262
263263`   TCollection = TGenericCollection<TCollectionItem>;`\
264264`   TFieldDefs = TGenericCollection<TFieldDef>; `
265265
266266`   TGenericList<T: PtrInt> = class(TObject)`\
267267`   ...implement TList and use PtrInt size for code generation`\
268268`   end;`
269269
270270`   TList = TGenericList<Pointer>;`
271271
272272Implementation of TGenericCollection can be compiled as if (T: TCollectionItem) were used. TGenericCollection의 구현은 마치 (T: TCollectionItem)이 사용된 것처럼 컴파일 되어질 것입니다
273273
274274Would 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. 여기서 순환참조를 해결할 수 있을까요? 저는 컴파일러 엔지니어가 아니지만, 적어도 하나가 현재 이 클래스들의 구현만큼 알기 때문에 가능하다고 봅니다
275275
276276For procedures: procedure 로써:
277277
278278` function MyFunc<T: TTreeItem>(A: T): T;`\
279279` begin`\
280280`  // do something with the tree item`\
281281`  // tree 아이템과 함께 무언가를 합니다`\
282282` end;  `
283283
284284` function Max<T>(A, B: T): T;`\
285285` begin`\
286286`   if A < B then`\
287287`     Result := B`\
288288`   else`\
289289`     Result := A;`\
290290` end; `
291291
292292My restrictions won't allow implementing generic Max and Min, I guess. That really needs macro-alike stuff (for the compiler implementation). 제가 생각하기로, 저의 제한은 Max, Min제너릭 구현을 허용할것 같지 않습니다. 그 것은 매크로 비슷한 것이 정말 필요해집니다(컴파일러 구현으로서)
293293
294294Another example for linked lists: (ripped from mail to fpc-devel of dannym, but modified a bit) 링크드 리스트로 다른 예제가 있습니다(메일로 온 dannym의 fpc-devel에서 가져왔지만, 조금만 고쳤습니다)
295295
296296` type`\
297297`   TListItem<T> = record`\
298298`     Data: T;`\
299299`     Next: TListItem;`\
300300`   end;`\
301301`   PListItem = ^TListItem;`\
302-\
302+
303303`   TList<T> = class`\
304304`   private`\
305305`     fHead: PListItem<T>;`\
306306`     fTail: PListItem<T>;`\
307307`   published`\
308308`     procedure Add(Item: T);`\
309309`   end;`\
310-\
310+
311311` procedure TList<T>.Add(Item: T);`\
312312` var`\
313313`   node: PListItem<T>;`\
314314` begin`\
315315`   New(node);`\
316316`   node^.Data := Item;`\
317317`   node^.Next := nil;`\
318318` `\
319319`   if Assigned(fTail) then begin`\
320320`     fTail^.Next := node;`\
321321`   end else begin`\
322322`     fHead := node;`\
323323`   end;`\
324324` `\
325325`   fTail := node;`\
326326` end;`\
327327` `\
328328` type`\
329329`   TApple = class`\
330330`   end;`\
331331`   TOrange = class`\
332332`   end;`\
333333` `\
334334`   TAppleList = TList<TApple>;`\
335335` `\
336336` var`\
337337`   apples: TAppleList;`\
338338`   apple: TApple;`\
339339` begin`\
340340`   apples.Add(TApple.Create); // works //잘 됨.`\
341341`   apples.Add(TOrange.Create); // compile error //컴파일 에러.`\
342342` `\
343343`   apple := apples[0]; // works //잘 됨.`\
344344`   apple := apples[1]; // not applicable //적용되지 않음`\
345345`   apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨.`\
346346`   apple := apples[1] as TApple; // not applicable //적용되지 않음`\
347347` end;`
348348
349349### "generic" 낱말을 사용하기
350350
351351` type`\
352352`   TGenericCollection = generic(T: TCollectionItem) class(TComponent)`\
353353`   ...implement TCollection and use T`\
354354`   end;`
355355
356356`   TCollection = specialize TGenericCollection(TCollectionItem);`\
357357`   TFieldDefs = specialize TGenericCollection(TFieldDef); `
358358
359359`   TGenericList = generic(T: PtrInt) class(TObject)`\
360360`   ...implement TList and use PtrInt size for code generation`\
361361`   end;`
362362
363363`   TList = specialize TGenericList(Pointer);`
364364
365365procedure 로써:
366366
367367` function generic(T: TTreeItem) MyFunc(A: T): T;`\
368368` begin`\
369369`  // do something with the tree item`\
370370`  // tree 아이템 과 함께 무언가를 합니다`\
371371` end;  `
372372
373373` function generic(T) Max(A, B: T): T;`\
374374` begin`\
375375`   if A < B then`\
376376`     Result := B`\
377377`   else`\
378378`     Result := A;`\
379379` end; `
380380
381381Another example for linked lists: (ripped from mail to fpc-devel of dannym, but modified a bit) 링크드 리스트로 다른 예제가 있습니다(메일로 온 dannym의 fpc-devel에서 가져왔지만, 조금만 고쳤습니다)
382382
383383` type`\
384384`   TListItem = generic(T) record`\
385385`     Data: T;`\
386386`     Next: TListItem;`\
387387`   end;`\
388388`   PListItem = ^TListItem;`\
389-\
389+
390390`   TList = generic(T) class`\
391391`   private`\
392392`     fHead: specialize PListItem(T);`\
393393`     fTail: specialize PListItem(T);`\
394394`   published`\
395395`     procedure Add(Item: T);`\
396396`   end;`\
397-\
397+
398398` procedure generic(T) TList.Add(Item: T);`\
399399` var`\
400400`   node: specialize PListItem(T);`\
401401` begin`\
402402`   New(node);`\
403403`   node^.Data := Item;`\
404404`   node^.Next := nil;`\
405405` `\
406406`   if Assigned(fTail) then begin`\
407407`     fTail^.Next := node;`\
408408`   end else begin`\
409409`     fHead := node;`\
410410`   end;`\
411411` `\
412412`   fTail := node;`\
413413` end;`\
414414` `\
415415` type`\
416416`   TApple = class`\
417417`   end;`\
418418`   TOrange = class`\
419419`   end;`\
420420` `\
421421`   TAppleList = specialize TList(TApple);`\
422422` `\
423423` var`\
424424`   apples: TAppleList;`\
425425`   apple: TApple;`\
426426` begin`\
427427`   apples.Add(TApple.Create); // works //잘 됨.`\
428428`   apples.Add(TOrange.Create); // compile error //컴파일 에러`\
429429` `\
430430`   apple := apples[0]; // works //잘 됨.`\
431431`   apple := apples[1]; // not applicable //적용 안됨`\
432432`   apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨.`\
433433`   apple := apples[1] as TApple; // not applicable //적용 안됨`\
434434` end;`
435435
436436Ugly things in need to be resolved: 해결이 필요한, 안좋은 점들:
437437
438438` { a generic type "TPointer" which is a pointer to type instantiated with }`\
439439` { 포인터로 생성된 "TPointer" 제너릭 선언 }`\
440440` type TPointer = generic(Type) ^Type;`\
441441` { a generic type that instantiates all the enums for Type }`\
442442` { 선언형의 모든 열거를 생성하는 제너릭 선언 }`\
443443` type TAllEnums = generic(Type)(low(Type),high(Type));`
444444
445445So, before a keyword can be real "nice" the following things need addressing: 그래서, keyword가 진짜 "멋져"지는것 보다 먼저, 아래의 목록들이 주소를 필요합니다
446446
4474471. Double brackets ()(), looks C-ish again
4484482. 다시 C같이 보여지는 두 개의 괄호 () ()
4494493. In math, one usually defines functions with the parameters on the left of the equal sign, not on the right
4504504. 수학에서, 보통 equal 기호의 왼쪽에(오른 쪽이 아닌) 인자들과 함께 함수들을 선언합니다.
451451
452452#### 제안 2
453453
454454Inspired by idea from oliebol in combination with ugly examples, in list of const, var, type sections, add "template" section: 안좋은 예제들의 결합 속에서 oliebol의 생각으로부터 영감을 얻어, const와 var, type 섹션들의 목록안에 "template" 섹션을 추가합니다
455455
456456` const`\
457457`   ThisIsAConst = 1;`\
458458` `\
459459` type`\
460460`   TMyEnum = (ab, ac);`\
461461` `\
462462` template(T: TCollectionItem)`\
463463`   TGenericCollection = class(TComponent)`\
464464`   ...implement TCollection and use T`\
465465`   end;`\
466466` `\
467467` type`\
468468`   TCollection = specialize TGenericCollection(TCollectionItem);`\
469469`   TFieldDefs = specialize TGenericCollection(TFieldDef); `\
470470` `\
471471` template(T: PtrInt)`\
472472`   TGenericList = class(TObject)`\
473473`   ...implement TList and use PtrInt size for code generation`\
474474`   end;`\
475475` `\
476476` type`\
477477`   TList = specialize TGenericList(Pointer);`
478478
479479For procedures: procedure 로써:
480480
481481` function generic(T: TTreeItem) MyFunc(A: T): T;`\
482482` begin`\
483483`  // do something with the tree item`\
484484`  // tree 아이템과 함께 무언가를 합니다`\
485485` end;  `
486486
487487` function generic(T) Max(A, B: T): T;`\
488488` begin`\
489489`   if A < B then`\
490490`     Result := B`\
491491`   else`\
492492`     Result := A;`\
493493` end; `
494494
495495Another example for linked lists: (ripped from mail to fpc-devel of dannym, but modified a bit) 링크드 리스트로 다른 예제가 있습니다(메일로 온 dannym의 fpc-devel에서 가져왔지만, 조금만 고쳤습니다)
496496
497497` template(T)`\
498498`   TListItem = record`\
499499`     Data: T;`\
500500`     Next: TListItem;`\
501501`   end;`\
502502`   PListItem = ^specialize TListItem(T);`\
503-\
503+
504504`   TList = class`\
505505`   type`\
506506`     PItem = specialize PListItem(T);`\
507507`   private`\
508508`     fHead: PItem;`\
509509`     fTail: PItem;`\
510510`   published`\
511511`     procedure Add(Item: T);`\
512512`   end;`\
513-\
513+
514514` ...implementation...`\
515515` `\
516516` procedure generic(T) TList.Add(Item: T);`\
517517` var`\
518518`   node: PItem;`\
519519` begin`\
520520`   New(node);`\
521521`   node^.Data := Item;`\
522522`   node^.Next := nil;`\
523523` `\
524524`   if Assigned(fTail) then begin`\
525525`     fTail^.Next := node;`\
526526`   end else begin`\
527527`     fHead := node;`\
528528`   end;`\
529529` `\
530530`   fTail := node;`\
531531` end;`\
532532` `\
533533` type`\
534534`   TApple = class`\
535535`   end;`\
536536`   TOrange = class`\
537537`   end;`\
538538` `\
539539`   TAppleList = specialize TList(TApple);`\
540540` `\
541541` var`\
542542`   apples: TAppleList;`\
543543`   apple: TApple;`\
544544` begin`\
545545`   apples.Add(TApple.Create); // works //잘 됨.`\
546546`   apples.Add(TOrange.Create); // compile error //컴파일 에러`\
547547` `\
548548`   apple := apples[0]; // works //잘 됨`\
549549`   apple := apples[1]; // not applicable //적용 안 됨`\
550550`   apple := apples[0] as TApple; // works, but unneccessary //필요하지 않지만, 잘 됨`\
551551`   apple := apples[1] as TApple; // not applicable //적용 안 됨`\
552552` end;`
553553
554554#### 제안 3
555555
556556` { Chu Jetcheng, 2008-07-24 }`
557557
558558` program Generics;`
559559
560560` type`\
561561`   { The compiler should maintain a global table storing each specialized type for each generic.  The `\
562562``      `of' operator is used to create a specialization for a specified generic type.  Specialized types  ``\
563563``      of the same `type layout' (no other words) point to the same entry in the table of specializations ``\
564564`     of the specialized generic type, and thus are compatible.  Generic objects and records should also `\
565565`     be allowed. }`\
566566``    { 컴파일러는 각 제너릭들을 위해 특별화된 선언형을 저장하는 전역 테이블을 유지해야만 합니다. `of' 연산자는 열거된 제너릭 선언들을 위해 ``\
567567``      특별하게 생성하려 사용되어졌습니다. 같은 `type layout'(다른 단어)의 특별화된 선언형들이 특별화된 제너릭 선언형의 테이블 안에 같은 ``\
568568`     entry를 가리키므로, 호환될 수 있습니다. 또한 제너릭 객체들과 레코드들은 허용해야 합니다}`
569569
570570`   TGeneric = generic class(TAncestorClass) of T1, T2`\
571571`   private`\
572572`     FData1: T1;`\
573573`     FData2: T2;`\
574574`   public`\
575575`     property Data1: T1 read FData1 write FData1;`\
576576`     property Data2: T2 read FData2 write FData2;`\
577577`     constructor Create(const A: T1; const B: T2);`\
578578`     procedure WriteData; virtual;`\
579579`   end;`
580580
581581`   TGenericDescendent = generic class(TGeneric of Integer, T3) of T3`\
582582`   private`\
583583`     FData3: T3;`\
584584`     FObjectOfSameType: TGenericDescendent of T3;`\
585585`   public`\
586586`     property Data3: T3 read FData3 write FData3;`\
587587`     property ObjectOfSameType: TGenericDescendent of T3 read FObjectOfSameType write FObjectOfSameType;`\
588588`     constructor Create(const C: T3);`\
589589`     procedure WriteData; override;`\
590590`   end;`
591591
592592`   TGenericIR = TGeneric of Integer, Real;`\
593593`   TGenericIRClass = class of TGenericIR;`
594594
595595`   TGenericISClass = class of (TGeneric of Integer, string);`
596596
597597`   PGenericObj = generic ^TGenericObj; `\
598598`   TGenericObj = generic object of T `\
599599`     MyField: T;`\
600600`     procedure WriteData;`\
601601`   end;`
602602
603603` { TGeneric }`
604604
605605` { Use the same syntax for method implementations as with immediate classes. }`\
606606` { 직접 클래스들과 함께로써 method 구현들을 위해 똑같은 문법을 사용합니다 }`
607607
608608` constructor TGeneric.Create(const A: T1; const B: T2);`\
609609` begin`\
610610`   FData1 := A;`\
611611`   FData2 := B;`\
612612` end;`
613613
614614` procedure TGeneric.WriteData;`\
615615` begin`\
616616`   Writeln(FData1);`\
617617`   Writeln(FData2);`\
618618` end;`
619619
620620` { TGenericDescendent }`
621621
622622` constructor TGenericDescendent.Create(const C: T3);`\
623623` begin`\
624624`   inherited Create(16, C);`\
625625`   FData3 := C;`\
626626` end;`
627627
628628` procedure TGenericDescendent.WriteData;`\
629629` begin`\
630630`   inherited;`\
631631`   Writeln(FData3);`\
632632`   if Assigned(FObjectOfSameType) then FObjectOfSameType.WriteData;`\
633633` end;`
634634
635635` { TGenericObj }`
636636
637637` procedure TGenericObj.WriteData;`\
638638` begin`\
639639`   Writeln(MyField);`\
640640` end;`
641641
642642` var `\
643643`   Obj1: TGeneric of Integer, Real;`\
644644`   Obj2, Obj3: TGenericDescendent of string;`\
645645`   OldStyleObj: TGenericObj of Integer;`\
646646`   OldStyleObjPtr: PGenericObj of Integer;`
647647
648648` begin`\
649649`   Obj1 := TGeneric.Create(32, 3.14);`\
650650`   Obj1.WriteData;`\
651651`   Writeln(#9, Obj1 is TGenericIR);`\
652652`   Writeln(#9, Obj1 is TGenericIS);`
653653
654654`   Obj2 := TGenericDescendent.Create('Generic test.');`\
655655`   Obj2.WriteData;`\
656656`   Writeln(#9, Obj2 is TGenericIR);`\
657657`   Writeln(#9, Obj2 is TGenericIS);`
658658
659659`   Obj3 := TGenericDescendent.Create('Another generic test.');`\
660660`   Obj3.ObjectOfSameType := Obj2;`\
661661`   Obj3.WriteData;`
662662
663663`   Obj3.Free;`\
664664`   Obj2.Free;`\
665665`   Obj1.Free;`
666666
667667`   OldStyleObj.MyField := 100;`\
668668`   OldStyleObj.WriteData;`
669669
670670`   OldStyleObjPtr := New(PGenericObj of Integer);`\
671671`   with OldStyleObjPtr^ do begin`\
672672`     MyField := 202;`\
673673`     WriteData;`\
674674`   end;`\
675675`   Dispose(ObjStyleObjPtr);`\
676676` end.`
677677
678678## Terms
679679
680680type user:
681681
682682- the function in the compiler that defines a variable or return type and thus 'uses a (already defined) type'.
683683
684684immediate type:
685685
686686- not generic and not specialized, i.e. 'normal type'
687687
688688generic type:
689689
690690- template for a class with some unspecified types, never to be filled in into this class type. Only by specialisation.
691691
692692specialization:
693693
694694- copy generic type class to new specialized type class
695695
696696type parameters:
697697
698698- T and Q, the unknown types for the generic TSomeGeneric\<T,Q\>
699699
700700specialized type:
701701
702702- a generic type with all type parameters know, written into a real class type (tree) and reused if possible
703703
704704## 변화들
705705
706706### class/record선언 표현 의 변화들
707707
708708Each class definition representation has added fields for:
709709
710710` - class instantiation mode`\
711711`    0  immediate type`\
712712`    1  generic type, no instantiation, just generate specialized type`\
713713`    2  specialized type`
714714
715715` - when mode 2:`\
716716`     generic type uplink (XXXX, what, unitname, typename?)`\
717717`   when mode 1:`\
718718`     list of specialized types known so far (and where),`\
719719`     XXXX list items`\
720720`   when mode 0: `\
721721`     nothing`
722722
723723### Changes in 'type user' compilation (for class/record types only)
724724
725725Each class type user will have to check mode of the class type.
726726
727727For the used class type, If mode is immediate
728728
729729` - proceed as always till now.`
730730
731731If mode is specialized
732732
733733` - proceed as always till now `\
734734` - keep in mind the generic type for some checks later (and debugging).`
735735
736736If mode is generic, this:
737737
738738` - check 'list of specialized types' for the type parameter to use.`\
739739`   If there is already a specialized type, use that.`\
740740`   (given that it is compatible with 'compile parameters' XXXX)`
741741
742742` - If not available, clone the generic type in the tree, and fill in the`\
743743`   type params with the actual types to use.`\
744744`   Generate machine code as normal.`\
745745`   Remember the new specialized type for later in the list by the `\
746746`   generic type and type params used.`
747747
748748(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)
749749
750750### type params
751751
752752Generics store a list of the type params (names).
753753
754754` ('T', 'Q')`
755755
756756And Specializations store a list of type mappings from the real types to the type params, in the way of
757757
758758` type`\
759759`   T = Integer;`\
760760`   Q = Boolean;`
761761
762762of course these are local to this class/record specialization.
763763
764764## Other things to note (for *later*)
765765
766766### What if a method implementation depends on the type used to know how the implementation should look like ?
767767
768768` procedure GList<T is TObject>.Add(const value: T);`\
769769` procedure GList<T is Integer>.Add(const value: T);`\
770770` ?`
771771
772772or more cryptic like
773773
774774` procedure GList<TObject>.Add(const value: T);`\
775775` procedure GList<Integer>.Add(const value: T);`\
776776` ?`
777777
778778or like
779779
780780` procedure GList<T>.Add(const value: Integer);`\
781781` procedure GList<T>.Add(const value: TObject);`
782782
783783the latter would need extra compiler support but would be nicer, overall. Potentially clashing with normal overloads though.
784784
785785### How to do internal storage classes
786786
787787` type`\
788788` PNode<T> = ^TNode<T>;`\
789789` TNode<T> = record`\
790790`   prev,next: PNode<T>;`\
791791`   data: T;`\
792792` end;`
793793
794794` type`\
795795` GList<T> = class`\
796796` private`\
797797`   head, tail: PNode<T>;`\
798798`   cnt: Integer;`\
799799` public`\
800800`   procedure Add(const stuff: T);`\
801801` end;`\
802802` ?`
803803
804804This implies that generics are best implemented both for records and for classes alike! Also implies that pointer types need to support generic too.
805805
806806Also one specialization should chain other specializations (probably also when deriving from a generic).
807807
808808### How to derive from the generic type
809809
810810It would be good if generic types could be derived from.
811811
812812` type`\
813813` TGenericEventyList<T> = class(TGenericList<T>)`\
814814` public`\
815815`   procedure Add(value: T); override;`\
816816` end;`\
817817` ...`
818818
819819### Interfaces should support generics too
820820
821821` type`\
822822` IBa<T> = interface`\
823823`   procedure Add(value: T);`\
824824` end;`\
825825` TBa<T> = class(...,IBla<T>,IInterface)`\
826826` end;`
827827
828828(what to do about the guids of the specializations? probably just generate whatever, they dont have any real meaning after all)
829829
830830Of course this has limitations to check, like
831831
832832- the generic interface cannot be used, just its specializations
833833- the specialized interface cannot be used in a generic class interface list
834834- (the generic interface can be used in a generic class interface list)
835835- the generic interface itself is invalid to use anywhere (just as generic classes are) except for specializing and deriving from
836836- normal interfaces cannot derive from generic interfaces
837837- (generic interfaces can derive from generic interfaces) - given the type params are the same
838838- specialized interfaces cannot be derived from
839839
840840### Limitation of possible specialisations
841841
842842` type`\
843843` TGenericList<T: TObject or Integer> = ...`\
844844` end;`
845845
846846Probably useful...
847847
848848### What to do with class functions
849849
850850I dont know a whole lot of how class functions are stored internally. What happens to class functions in generics?
851851
852852### 'class of'
853853
854854\<Almindor\> don't forget class of, we need class of compatibility for dynamic class factories
855855
856856\<Almindor\> There are possible problems with 'class of'
857857
858858## Implementation details
859859
860860### Sanity checks
861861
862862- Generic types cannot be instantiated from
863863- (Generic types can be derived from)
864864- Specialized types cannot be derived from
865865- Normal types cannot use generic types in its definition
866866- (Normal types can use specialized types in its definition)
867867- There are no half specialized types (one type param specified, the other not)
868868- prevent loops while 'unpacking' specializations (loop counter field in every specialization)
869869
870870### Things to note and not forgot
871871
872872- class와 record 제너릭은 그 선언 안에서 그 자신을 선언형으로 사용할 수 있습니다
873873
874874예:
875875
876876` type`\
877877` TBla<T> = class`\
878878`   parent: TBla<T>;`\
879879` end;`
880880
881881- class와 record 제너릭은 그 선언 안에서 다른 제너릭을 선언형으로 사용할 수 있습니다
882882
883883` type`\
884884` TBla<T> = class`\
885885`   parent: TBlo<T>;`\
886886` end;`
887887
888888## Implementation steps
889889
890890### Extend parser to support '\<T\>' and '\<T: bla or bla or bla\>' and '\<T,Q\>' notation
891891
892892Easy to do. Done.
893893
894894## Different ways to do it, one excluding the other
895895
896896### Way 1
897897
898898#### Change class/record/object/pointertype/interface parser to mark if it is a generic, a specialization or normal
899899
900900Mediate 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.
901901
902902#### insert dummy symbols (typesym + typedef) for the type params in the generic
903903
904904Cannot be inserted into the object because parsing of types within objects has been disabled to make that possible:
905905
906906` type`\
907907` Row = Cardinal;`\
908908` TBla = class `\
909909`   Row: Integer;`\
910910` end;`
911911
912912weird.. (function searchsym_type, is not possible to have type definitions in records, objects, parameters)
913913
914914#### parse implementation section methods *for the generic*
915915
916916Is 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).
917917
918918#### when parsing generics, use a dummy type in place of the type params
919919
920920For that, defer the type checking of the compiler in that case to 'as late as possible' or 'never for the generic' \<--- TODO... hard...
921921
922922#### Change derivation handlers to do the sanity checks
923923
924924Should pose no problems other than finding all the places.
925925
926926#### Add error messages for it
927927
928928#### Change pexpr (tnode creating)
929929
930930\<Synopsis+\> see the do_resulttypepass() calls in pexpr.pas But the compiler needs to known for example if it allows a . after the type
931931
932932- 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).
933933
934934Examples for postfix operators are:
935935
936936- '\[\]' array member access (normal array, class default array property?)
937937
938938- '.' record/class member method/variable access
939939
940940- '^' pointer dereference
941941
942942- (automatic pointer dereference)
943943
944944\<Synopsis\> grep for m_auto and you'll find the places where it is used \<Synopsis\> only in pexpr.pas
945945
946946#### Change ppu streaming routines to save the tree of generics to the ppu
947947
948948#### Change type user to instantiate specialized types for generics when used
949949
950950Somewhat hard to do. (main work here :))
951951
952952For the instantiation
953953
954954- there is a dummy type sym needed (ok),
955955- a new objectdef
956956- clone of all the syms and defs (at least proc and property) of the original class/object
957957- and replacing all the type params by the correct types.
958958- Store that into the module as def (not on disk).
959959- (\<Synopsis+\> an additional symtable shall be added to tmodule: tempsymtable; all temporary tdef's shall be stored in that symtable)
960960- Then resume compiling for the class/object.
961961
962962### Way 2
963963
964964just 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'
965965
966966#### Notes
967967
968968\<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.
969969
970970\<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
971971
972972\<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.
973973
974974fpk has patches to make cloning defs possible.
975975
97697601:28:24 \<Synopsis+\> users will complain; things like:
977977
978978` interface`\
979979`   generictype declar`\
980980` implementation`\
981981`   procedure helper;`\
982982`   begin`\
983983`   end`\
984984`   constructor generictype.create`\
985985`   begin`\
986986`     helper`\
987987`   end`\
988988` end.`
989989
990990Will not be allowed.
991991
992992Another problem:
993993
994994` unit a;`\
995995` interface`\
996996`   generictypeA`\
997997` implementation`\
998998` uses B`\
999999` end.`
10001000
10011001` unit b;`\
10021002` interface`\
10031003` uses a`\
10041004` implemenation`\
10051005` begin`\
10061006`   generictypeA<integer>.craete`\
10071007` end.`
10081008
10091009At 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.
10101010
10111011\<fpk-\> dannym, Synopsis: we can simply forbid such code in generics which cause the problem
10121012
10131013\<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 :)
10141014
10151015\<Synopsis+\> fpk had a good idea that can solve some of the issues: unit bla; interface ... generics ... implementation ... initialisation ... finalizatrion end.
10161016
10171017\<Synopsis+\> The generics delcarations shall be put in a separate section before implementation is parsed
10181018
10191019\<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 ?
10201020
10211021\<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.
10221022
10231023` { for records, don't search the recordsymtable for the symbols of the types }`\
10241024` oldsymtablestack:=symtablestack;`\
10251025` symtablestack:=symtablestack.next;`
10261026
10271027Because you can have a field with the same name as a type
10281028
10291029` type`\
10301030` Wrd = Word;`\
10311031` R = Record`\
10321032`   Wrd : Wrd;`\
10331033` end`
10341034
10351035this is allowed. To support this the record or object symtable is remvoed from the symtablestack when the type is parsed.
10361036
10371037## 이미 존재하는 것
10381038
10391039### 메타 클래스
10401040
10411041` type`\
10421042` TObjectClass = class of TObject;`\
10431043` TTypedList = class`\
10441044` private`\
10451045`   Fwanttype: TObjectClass;`\
10461046`   ...`\
10471047` public`\
10481048`   constructor Create(itemtype: TObjectClass);`\
10491049`   procedure Add(item: TObject);`\
10501050`   ...`\
10511051` end;`\
10521052` constructor TTypedList.Create(itemtype: TObjectClass);`\
10531053` begin`\
10541054`   Fwanttype := itemtype;`\
10551055`   ...`\
10561056` end;`\
10571057` procedure TTypedList.Add(item: TObject);`\
10581058` begin`\
10591059`   assert(item.Class = Fwanttype);`\
10601060`   ...`\
10611061` end;`
10621062
10631063` ...`\
10641064` TSomeStuff = class`\
10651065` end;`\
10661066` ...`\
10671067` Flist := TTypedList.Create(TSomeStuff);`
10681068
10691069장점
10701070
10711071- 이미 구현되어 있음
10721072
10731073단점
10741074
10751075- runtime 때 느림
10761076- 간단한 선언형을 만들 수 없음.
10771077- 지원되는 선언형들에서도 모든 time에 변환(type-casting)이 필요합니다(다시말하면, 읽을때에도)
10781078
10791079## 여기서 부터 통합됩니다
10801080
10811081### 채팅 내용
10821082
10831083\<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>
10841084
10851085---
10861086*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