pas2js Generics: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: pas2js Generics
| Old | New | Line | |
|---|---|---|---|
| 1 | + | # Overview | |
| 2 | + | ||
| 3 | + | Pas2js 1.5 supports generic types and functions in either the ObjFPC or Delphi like way. | |
| 4 | + | ||
| 5 | + | Next goal is to test and fix bugs. | |
| 6 | + | ||
| 7 | + | ## Working | |
| 8 | + | ||
| 9 | + | - generic class | |
| 10 | + | - ClassName, TypeInfo Name | |
| 11 | + | - Delphi, pas2js: full path with param names, e.g. 'TAnt\<System.Word\>' and 'TAnt\<System.Word\>.TLeg' | |
| 12 | + | - FPC: instead of param names uses crc, e.g. 'TAnt\$1\$crcHexNumber', full paths for classnames, e.g. 'TAnt\$1\$crcHexNumber.TLeg', last name for TypeInfo: e.g. 'TLeg' | |
| 13 | + | - JS specialize code in unit of generic | |
| 14 | + | - forward generic class, e.g. *type TAnt\<T\>=class; TBird=class a: TAnt\<word\>; end; TAnt\<T\>=class a:T; end;* | |
| 15 | + | - Delphi/pas2js: supported | |
| 16 | + | - FPC: 3.3.1 does not support it yet | |
| 17 | + | - enumtype inside generic is not propagated | |
| 18 | + | - ObjFPC: members can refer to parent type without type parameters, e.g. *type generic TAnt\<T\> = class Parent: TAnt; end;* | |
| 19 | + | - Delphi/FPC: descendants cannot refer to type parameters of ancestors, pas2js allows it within same unit (strict private). | |
| 20 | + | - Delphi/FPC does not allow accessing local symbols. pas2js allows it. | |
| 21 | + | - class constructor | |
| 22 | + | - generic external class | |
| 23 | + | - generic record | |
| 24 | + | - generic dynamic array | |
| 25 | + | - generic static array: Note: delphi wiki says "no static arrays", but 10.3 compiles it, see <http://docwiki.embarcadero.com/RADStudio/Rio/en/Declaring_Generics> | |
| 26 | + | - generic interface | |
| 27 | + | - generic procedural type | |
| 28 | + | - specialized proc types can assign normal proc | |
| 29 | + | - Procedure local scope: | |
| 30 | + | - pas2js: allowed, except for typeinfo | |
| 31 | + | - FPC: allowed, including typeinfo | |
| 32 | + | - Delphi: Error: parameterized type can not be declared in procedure local scope | |
| 33 | + | - anonymous type in specialize: *TBird\<array of word\>* | |
| 34 | + | - Delphi type overloads A, A\<T\> and A\<S,T\> | |
| 35 | + | - specialize: | |
| 36 | + | - ObjFPC: *type TFoo = specialize TGen\<word\>;* | |
| 37 | + | - Delphi: *type TFoo = TGen\<word\>;* | |
| 38 | + | - ObjFPC anonymous: *var r: specialize TBird\<word\>;* | |
| 39 | + | - Delphi: anonymous *var r: TBird\<word\>;* | |
| 40 | + | - nested specialize: TBird\<TWing\<byte\>\> | |
| 41 | + | - record/class field | |
| 42 | + | - property | |
| 43 | + | - method (not confused with generic method) | |
| 44 | + | - Delphi: implementation must repeat type params, must omit constraints | |
| 45 | + | - FPC: implementation must not repeat type params | |
| 46 | + | - helper for generic type | |
| 47 | + | - constraints: | |
| 48 | + | - keyword *record*, *class*, *constructor* checked at specialization | |
| 49 | + | - class type checked at specialization | |
| 50 | + | - constraints: | |
| 51 | + | - "class": | |
| 52 | + | - Delphi/FPC: T is TObject | |
| 53 | + | - pas2js: test if T is a class, either TObject or an external class | |
| 54 | + | - "constructor": test if T is TObject and Create resolves to TObject.create | |
| 55 | + | - "record": test if T is a record type | |
| 56 | + | - class type: test if param fits | |
| 57 | + | - list of interface types: test if param fits | |
| 58 | + | - forward class must repeat constraints | |
| 59 | + | - Delphi does not allow *TObject* as constraint. pas2js allows it, because it has other root classes. | |
| 60 | + | - constraint can refer prior templates: *type TBird\<X, Y: TAnt\<X\>\> = record a: X; b: Y; end;*. This is Delphi compatible. FPC 3.3.1 does not support this (23th Aug 2020). | |
| 61 | + | - statements: | |
| 62 | + | - specialize (cloning) all kinds of statements and expressions | |
| 63 | + | - for-loop, if-then-else, repeat-until, while-do, try-finally, try-except, case-of | |
| 64 | + | - assignments | |
| 65 | + | - primitive expression like identifiers and constants | |
| 66 | + | - operators: +, -, *, / | |
| 67 | + | - inline specialize expression, e.g. *TList\<word\>.Create* | |
| 68 | + | - Delphi: TFoo\<Integer\>.Create | |
| 69 | + | - FPC: specialize TFoo\<Integer\>.Create | |
| 70 | + | - "obj is T": allowed with constraint "class" or class type | |
| 71 | + | - typecast T(): allowed with constraint "class" or class type | |
| 72 | + | - using implementation function in generic function: | |
| 73 | + | - Delphi: Error: Method of parameterized type declared in interface section must not use local symbol '%s' | |
| 74 | + | - FPC: Error: Global Generic template references static symtable | |
| 75 | + | - Pas2js: allowed | |
| 76 | + | - anInt:=GenericVar | |
| 77 | + | - Delphi: always Error: Incompatible types: 'Integer' and 'T' | |
| 78 | + | - FPC/pas2js: allowed for valid combinations -\> operators are checked on specialization, Note: because of implementation cross uses, check is delayed until used unit implementation is complete | |
| 79 | + | - for-in T do -\> T must have constraints | |
| 80 | + | - typeinfo(T) | |
| 81 | + | - T is TFoo\<Integer\> | |
| 82 | + | - T as TFoo\<Integer\> | |
| 83 | + | - TFoo\<Integer\>(expr) | |
| 84 | + | - call | |
| 85 | + | - pas2js: Later checked by specialization. | |
| 86 | + | - Delphi: must fit the constraint. For example without constraint it only fits untyped args. | |
| 87 | + | - FPC: if there is only one function in scope select it, overloads are selected by constraints alone. Later checked by specialization. | |
| 88 | + | - generic function (aka parametrized method): | |
| 89 | + | - ObjFPC: *generic procedure Fly\<T\>(a: T)* | |
| 90 | + | - Delphi: *procedure Fly\<T\>(a: T)* Note: Delphi 10.3 only supports parametrized method, not global procedure, pas2js allows it | |
| 91 | + | - forward | |
| 92 | + | - unit interface/implementation | |
| 93 | + | - overloads | |
| 94 | + | - generic procedure inside a procedure is forbidden, same as FPC/Delphi | |
| 95 | + | - local procedures inside a generic function: supported by FPC and pas2js, not supported by Delphi | |
| 96 | + | - calling self | |
| 97 | + | - constraints, see above, same as type constraints | |
| 98 | + | - ObjFPC explicitly spezialize: *specialize Fly\<word\>(aWord)* | |
| 99 | + | - Delphi explicitly spezialize: *Fly\<word\>(aWord)* | |
| 100 | + | - parameter type inline specialization: *procedure Run\<T\>(List: TList\<T\>);* | |
| 101 | + | - generic method (aka parametrized method): | |
| 102 | + | - methods: virtual, message, constructor and destructors cannot have type parameters | |
| 103 | + | - class interface methods cannot have type parameters | |
| 104 | + | - proc types | |
| 105 | + | - overloads | |
| 106 | + | - automatically inferring types of generic method/function: | |
| 107 | + | - *MyProc(1)* calls *MyProc\<T\>(a: T)* | |
| 108 | + | - **\$modeswitch implicitfunctionspecialization**: mode Delphi: default enabled, ObjFPC: disabled | |
| 109 | + | - array of T: *procedure Run\<T\>(a: array of T)* | |
| 110 | + | - any order: *procedure Run\<S,T\>(a:T; b:S)* | |
| 111 | + | - infer types: widen types, e.g. *Run(1,1000000)* specializes *Run\<T\>(a,b:T)* with *T* as *longint*. Not supported by Delphi/FPC, supported by pas2js to reduce number of specializations | |
| 112 | + | - typecast between specializations gives a warning, not an error | |
| 113 | + | - typecast TGenType\<jsvalue\> from/to TGenType\<SomeType\> without warning | |
| 114 | + | - allowing ATExtClass\<jsvalue\> := ATExtClass\<SomeType\> | |
| 115 | + | - function GetTypeKind(aType): TTypeKind | |
| 116 | + | - RTTI | |
| 117 | + | - RTTI names use FPC/Delphi like *TList\<word\>* instead of the JS name *TList\$G1* | |
| 118 | + | ||
| 119 | + | # RTL Units | |
| 120 | + | ||
| 121 | + | - generics.defaults.pas | |
| 122 | + | - generics.strings.pas | |
| 123 | + | - generics.collections.pas | |
| 124 | + | ||
| 125 | + | # RTL Classes | |
| 126 | + | ||
| 127 | + | - TArray\<T\> | |
| 128 | + | - IComparer\<T\> | |
| 129 | + | - TOnComparison\<T\> | |
| 130 | + | - TComparer\<T\> | |
| 131 | + | - TDefaultComparer\<T\> | |
| 132 | + | - IEnumerator\<T\> | |
| 133 | + | - IEnumerable\<T\> | |
| 134 | + | - TCollectionNotifyEvent\<T\> | |
| 135 | + | - TCustomArrayHelper\<T\> | |
| 136 | + | - TArrayHelper\<T\> | |
| 137 | + | - TEnumerator\<T\> | |
| 138 | + | - TEnumerable\<T\> | |
| 139 | + | - TCustomList\<T\> | |
| 140 | + | - TCustomListEnumerator\<T\> | |
| 141 | + | - TCustomInvertedListEnumerator\<T\> | |
| 142 | + | - TList\<T\> | |
| 143 | + | - TObjectList\<T: class\> | |
| 144 | + | - TThreadList\<T\> | |
| 145 | + | - TQueue\<T\> | |
| 146 | + | - TObjectQueue\<T: class\> | |
| 147 | + | - TStack\<T\> | |
| 148 | + | - TObjectStack\<T: class\> | |
| 149 | + | - TPair\<TKey,TValue\> | |
| 150 | + | - TDictionary\<TKey,TValue\> | |
| 151 | + | ||
| 152 | + | ## ToDos | |
| 153 | + | ||
| 154 | + | - anonymous record, e.g. *type TAnt\<T\> = class a: record end; end;* | |
| 155 | + | - anonymous set, e.g. *type TAnt\<T\> = class a: (red, blue); end;* | |
| 156 | + | - type alias type as parameter: create separate specialization, at the moment *TList\<integer\>* and *TList\<TColor\>* are the same specialization in pas2js | |
| 157 | + | - generic class: | |
| 158 | + | - nested generic type: i.e. generic inside a generic. Allowed by Delphi, not allowed by FPC | |
| 159 | + | - cascaded specialize: TBird\<word\>.TWing\<byte\> | |
| 160 | + | - generic ancestor, allowed in FPC, not allowed in Delphi: *TExample\<T: class\> = class(T) end;* | |
| 161 | + | - nicer error messages | |
| 162 | + | - write a hint where it was specialized | |
| 163 | + | - Redefinition. Example: *type TBird\<T\> = class i: integer; end; integer = string; TEagle = TBird\<integer\>;* FPC+pas2js: create i as *string*, Delphi: creates i as *system.integer* | |
| 164 | + | - optimization: reuse specialized functions | |
| 165 | + | - constants as templates | |
| 166 | + | - precompiled js files. At the moment all specializations are added to the unit where the generic is defined. That means using a new specialization require to recompile the js file. | |
| 167 | + | ||
| 168 | + | --- | |
| 169 | + | *From the Free Pascal wiki, page "pas2js Generics", as it stood on 2022-12-19 after a change by Mattias2, 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).* | |
| 170 | + | Category: Pas2js |
