Sign in Join
Wiki copytemporary

default properties: what changed

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

OldNewLine
1-Default properties allow "hoisting" or exposing of object members into the caller name space to facilitate wrapper types and (possibly) delegation patterns. They could be seen as "with" statements which encompass an entire structures namespace.
2-
3-This feature is under development and everything is subject to change.
4-
5-## Contents
1+Default properties allow "hoisting" or exposing of object members into the caller name space to facilitate wrapper types and (possibly) delegation patterns. They could be seen as "with" statements which encompass an entire structures namespace.
62
7- * 1 Download Development Branch
8- * 2 Supports
9- * 3 Hoisting Members
10- * 4 Precedence Rules
11- * 5 Passing
12- * 6 Assignment Rules
13- * 7 Multiple Defaults
14- * 8 Hiding Fields
15- * 9 Examples Usages
16- * 9.1 Nullable types
17- * 9.2 Auto managed classes using management operators
18- * 9.3 Array indexing
19- * 9.4 Delegation
20- * 9.5 Default "Implements" Properties
21- * 10 COMPILER: Implemention Details
3+This feature is under development and everything is subject to change.
224
235## Download Development Branch
246
257<https://github.com/genericptr/freepascal/tree/defaultprops>
268
279## Supports
2810
29- * records, objects, classes.
30- * arithmetic, compare, binary, unary, in overloads. (<https://www.freepascal.org/docs-html/ref/refch15.html>)
31- * visibility sections.
32- * array indexing with []
33- * if, while, repeat, case, for..do statements
11+- records, objects, classes.
12+- arithmetic, compare, binary, unary, in overloads. (https://www.freepascal.org/docs-html/ref/refch15.html)
13+- visibility sections.
14+- array indexing with \[\]
15+- if, while, repeat, case, for..do statements
3416
3517## Hoisting Members
3618
37-By making "m_obj" a default property we can omit m_obj. to subscript into the members. This is like wrapping every instance of "m_obj" in a "with" statement. This makes it possible to bring members from other structures into the current structure without prefixing "m_obj." before accessing fields.
38-```
39-type
40- THelper = record
41- num: integer;
42- end;
43-
44- type
45- TWrapper = record
46- m_obj: THelper;
47- property helper: THelper read m_obj; default;
48- procedure Inc;
49- end;
50-
51- procedure TWrapper.Inc;
52- begin
53- num += 1;
54- end;
55-
56- var
57- wrapper: TWrapper;
58- begin
59- wrapper.num := 100;
60- wrapper.Inc;
61- writeln(wrapper.num);
62- end.
19+By making "m_obj" a default property we can omit m_obj. to subscript into the members. This is like wrapping every instance of "m_obj" in a "with" statement. This makes it possible to bring members from other structures into the current structure without prefixing "m_obj." before accessing fields.
20+
21+``` pascal
22+ type
23+ THelper = record
24+ num: integer;
25+ end;
26+
27+ type
28+ TWrapper = record
29+ m_obj: THelper;
30+ property helper: THelper read m_obj; default;
31+ procedure Inc;
32+ end;
33+
34+ procedure TWrapper.Inc;
35+ begin
36+ num += 1;
37+ end;
38+
39+ var
40+ wrapper: TWrapper;
41+ begin
42+ wrapper.num := 100;
43+ wrapper.Inc;
44+ writeln(wrapper.num);
45+ end.
6346```
6447
6548## Precedence Rules
6649
67-For default properties which are structures (objects, records, classes) it's possible to have method overloads in both the base structure and the default property (or unit scope even). For this reason overload resolution must follow a predicable pattern.
50+For default properties which are structures (objects, records, classes) it's possible to have method overloads in both the base structure and the default property (or unit scope even). For this reason overload resolution must follow a predicable pattern.
6851
69-Precedence order for overloads is as follows: base, default (last to first).
70-```
71-type
72- THelper = class
73- num: integer;
74- procedure DoThis; overload;
75- procedure DoThis (param: integer); overload;
76- procedure DoThis (param: string); overload;
77- end;
78-
79- procedure THelper.DoThis;
80- begin
81- writeln('THelper.DoThis:',num);
82- end;
83-
84- procedure THelper.DoThis (param: integer);
85- begin
86- writeln('THelper.DoThis:',param,':',num);
87- end;
88-
89- procedure THelper.DoThis (param: string);
90- begin
91- writeln('THelper.DoThis:',param,':',num);
92- end;
93-
94- type
95- TParent = class
96- m_helper: THelper;
97- property helper: THelper read m_helper; default;
98- procedure DoThis (param:single);overload;
99- end;
100-
101- procedure TParent.DoThis (param:single);
102- begin
103- writeln('TParent.DoThis:',param:1:1);
104- end;
105-
106- type
107- TMyObject = class (TParent)
108- procedure Call;
109- procedure DoThis;overload;
110- end;
111-
112- procedure TMyObject.DoThis;
113- begin
114- writeln('TMyObject.DoThis');
115- end;
116-
117- procedure TMyObject.Call;
118- begin
119- DoThis(100); // THelper.DoThis
120- DoThis(10.5); // TParent.DoThis
121- DoThis('hello'); // THelper.DoThis
122- DoThis; // TMyObject.DoThis
123- end;
124-
125- var
126- obj: TMyObject;
127- begin
128- obj := TMyObject.Create;
129- obj.m_helper := THelper.Create;
130- obj.Call;
131- end.
132-```
52+Precedence order for overloads is as follows: base, default (last to first).
13353
134-Operator overloads are possible also. Precedence can get complicated considering it's possible to have overloads in the current unit for the default type as well as overloads in the structure itself.
135-```
136-operator + (l : integer; r : ansistring): integer;
137- begin
138- result := l + StrToInt(r);
139- end;
140-
141- type
142- TWrapper = record
143- m_value: integer;
144- property value: integer read m_value write m_value; default;
145- end;
146-
147- var
148- wrapper: TWrapper;
149- begin
150- wrapper += 1; // default property takes precedence
151- wrapper += '128'; // unit + operator takes precedence because default property type (integer) doesn't support string overloads
152- writeln(wrapper.value); // 129
153- if wrapper = 129 then // = operator works also
154- writeln('got 129');
155- end.
54+``` pascal
55+ type
56+ THelper = class
57+ num: integer;
58+ procedure DoThis; overload;
59+ procedure DoThis (param: integer); overload;
60+ procedure DoThis (param: string); overload;
61+ end;
62+
63+ procedure THelper.DoThis;
64+ begin
65+ writeln('THelper.DoThis:',num);
66+ end;
67+
68+ procedure THelper.DoThis (param: integer);
69+ begin
70+ writeln('THelper.DoThis:',param,':',num);
71+ end;
72+
73+ procedure THelper.DoThis (param: string);
74+ begin
75+ writeln('THelper.DoThis:',param,':',num);
76+ end;
77+
78+ type
79+ TParent = class
80+ m_helper: THelper;
81+ property helper: THelper read m_helper; default;
82+ procedure DoThis (param:single);overload;
83+ end;
84+
85+ procedure TParent.DoThis (param:single);
86+ begin
87+ writeln('TParent.DoThis:',param:1:1);
88+ end;
89+
90+ type
91+ TMyObject = class (TParent)
92+ procedure Call;
93+ procedure DoThis;overload;
94+ end;
95+
96+ procedure TMyObject.DoThis;
97+ begin
98+ writeln('TMyObject.DoThis');
99+ end;
100+
101+ procedure TMyObject.Call;
102+ begin
103+ DoThis(100); // THelper.DoThis
104+ DoThis(10.5); // TParent.DoThis
105+ DoThis('hello'); // THelper.DoThis
106+ DoThis; // TMyObject.DoThis
107+ end;
108+
109+ var
110+ obj: TMyObject;
111+ begin
112+ obj := TMyObject.Create;
113+ obj.m_helper := THelper.Create;
114+ obj.Call;
115+ end.
156116```
157117
158-Type helpers behave as normal on the default type.
118+Operator overloads are possible also. Precedence can get complicated considering it's possible to have overloads in the current unit for the default type as well as overloads in the structure itself.
119+
120+``` pascal
121+ operator + (l : integer; r : ansistring): integer;
122+ begin
123+ result := l + StrToInt(r);
124+ end;
125+
126+ type
127+ TWrapper = record
128+ m_value: integer;
129+ property value: integer read m_value write m_value; default;
130+ end;
131+
132+ var
133+ wrapper: TWrapper;
134+ begin
135+ wrapper += 1; // default property takes precedence
136+ wrapper += '128'; // unit + operator takes precedence because default property type (integer) doesn't support string overloads
137+ writeln(wrapper.value); // 129
138+ if wrapper = 129 then // = operator works also
139+ writeln('got 129');
140+ end.
159141```
160-type
161- TIntegerHelper = type helper for integer
162- function Str: string;
163- end;
164-
165- function TIntegerHelper.Str: string;
166- begin
167- result := 'string->'+IntToStr(self);
168- end;
169-
170- type
171- TWrapper = record
172- m_value: integer;
173- property value: integer read m_value write m_value; default;
174- end;
175-
176- var
177- wrapper: TWrapper;
178- begin
179- wrapper := 100;
180- writeln(wrapper.str);
181- end.
142+
143+Type helpers behave as normal on the default type.
144+
145+``` pascal
146+ type
147+ TIntegerHelper = type helper for integer
148+ function Str: string;
149+ end;
150+
151+ function TIntegerHelper.Str: string;
152+ begin
153+ result := 'string->'+IntToStr(self);
154+ end;
155+
156+ type
157+ TWrapper = record
158+ m_value: integer;
159+ property value: integer read m_value write m_value; default;
160+ end;
161+
162+ var
163+ wrapper: TWrapper;
164+ begin
165+ wrapper := 100;
166+ writeln(wrapper.str);
167+ end.
182168```
183169
184170## Passing
185171
186-Passing a structure with default properties follows normal move semantics. For example, if there is a record with a default property of the type "integer" passing the record will not copy the integer value but rather the entire record will be passed.
187-```
188-type
189- TIntRec = record
190- m_int: integer;
191- property value: integer read m_obj; default;
192- end;
193-
194- procedure Print (int: TIntRec); overload;
195- begin
196- writeln(int.value);
197- end;
198-
199- procedure Print (int: integer); overload;
200- begin
201- writeln(int);
202- end;
203-
204- var
205- int: TIntRec;
206- begin
207- int := 100;
208- Print(int); // Print(TIntRec) is called
209- writeln(int) // ERROR: can't write this type (TIntRec)
210- end.
172+Passing a structure with default properties follows normal move semantics. For example, if there is a record with a default property of the type "integer" passing the record will not copy the integer value but rather the entire record will be passed.
173+
174+``` pascal
175+ type
176+ TIntRec = record
177+ m_int: integer;
178+ property value: integer read m_obj; default;
179+ end;
180+
181+ procedure Print (int: TIntRec); overload;
182+ begin
183+ writeln(int.value);
184+ end;
185+
186+ procedure Print (int: integer); overload;
187+ begin
188+ writeln(int);
189+ end;
190+
191+ var
192+ int: TIntRec;
193+ begin
194+ int := 100;
195+ Print(int); // Print(TIntRec) is called
196+ writeln(int) // ERROR: can't write this type (TIntRec)
197+ end.
211198```
212199
213200## Assignment Rules
214201
215-Default properties introduce an ambiguity with assignments which is resolved by type.
216-```
217-type
218- TWrapper = class
219- m_value: integer;
220- m_string: string;
221- property value: integer read m_value write m_value; default;
222- end;
223-
224- var
225- wrapper: TWrapper;
226- begin
227- wrapper := TWrapper.Create; // TWrapper is same type so assignment is as normal
228- wrapper := 100; // integer matches "value"
229- writeln(wrapper.value);
230- end.
202+Default properties introduce an ambiguity with assignments which is resolved by type.
203+
204+``` pascal
205+ type
206+ TWrapper = class
207+ m_value: integer;
208+ m_string: string;
209+ property value: integer read m_value write m_value; default;
210+ end;
211+
212+ var
213+ wrapper: TWrapper;
214+ begin
215+ wrapper := TWrapper.Create; // TWrapper is same type so assignment is as normal
216+ wrapper := 100; // integer matches "value"
217+ writeln(wrapper.value);
218+ end.
231219```
232220
233221## Multiple Defaults
234222
235-Currently for development default properties are "multidimensional", meaning you can declare more than one per type and overloads will be resolved according to precedence.
223+Currently for development default properties are "multidimensional", meaning you can declare more than one per type and overloads will be resolved according to precedence.
236224
237-They have been developed this way from the outset because the nature of the search is inherently multidimensional, i.e base object, default property 1, default property 2 etc... so I wanted to keep the option available while the concept is being explored.
225+They have been developed this way from the outset because the nature of the search is inherently multidimensional, i.e base object, default property 1, default property 2 etc... so I wanted to keep the option available while the concept is being explored.
238226
239-This is of course a highly contested idea given the capacity to introduce difficult to understand namespace collisions.
227+This is of course a highly contested idea given the capacity to introduce difficult to understand namespace collisions.
240228
241229## Hiding Fields
242230
243-If multiple defaults are allowed then it would be possible to hide fields from other default properties and cause some potential bugs.
244-```
245-type
246- THelper = record
247- data: integer;
248- end;
249-
250- type
251- TWrapper = record
252- m_objA: THelper;
253- m_objB: THelper;
254- property helperA: THelper read m_objA; default;
255- property helperB: THelper read m_objB; default;
256- end;
257-
258- var
259- wrapper: TWrapper;
260- begin
261- wrapper.data := 1;
262- writeln('helperA:',wrapper.helperA.data); // 0
263- writeln('helperB:',wrapper.helperB.data); // 1
264- end.
231+If multiple defaults are allowed then it would be possible to hide fields from other default properties and cause some potential bugs.
232+
233+``` pascal
234+ type
235+ THelper = record
236+ data: integer;
237+ end;
238+
239+ type
240+ TWrapper = record
241+ m_objA: THelper;
242+ m_objB: THelper;
243+ property helperA: THelper read m_objA; default;
244+ property helperB: THelper read m_objB; default;
245+ end;
246+
247+ var
248+ wrapper: TWrapper;
249+ begin
250+ wrapper.data := 1;
251+ writeln('helperA:',wrapper.helperA.data); // 0
252+ writeln('helperB:',wrapper.helperB.data); // 1
253+ end.
265254```
266255
267256## Examples Usages
268257
269258### Nullable types
270-```
271-type
272- generic TNullable<T>= record
273- private
274- FValue : T;
275- public
276- isAssigned : boolean;
277- function IsNull: boolean;
278- procedure SetValue (newValue: T);
279- Property Value : T read FValue write SetValue; default;
280- class operator Initialize(var a: TNullable);
281- end;
282-
283- procedure TNullable.SetValue (newValue: T);
284- begin
285- FValue := newValue;
286- isAssigned := true;
287- end;
288-
289- function TNullable.IsNull: boolean;
290- begin
291- result := not isAssigned;
292- end;
293-
294- class operator TNullable.Initialize(var a: TNullable);
295- begin
296- a.isAssigned := Default(T);
297- end;
298-
299- type
300- TBoolean = specialize TNullable<boolean>;
301- Var
302- bool: TBoolean;
303- begin
304- bool := true;
305- if bool then
306- writeln('bool is true');
307- end.
259+
260+``` pascal
261+ type
262+ generic TNullable<T>= record
263+ private
264+ FValue : T;
265+ public
266+ isAssigned : boolean;
267+ function IsNull: boolean;
268+ procedure SetValue (newValue: T);
269+ Property Value : T read FValue write SetValue; default;
270+ class operator Initialize(var a: TNullable);
271+ end;
272+
273+ procedure TNullable.SetValue (newValue: T);
274+ begin
275+ FValue := newValue;
276+ isAssigned := true;
277+ end;
278+
279+ function TNullable.IsNull: boolean;
280+ begin
281+ result := not isAssigned;
282+ end;
283+
284+ class operator TNullable.Initialize(var a: TNullable);
285+ begin
286+ a.isAssigned := Default(T);
287+ end;
288+
289+ type
290+ TBoolean = specialize TNullable<boolean>;
291+ Var
292+ bool: TBoolean;
293+ begin
294+ bool := true;
295+ if bool then
296+ writeln('bool is true');
297+ end.
308298```
309299
310300### Auto managed classes using management operators
311-```
312-type
313- generic TAuto<T> = record
314- private
315- m_object: T;
316- class operator Initialize(var a: TAuto);
317- class operator Finalize(var a: TAuto);
318- public
319- property obj: T read m_object; default;
320- end;
321-
322- type
323- TStringList = specialize TFPGList<String>;
324- TStringListAuto = specialize TAuto<TStringList>;
325-
326- class operator TAuto.Initialize(var a: TAuto);
327- begin
328- a.m_object := T.Create;
329- end;
330-
331- class operator TAuto.Finalize(var a: TAuto);
332- begin
333- a.m_object.Free;
334- end;
335-
336- var
337- list: TStringListAuto;
338- str: string;
339- begin
340- list.Add('foo');
341- list.Add('bar');
342- for str in list do
343- writeln(str);
344- end.
301+
302+``` pascal
303+ type
304+ generic TAuto<T> = record
305+ private
306+ m_object: T;
307+ class operator Initialize(var a: TAuto);
308+ class operator Finalize(var a: TAuto);
309+ public
310+ property obj: T read m_object; default;
311+ end;
312+
313+ type
314+ TStringList = specialize TFPGList<String>;
315+ TStringListAuto = specialize TAuto<TStringList>;
316+
317+ class operator TAuto.Initialize(var a: TAuto);
318+ begin
319+ a.m_object := T.Create;
320+ end;
321+
322+ class operator TAuto.Finalize(var a: TAuto);
323+ begin
324+ a.m_object.Free;
325+ end;
326+
327+ var
328+ list: TStringListAuto;
329+ str: string;
330+ begin
331+ list.Add('foo');
332+ list.Add('bar');
333+ for str in list do
334+ writeln(str);
335+ end.
345336```
346337
347338### Array indexing
348339
349-Because it is technically possible arrays are exposed using default properties. This however does conflict with the existing [] indexer properties so this may be a problem.
340+Because it is technically possible arrays are exposed using default properties. This however does conflict with the existing \[\] indexer properties so this may be a problem.
350341
351-As it stands however default properties on array types are an interesting method to make array wrappers.
352-```
353-type
354- TIntArray = array of integer;
355- TWrapper = record
356- m_value: TIntArray;
357- property value: TIntArray read m_value write m_value; default;
358- end;
359-
360- var
361- wrapper: TWrapper;
362- i: integer;
363- begin
364- wrapper := TIntArray.Create(100,200,300); // NOTE: we can't use array constructors [] due to bug in compiler
365- wrapper[0] += 50;
366- wrapper[1] += 1;
367- for i in wrapper do
368- writeln(i);
369- end.
342+As it stands however default properties on array types are an interesting method to make array wrappers.
343+
344+``` pascal
345+ type
346+ TIntArray = array of integer;
347+ TWrapper = record
348+ m_value: TIntArray;
349+ property value: TIntArray read m_value write m_value; default;
350+ end;
351+
352+ var
353+ wrapper: TWrapper;
354+ i: integer;
355+ begin
356+ wrapper := TIntArray.Create(100,200,300); // NOTE: we can't use array constructors [] due to bug in compiler
357+ wrapper[0] += 50;
358+ wrapper[1] += 1;
359+ for i in wrapper do
360+ writeln(i);
361+ end.
370362```
371363
372364### Delegation
373365
374-If delegate properties are allowed be multidimensional in the final version they can be used for delegation patterns that would otherwise only be possible with multiple inheritance (in languages such as C++, Java).
375-```
376-type
377- TStats = record
378- hp: integer;
379- exp: integer;
380- procedure InitStats;
381- end;
382-
383- // Base Module:
384-
385- type
386- TEntity = class;
387- TBaseHandler = class
388- entity: TEntity;
389- constructor Create (inEntity: TEntity);
390- procedure Clear;
391- end;
392-
393- // Physics Module:
394-
395- TPhysicsHandler = class (TBaseHandler)
396- pos: TVec3;
397- acc: TVec3;
398- vel: TVec3;
399- procedure Integrate; virtual;
400- end;
401-
402- // Renderer Module:
403-
404- TRendererHandler = class (TBaseHandler)
405- procedure Render; virtual;
406- end;
407-
408- // Entity:
409-
410- TEntity = class
411- private
412- m_physics: TPhysicsHandler;
413- m_renderer: TRendererHandler;
414- m_stats: TStats;
415- public
416- property physics: TPhysicsHandler read m_physics; default;
417- property renderer: TRendererHandler read m_renderer; default;
418- property stats: TStats read m_stats; default;
419- public
420- procedure Update;
421- end;
422-
423- // Implemention:
424-
425- type
426- TMonster = class (TEntity)
427- public
428- procedure AfterConstruction; override;
429- end;
430-
431- type
432- TMonsterRenderer = class (TRendererHandler)
433- procedure Render; override;
434- end;
435-
436- procedure TStats.InitStats;
437- begin
438- hp := 100;
439- exp := 0;
440- end;
441-
442- procedure TBaseHandler.Clear;
443- begin
444- writeln(classname,' clear');
445- end;
446-
447- constructor TBaseHandler.Create (inEntity: TEntity);
448- begin
449- entity := inEntity;
450- end;
451-
452- procedure TPhysicsHandler.Integrate;
453- begin
454- pos.x += vel.x;
455- pos.y += vel.y;
456- pos.z += vel.z;
457- end;
458-
459- procedure TRendererHandler.Render;
460- begin
461- end;
462- RSS
463- procedure TEntity.Update;
464- begin
465- Integrate;
466- Render;
467- end;
468-
469- procedure TMonster.AfterConstruction;
470- begin
471- m_physics := TPhysicsHandler.Create(self);
472- m_renderer := TMonsterRenderer.Create(self);
473-
474- InitStats;
475-
476- vel.x := 80;
477- vel.y := 20;
478- vel.z := 0;
479- end;
480-
481- procedure TMonsterRenderer.Render;
482- begin
483- writeln('render monster at ', entity.pos.str, ' hp:', entity.hp);
484- end;
485-
486- var
487- entity: TMonster;
488- i: integer;
489- begin
490- entity := TMonster.Create;
491- entity.Clear;
492- for i := 0 to 2 do
493- entity.Update;
494- end.
366+If delegate properties are allowed be multidimensional in the final version they can be used for delegation patterns that would otherwise only be possible with multiple inheritance (in languages such as C++, Java).
367+
368+``` pascal
369+
370+ type
371+ TStats = record
372+ hp: integer;
373+ exp: integer;
374+ procedure InitStats;
375+ end;
376+
377+ // Base Module:
378+
379+ type
380+ TEntity = class;
381+ TBaseHandler = class
382+ entity: TEntity;
383+ constructor Create (inEntity: TEntity);
384+ procedure Clear;
385+ end;
386+
387+ // Physics Module:
388+
389+ TPhysicsHandler = class (TBaseHandler)
390+ pos: TVec3;
391+ acc: TVec3;
392+ vel: TVec3;
393+ procedure Integrate; virtual;
394+ end;
395+
396+ // Renderer Module:
397+
398+ TRendererHandler = class (TBaseHandler)
399+ procedure Render; virtual;
400+ end;
401+
402+ // Entity:
403+
404+ TEntity = class
405+ private
406+ m_physics: TPhysicsHandler;
407+ m_renderer: TRendererHandler;
408+ m_stats: TStats;
409+ public
410+ property physics: TPhysicsHandler read m_physics; default;
411+ property renderer: TRendererHandler read m_renderer; default;
412+ property stats: TStats read m_stats; default;
413+ public
414+ procedure Update;
415+ end;
416+
417+ // Implemention:
418+
419+ type
420+ TMonster = class (TEntity)
421+ public
422+ procedure AfterConstruction; override;
423+ end;
424+
425+ type
426+ TMonsterRenderer = class (TRendererHandler)
427+ procedure Render; override;
428+ end;
429+
430+ procedure TStats.InitStats;
431+ begin
432+ hp := 100;
433+ exp := 0;
434+ end;
435+
436+ procedure TBaseHandler.Clear;
437+ begin
438+ writeln(classname,' clear');
439+ end;
440+
441+ constructor TBaseHandler.Create (inEntity: TEntity);
442+ begin
443+ entity := inEntity;
444+ end;
445+
446+ procedure TPhysicsHandler.Integrate;
447+ begin
448+ pos.x += vel.x;
449+ pos.y += vel.y;
450+ pos.z += vel.z;
451+ end;
452+
453+ procedure TRendererHandler.Render;
454+ begin
455+ end;
456+ RSS
457+ procedure TEntity.Update;
458+ begin
459+ Integrate;
460+ Render;
461+ end;
462+
463+ procedure TMonster.AfterConstruction;
464+ begin
465+ m_physics := TPhysicsHandler.Create(self);
466+ m_renderer := TMonsterRenderer.Create(self);
467+
468+ InitStats;
469+
470+ vel.x := 80;
471+ vel.y := 20;
472+ vel.z := 0;
473+ end;
474+
475+ procedure TMonsterRenderer.Render;
476+ begin
477+ writeln('render monster at ', entity.pos.str, ' hp:', entity.hp);
478+ end;
479+
480+ var
481+ entity: TMonster;
482+ i: integer;
483+ begin
484+ entity := TMonster.Create;
485+ entity.Clear;
486+ for i := 0 to 2 do
487+ entity.Update;
488+ end.
495489```
496490
497491### Default "Implements" Properties
498492
499-"implements" properties are more complete by exposing their namespace using "default". If multiple defaults are allowed one could imagine this being a possible method to implement multiple inheritance in Pascal.
500-```
501-type
502- IWrapper = interface ['IWrapper']
503- procedure DoThis;
504- end;
505-
506- type
507- TWrapper_Handler = class (IWrapper)
508- procedure DoThis;
509- end;
510-
511- procedure TWrapper_Handler.DoThis;
512- begin
513- writeln('TWrapper_Handler.DoThis');
514- end;
515-
516- type
517- TWrapper = class (IWrapper)
518- m_wrapper: TWrapper_Handler;
519- property handler: TWrapper_Handler read m_wrapper implements IWrapper; default;
520- procedure AfterConstruction; override;
521- end;
522-
523- procedure TWrapper.AfterConstruction;
524- begin
525- m_wrapper := TWrapper_Handler.Create;
526- end;
527-
528- procedure HandleWrapper (wrapper: IWrapper);
529- begin
530- wrapper.DoThis;
531- end;
532-
533- var
534- wrapper: TWrapper;
535- begin
536- wrapper := TWrapper.Create;
537- HandleWrapper(wrapper);
538- end.
493+"implements" properties are more complete by exposing their namespace using "default". If multiple defaults are allowed one could imagine this being a possible method to implement multiple inheritance in Pascal.
494+
495+``` pascal
496+ type
497+ IWrapper = interface ['IWrapper']
498+ procedure DoThis;
499+ end;
500+
501+ type
502+ TWrapper_Handler = class (IWrapper)
503+ procedure DoThis;
504+ end;
505+
506+ procedure TWrapper_Handler.DoThis;
507+ begin
508+ writeln('TWrapper_Handler.DoThis');
509+ end;
510+
511+ type
512+ TWrapper = class (IWrapper)
513+ m_wrapper: TWrapper_Handler;
514+ property handler: TWrapper_Handler read m_wrapper implements IWrapper; default;
515+ procedure AfterConstruction; override;
516+ end;
517+
518+ procedure TWrapper.AfterConstruction;
519+ begin
520+ m_wrapper := TWrapper_Handler.Create;
521+ end;
522+
523+ procedure HandleWrapper (wrapper: IWrapper);
524+ begin
525+ wrapper.DoThis;
526+ end;
527+
528+ var
529+ wrapper: TWrapper;
530+ begin
531+ wrapper := TWrapper.Create;
532+ HandleWrapper(wrapper);
533+ end.
539534```
540535
541536## COMPILER: Implemention Details
542537
543-Default properties are implemented primarily at the parser layer and overloads (proc and operator) are handled through tcallcandiates (must be explictly requested in create params). They could be handled in the node layer during typechecking instead if that was deemed more appropriate. I used the parser layer because regular properties are handled this way and I wasn't sure about the ramifications of making nodes convert themselves to properties in all instances across the entire platform. Furthermore I personally see default properties as a sort of "meta-layer" which doesn't really exist but is more of a re-routing scheme which is applied in advance of normal syntax.
538+Default properties are implemented primarily at the parser layer and overloads (proc and operator) are handled through tcallcandiates (must be explictly requested in create params). They could be handled in the node layer during typechecking instead if that was deemed more appropriate. I used the parser layer because regular properties are handled this way and I wasn't sure about the ramifications of making nodes convert themselves to properties in all instances across the entire platform. Furthermore I personally see default properties as a sort of "meta-layer" which doesn't really exist but is more of a re-routing scheme which is applied in advance of normal syntax.
544539
545-For reference here are some of the important changes made to support default properties.
540+For reference here are some of the important changes made to support default properties.
546541
547- * symtable.pas
542+- symtable.pas
548543
549-searchsym_xxx() functions now contain parameters which explicitly request defaults to be included in the result (see ssf_search_defaults) and return a tpropertysym. searchsym_with_defaults() is added for unit level searching.
544+searchsym_xxx() functions now contain parameters which explicitly request defaults to be included in the result (see ssf_search_defaults) and return a tpropertysym. searchsym_with_defaults() is added for unit level searching.
550545
551- * pexpr.pas
546+- pexpr.pas
552547
553-```
554-do_member_read_internal() - handles the default property sym returned by searchsym_xxx using handle_read_property().
555- do_proc_call() - after proc params are parsed default read property is handled via handle_default_proc_call().
556-```
548+` do_member_read_internal() - handles the default property sym returned by searchsym_xxx using handle_read_property().`\
549+` do_proc_call() - after proc params are parsed default read property is handled via handle_default_proc_call().`\
550+` `
557551
558-Other relevant functions:
559-```
560-handle_default_assignment()
561- handle_default_proc_call()
562- handle_default_unary_operator()
563- handle_default_binary_operator()
564-```
552+Other relevant functions:
565553
566- * htypcheck.pas
554+` handle_default_assignment()`\
555+` handle_default_proc_call()`\
556+` handle_default_unary_operator()`\
557+` handle_default_binary_operator()`
567558
568-Procdefs returned from tcallcandidates (if requested in constructor) can return procdefs from default properties. To help facilitate this tprocoverloadentry class was added (see collect_overloads_in_struct).
559+- htypcheck.pas
569560
570-The new overload for choose_best will return a tpropertysym (if the the best procdef belongs to a default property) so it can be handled properly.
561+Procdefs returned from tcallcandidates (if requested in constructor) can return procdefs from default properties. To help facilitate this tprocoverloadentry class was added (see collect_overloads_in_struct).
571562
572- * pstatmnt.pas
563+The new overload for choose_best will return a tpropertysym (if the the best procdef belongs to a default property) so it can be handled properly.
573564
574-Expressions of type torddef are converted to properties using handle_expr_default_property_access().
565+- pstatmnt.pas
575566
576- * nutils.pas
567+Expressions of type torddef are converted to properties using handle_expr_default_property_access().
577568
578-Various helper functions for default properties:
579-```
580-handle_read_property()
581- handle_write_property()
582- try_default_read_property()
583-```
569+- nutils.pas
584570
585- * nflw.pas
571+Various helper functions for default properties:
586572
573+` handle_read_property()`\
574+` handle_write_property()`\
575+` try_default_read_property()`
576+
577+- nflw.pas
578+
587579Uses try_default_read_property() to resolve default read properties for for..in enumerators. This is only possible for default properties that support the for..in loop, such as arrays, sets etc...
588580
589581---
590-*From the Free Pascal wiki, page "default properties", as the Internet Archive kept it on 2022-12-30. 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).*
582+*From the Free Pascal wiki, page "default properties", as it stood on 2019-12-16 after a change by Trev, 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).*
583+Category: FPC

Back to history