@@ -880,9 +880,10 @@ function foo()
880880
881881### Compiler-assisted field mapping
882882
883- For dedicated state classes, import ` MagicFunctions ` to use compiler-assisted field iteration and generic
884- construction. These operations expand to ordinary constructors and direct field accesses; serialization formats,
885- hashes, and storage remain standard-library concerns.
883+ Import ` MagicFunctions ` to use the compiler-provided ` wurstForFields ` , ` wurstMapFields ` , and
884+ ` wurstNewInstance<T>() ` helpers. Their ` @compilerintrinsic ` declarations provide completion, hover information,
885+ and definition navigation. Calls are replaced at compile time with ordinary field accesses or constructor calls;
886+ the declarations themselves do not remain in generated Jass or Lua.
886887
887888``` wurst
888889import MagicFunctions
@@ -892,59 +893,71 @@ class PlayerState
892893 string name = ""
893894
894895 function save(FieldWriter writer)
895- forFields ((fieldName, value) -> writer.write(fieldName, value))
896+ wurstForFields ((fieldName, value) -> writer.write(fieldName, value))
896897
897898 function load(FieldReader reader)
898- mapFields ((fieldName, value) -> reader.read(fieldName, value))
899+ wurstMapFields ((fieldName, value) -> reader.read(fieldName, value))
899900```
900901
901- ` forFields ` invokes the callback once for every accessible, non-static instance field. This includes inherited,
902- module-injected, readonly, and constant fields. The callback receives the field key and current value and must
903- produce a statement. ` mapFields ` assigns each callback result back to its field, so it includes only accessible,
904- mutable instance fields. Module field keys are qualified when necessary to disambiguate equal names .
902+ ` wurstForFields ` emits one callback invocation for each accessible, non-static instance field. This includes
903+ inherited, module-injected, readonly, and constant fields. The callback must produce a statement.
904+ ` wurstMapFields ` assigns each callback result back to its field, so every visited field must be mutable; a readonly
905+ or constant field produces a compile-time diagnostic. Static fields are never visited .
905906
906- Both functions also accept an explicit target. The target is evaluated exactly once:
907+ The callback receives a field key and the field's current value. The value parameter has a different concrete type
908+ for each generated invocation, despite the ` int ` placeholder shown by the tooling interface. Leave callback
909+ parameter types inferred and use overloads for the field types your mapper supports. Field iteration itself is
910+ shallow: nested classes, tuples, collections, nullable values, and other composite types require matching library
911+ or user-provided overloads. The compiler does not recursively serialize them.
912+
913+ Both operations also accept an explicit target as their first argument. Class targets are evaluated exactly once.
914+ Class and tuple targets are supported. A tuple passed to ` wurstMapFields ` must be a variable so the compiler can
915+ write the mapped tuple back once after updating its components.
907916
908917``` wurst
909- forFields(state, (fieldName, value) -> writer.write(fieldName, value))
910- mapFields(state, (fieldName, value) -> reader.read(fieldName, value))
911- ```
918+ tuple Position(int x, int y)
919+
920+ function savePosition(Position position, FieldWriter writer)
921+ wurstForFields(position, (fieldName, value) -> writer.write(fieldName, value))
912922
913- Leave callback parameter types inferred and overload the reader or writer for every field type used by the state
914- class. An applicable ordinary visible overload with one of these names is resolved normally and is not treated as
915- compiler magic.
923+ function loadPosition(Position position, FieldReader reader) returns Position
924+ var result = position
925+ wurstMapFields(result, (fieldName, value) -> reader.read(fieldName, value))
926+ return result
927+ ```
916928
917- Use ` newInstance <T>()` when a specialized generic function needs to construct its concrete result type:
929+ Use ` wurstNewInstance <T>()` in a generic loader when the concrete result type is known at specialization time :
918930
919931``` wurst
920932function loadState<T:>(FieldReader reader) returns T
921- let result = newInstance <T>()
922- mapFields (result, (fieldName, oldValue) -> reader.read(fieldName, oldValue))
933+ let result = wurstNewInstance <T>()
934+ wurstMapFields (result, (fieldName, oldValue) -> reader.read(fieldName, oldValue))
923935 return result
924936```
925937
926- At each concrete call such as ` loadState<PlayerState>(reader) ` , the compiler specializes the required path and
927- lowers ` newInstance<PlayerState>() ` to its normal zero-argument constructor. ` T ` must resolve to a concrete,
928- non-abstract class with an accessible zero-argument constructor. Interfaces, handles, primitives, tuples,
929- unresolved type parameters, and classes without a usable constructor are rejected.
930-
931- Keep a generic loader in the free-function form shown above. On Lua, a method cannot currently combine type
932- parameters from its generic owning class with additional type parameters declared by the method itself.
933- Likewise, do not call ` newInstance<T>() ` from a generic class constructor. Construct the state in the loader and
934- initialize nested state explicitly afterward.
935-
936- On Lua, do not invoke a generic-construction method directly on a freshly constructed generic receiver. Prefer the
937- free loader above, or store the receiver in a typed local first. Multi-parameter generic-interface dispatch is also
938- outside this loader contract; use one construction type parameter. ` newInstance<T>() ` is for runtime Jass/Lua
939- construction and is not supported inside ` compiletime(...) ` expressions. Field mapping also does not support
940- nested modules whose sibling submodules declare fields with the same name; use direct fields, inheritance, or
941- unique shallow module field names for dedicated state classes.
942-
943- These are compile-time transformations, not runtime reflection, and generate equivalent direct accesses in both
944- Jass and Lua. They generate no runtime registry, type-name lookup, or reflection metadata. Keep serializable state
945- in small, dedicated classes, avoid unsupported field kinds such as static fields, and keep persistence codecs and
946- format migration separate from the state model. See the [ Save and Load tutorial] ( /tutorials/saveload.html ) for
947- integration with Warcraft III's file API.
938+ The helper invokes the normal accessible zero-argument constructor of a concrete, non-abstract class. It does not
939+ allocate an uninitialized object or look up a class by name. Constructor initializers run normally, which lets a
940+ serialization library retain defaults for fields missing from older records.
941+
942+ These helpers provide no wire format, stable field IDs, versioning, migration policy, integrity checks, runtime
943+ reflection metadata, or type registry. Those remain library concerns. In particular, field keys are source names,
944+ not stable persisted identities; a library must translate them to its own schema identity if renames need to remain
945+ compatible.
946+
947+ The original unprefixed ` forFields ` , ` mapFields ` , and ` newInstance<T>() ` spellings remain available as compatibility
948+ fallbacks. New code should use the ` wurst ` -prefixed names to avoid accidental collisions. If an applicable ordinary
949+ function with the same name is visible, normal overload resolution selects that function instead of the compiler
950+ operation.
951+
952+ For Lua, keep generic construction in a free function with one construction type parameter. Do not combine type
953+ parameters from a generic owning class with independent method type parameters, call ` wurstNewInstance<T>() ` from
954+ a generic class constructor, invoke a generic-construction method directly on a freshly constructed generic
955+ receiver, or use multi-parameter generic-interface dispatch. ` wurstNewInstance<T>() ` is a runtime Jass/Lua helper
956+ and is not supported inside ` compiletime(...) ` . Field mapping does not support nested modules whose sibling
957+ submodules declare equal field names.
958+
959+ See the [ Save and Load tutorial] ( /tutorials/saveload.html ) for integration with Warcraft III's file API and the
960+ standard library serialization layers.
948961
949962Identifiers beginning with ` __wurst ` are reserved for compiler-generated internals and must not be declared by
950963user code.
0 commit comments