Difference between revisions of "pas2js Generics"
From Lazarus wiki
Jump to navigationJump to searchLine 90: | Line 90: | ||
** proc types | ** proc types | ||
** overloads | ** overloads | ||
− | * | + | * automatically inferring types of generic method: |
** ''MyProc(1)'' calls ''MyProc<T>(a: T)'' | ** ''MyProc(1)'' calls ''MyProc<T>(a: T)'' | ||
** '''$modeswitch implicitfunctionspecialization''': mode Delphi: default enabled, ObjFPC: disabled | ** '''$modeswitch implicitfunctionspecialization''': mode Delphi: default enabled, ObjFPC: disabled |
Revision as of 18:51, 17 October 2019
Overview
Pas2js 1.5 supports generic types and functions in either the ObjFPC or Delphi like way.
Next goal is to test and fix bugs.
Working
- generic record
- specialize:
- ObjFPC: type TFoo = specialize TGen<word>;
- Delphi: type TFoo = TGen<word>;
- ObjFPC anonymous: var r: specialize TBird<word>;
- Delphi: anonymous var r: TBird<word>;
- generic class
- specialize in ancestor type
- forward generic class (FPC 3.3.1 does not support it yet)
- enumtype inside generic is not propagated
- ObjFPC: members can refer to parent type without type parameters
- Delphi: descendants cannot refer to type parameters of ancestors, pas2js allows it.
- Delphi/FPC does not allows accessing local symbols. pas2js allows it.
- generic external class
- generic array
- 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
- generic interface
- generic procedural type
- specialized proc types can assign normal proc
- anonymous type in specialize: TBird<array of word>
- nested specialize: TBird<TWing<byte>>
- record/class field
- property
- method (not confused with generic method)
- Delphi: implementation must repeat type params, must omit constraints
- FPC: implementation must not repeat type params
- for-loop, if-then-else, repeat-until, while-do, try-finally, try-except, case-of
- assignments
- primitive expression like identifiers and constants
- operators: +, -, *, /
- constraints:
- keyword record, class, constructor checked at specialization
- class type checked at specialization
- constraints:
- "class":
- Delphi/FPC: T is TObject
- pas2js: test if T is a class, either TObject or an external class
- "constructor": test if T is TObject and Create resolves to TObject.create
- "record": test if T is a record type
- class type: test if param fits
- list of interface types: test if param fits
- forward class must repeat constraints
- Delphi does not allow TObject as constraint. pas2js allows it, because it has other root classes.
- constraint refers to prior template name: type TBird<X, Y: TAnt<X>> = record a: X; b: Y; end;
- "class":
- statements:
- specialize (cloning) all kinds of statements and expressions
- inline specialize expression, e.g. TList<word>.Create
- Delphi: TFoo<Integer>.Create
- FPC: specialize TFoo<Integer>.Create
- "obj is T": allowed with constraint "class" or class type
- typecast T(): allowed with constraint "class" or class type
- using implementation function in generic function:
- Delphi: Error: Method of parameterized type declared in interface section must not use local symbol '%s'
- FPC: Error: Global Generic template references static symtable
- Pas2js: allowed
- anInt:=GenericVar
- Delphi: always Error: Incompatible types: 'Integer' and 'T'
- 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
- for-in TWithConstraint
- typeinfo(T)
- T is TFoo<Integer>
- T as TFoo<Integer>
- TFoo<Integer>(expr)
- call
- pas2js: Later checked by specialization.
- Delphi: must fit the constraint. For example without constraint it only fits untyped args.
- FPC: if there is only one function in scope select it, overloads are selected by constraints alone. Later checked by specialization.
- generic function (aka parametrized method):
- ObjFPC: generic procedure Fly<T>(a: T)
- Delphi: procedure Fly<T>(a: T) Note: Delphi 10.3 only supports parametrized method, not global procedure, pas2js allows it
- forward
- unit interface/implementation
- overloads
- nested generic procedure is forbidden, same as FPC/Delphi
- calling self
- constraints, see above, same as type constraints
- ObjFPC explicitly spezialize: specialize Fly<word>(aWord)
- Delphi explicitly spezialize: Fly<word>(aWord)
- generic method (aka parametrized method):
- methods: virtual, message, constructor and destructors cannot have type parameters
- class interface methods cannot have type parameters
- proc types
- overloads
- automatically inferring types of generic method:
- MyProc(1) calls MyProc<T>(a: T)
- $modeswitch implicitfunctionspecialization: mode Delphi: default enabled, ObjFPC: disabled
- array of T: procedure Run<T>(a: array of T)
- any order: procedure Run<S,T>(a:T; b:S)
ToDos
- nested generic type: allowed by Delphi, not allowed by FPC, not planned for 1.5
- cascaded specialize: TBird<word>.TWing<byte>, not planned for 1.5
- generic class:
- Delphi type overloads A, A<T> and A<S,T>, not planned for 1.5
- Delphi/FPC classname "TTest<System.Longint>", pas2js uses shorter classname "TTest$G1"
- class constructor
- generic method (aka parametrized method):
- 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
- nicer error messages
- instead of TList$G1 write TList<word>
- write a hint where it was specialized
- filer
- optimization: reuse specialized functions
- constants as templates: Not planned