diff --git a/src/lib/diff/tree-mutator-attribute-binding.hpp b/src/lib/diff/tree-mutator-attribute-binding.hpp index 260cb532e..81babe431 100644 --- a/src/lib/diff/tree-mutator-attribute-binding.hpp +++ b/src/lib/diff/tree-mutator-attribute-binding.hpp @@ -100,6 +100,7 @@ #include "lib/symbol.hpp" #include "lib/diff/gen-node.hpp" #include "lib/diff/tree-mutator.hpp" +#include "lib/meta/typeseq-util.hpp" #include "lib/format-string.hpp" #include "lib/idi/entry-id.hpp" diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index cfefcb2da..7733480b3 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -103,7 +103,7 @@ #include "lib/meta/duck-detector.hpp" #include "lib/meta/function.hpp" #include "lib/meta/trait.hpp" -#include "lib/wrapper.hpp" ////////////TODO : could be more lightweight by splitting FunctionResult into separate header. Relevant? +#include "lib/wrapper.hpp" #include "lib/iter-adapter.hpp" #include "lib/iter-source.hpp" /////////////TICKET #493 : only using the IterSource base feature / interface here. Should really split the iter-source.hpp #include "lib/iter-stack.hpp" diff --git a/src/lib/meta/function-closure.hpp b/src/lib/meta/function-closure.hpp index d551e4b2e..ed2451574 100644 --- a/src/lib/meta/function-closure.hpp +++ b/src/lib/meta/function-closure.hpp @@ -14,15 +14,17 @@ /** @file function-closure.hpp ** Partial function application and building a complete function closure. - ** This is a addendum to (and thin wrapper for) ``, supporting - ** the case when a function should be _closed_ over (partially or all) arguments, - ** where especially the parameter values to close on are provided as a tuple. + ** This is a addendum to std::bind, to support especially the case when a + ** function should be _closed_ over (partially or all) arguments. This implies + ** to bind some arguments immediately, while keeping other arguments open to + ** be supplied on function invocation. ** Additionally, we allow for composing (chaining) of two functions. - ** - ** Because we have to deal with arbitrary functions and arbitrary parameter types, - ** we need a lot of repetitive code to "catch" functions from zero to nine arguments. - ** At the bottom of this header, you'll find a function-style interface, which - ** wraps up all these technicalities. + ** @warning this header is in a state of transition as of 2/2025, because functionality + ** of this kind will certainly needed in future, but with full support for lambdas, + ** move-only types and perfect forwarding. A gradual rework has been started, and + ** will lead to a complete rewrite of the core functionality eventually, making + ** better use of variadic templates and library functions like std::apply, which + ** were not available at the time of the first implementation. ** ** @todo the implementation is able to handle partial application with N arguments, ** but currently we need just one argument, thus only this case was wrapped @@ -38,9 +40,11 @@ ** expectations (including move, constexpr); if we choose to retain a generic ** function-style front-end, it should be aligned with these standard facilities. ** We might want to retain a simple generic interface especially for binding some - ** selected argument, which handles the intricacies of storing the functor. + ** selected argument, which handles the intricacies of storing the functor. ** ** @see control::CommandDef usage example + ** @see function-closure-test.hpp + ** @see function-composition-test.hpp ** @see function.hpp ** */ @@ -543,7 +547,7 @@ namespace func{ /** * Partial function application * Takes a function and a value tuple, - * using the latter to close function arguments + * using the latter to close function arguments * either from the front (left) or aligned to the end * of the function argument list. Result is a "reduced" function, * expecting only the remaining "un-closed" arguments at invocation. diff --git a/src/lib/meta/tuple-closure.hpp b/src/lib/meta/tuple-closure.hpp new file mode 100644 index 000000000..e2a758bc1 --- /dev/null +++ b/src/lib/meta/tuple-closure.hpp @@ -0,0 +1,88 @@ +/* + TUPLE-CLOSURE.hpp - metaprogramming tools for closing a function over given arguments + + Copyright (C) + 2025, Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +*/ + + +/** @file tuple-closure.hpp + ** Partial binding for construction of tuple-like records. + ** Sometimes tuple-like structures must be created as part of library code, + ** in a situation where _some of the values_ are known and should be fixed-in, + ** while other values need to be supplied late. Obviously this implies creating + ** a functor, and then partially to close some arguments. While seemingly simple, + ** this task is often complicated by the need to support _»tuple-like«_ records, + ** i.e. anything which adheres to the »C++ tuple protocol« (e.g. std::array). + ** Which requires to pick up the actual container type by template pattern match + ** and to rely solely on the helper functions from the STLIB for data access. + ** + ** A relevant use-case is the handling of invocation parameters for Render Nodes: + ** typically, some parameters are of technical nature and can be configured during + ** the setup-phase of the render network, while other parameters allow the user + ** to exert artistic control and will be supplied later, through automation. + ** + ** @see weaving-pattern-builder.hpp + ** @see NodeBuilder_test::build_Node_closedParam() + ** + */ + + +#ifndef LIB_META_TUPLE_CLOSURE_H +#define LIB_META_TUPLE_CLOSURE_H + +#include "lib/meta/function-closure.hpp" +#include "lib/meta/tuple-helper.hpp" + +#include +#include + + + +namespace lib { +namespace meta{ + + template + struct TupleClosureBuilder; + + template class TUP, typename...PARS> + struct TupleClosureBuilder> + { + using Params = TUP; + + static Params + buildParam (PARS ...params) + { + return {params...}; + } + + template + static auto + closeFront (VALS ...vs) + { + using lib::meta::_Fun; + using lib::meta::TySeq; + using lib::meta::func::PApply; + using ClosedTypes = TySeq; + using ParamBuilderSig = Params(PARS...); + auto partialClosure = PApply::bindFront (buildParam, std::make_tuple(vs...)); + using RemainingArgs = typename _Fun::Args; + using RemainingParams = typename lib::meta::RebindVariadic::Type; + return [closure = move(partialClosure) + ] + (RemainingParams remPar) + { + return std::apply (closure, remPar); + }; + } + }; + + +}} // namespace lib::meta +#endif diff --git a/src/lib/wrapper-function-result.hpp b/src/lib/wrapper-function-result.hpp new file mode 100644 index 000000000..5ce8870c4 --- /dev/null +++ b/src/lib/wrapper-function-result.hpp @@ -0,0 +1,92 @@ +/* + WRAPPER-FUNCTION-RESULT.hpp - some smart wrapping and reference managing helper templates + + Copyright (C) + 2009, Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +*/ + +/** @file wrapper-function-result.hpp + ** Helper to cache the result of function invocation. + ** @todo 2025 initially created by direct need, it was used for a while, + ** but became largely obsoleted by the ''transforming'' functionality + ** provided by iter-explorer.hpp (which is implemented by the same + ** basic technique, but without the std::function baseclass). + */ + + +#ifndef LIB_WRAPPER_FUNCTION_RESULT_H +#define LIB_WRAPPER_FUNCTION_RESULT_H + +#include "lib/wrapper.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/function-closure.hpp" +#include "lib/meta/util.hpp" + +#include + + +namespace lib { +namespace wrapper { + + using lib::meta::_Fun; + using std::function; + + + + /** + * Extension of ItemWrapper: a function remembering the result of the + * last invocation. Initially, the "value" is bottom (undefined, NIL), + * until the function is invoked for the first time. After that, the + * result of the last invocation can be accessed by `operator* ()` + * @note deliberately non-copyable, since we capture a reference + * to `this` in order to write to the embedded ItemWrapper. + * (to alleviate, we'd have to re-link after copying/moving) + */ + template + struct FunctionResult + : public function + , util::NonCopyable + { + using Res = typename _Fun::Ret; + using ResWrapper = ItemWrapper; + + ResWrapper lastResult_; + + public: + /** by default locked to _invalid state_ */ + FunctionResult() = default; + + /** + * Create result-remembering functor by outfitting a _copy_ + * of the given function with an adaptor to _capture_ each + * produced result. + * @warning if function result is a value, it is copied. + */ + template + FunctionResult (FUN&& targetFunction) + : function{lib::meta::func::chained + ( std::forward (targetFunction) + , [this](Res res) -> Res + { + lastResult_ = res; + return std::forward (res); + })} + { } + + /** retrieve the last function result observed */ + Res& operator*() const { return *lastResult_; } + bool isValid () const { return lastResult_.isValid(); } + + explicit + operator bool() const { return isValid(); } + }; + + +}} // namespace lib::wrap +#endif /*LIB_WRAPPER_FUNCTION_RESULT_H*/ diff --git a/src/lib/wrapper.hpp b/src/lib/wrapper.hpp index 3d3fe65d8..3050cdd3a 100644 --- a/src/lib/wrapper.hpp +++ b/src/lib/wrapper.hpp @@ -16,16 +16,22 @@ ** This is (intended to become) a loose collection of the various small helper templates ** for wrapping, containing, placing or handling a somewhat \em problematic other object. ** Mostly these are implemented to suit a specific need and then factored out later on. - ** - ItemWrapper is a similar concept, but more like a smart-ptr. Moreover, - ** it can be instantiated with a value type, a pointer or a reference type, - ** yielding the same behaviour in all cases (useful for building templates) + ** - ReturnRef is similar to std::reference_wrapper, but with a function-like usage. + ** - ItemWrapper is a similar concept, but used more like a smart-ptr. Notably, + ** a value-object is stored inline, into an embedded buffer. + ** Furthermore, ItemWrapper can be used to level differences between values, + ** references and pointers, as it can be instantiated with any of them, offering + ** (almost) uniform handling in all cases (useful for building templates) ** - FunctionResult is the combination of ItemWrapper with a functor object - ** to cache the function result value. - ** + ** to cache the function result value. It was split off into a separate + ** header \ref wrapper-function-result.hpp to reduce include impact + ** @remark most of this helper collection became obsolete with the evolution of the + ** standard library — with the exception of ItermWrapper, which turned out to be + ** very effective and is now pervasively used as part of transforming functor + ** pipelines, to cache the result of the transforming function invocation. ** @see lib::TransformIter - ** - ** @todo 2017 consider to split off the FunctionResult into a dedicated header to reduce includes - ** + ** @see lib::explore + ** */ @@ -34,25 +40,19 @@ #include "lib/error.hpp" #include "lib/nocopy.hpp" -#include "lib/meta/function.hpp" -#include "lib/meta/function-closure.hpp" -#include "lib/meta/util.hpp" #include "lib/util.hpp" -#include #include +#include +#include namespace lib { namespace wrapper { - using util::unConst; using util::isSameObject; - using lib::meta::_Fun; using LERR_(BOTTOM_VALUE); - using std::function; - /** @@ -386,56 +386,5 @@ namespace wrapper { } - - - /** - * Extension of ItemWrapper: a function remembering the result of the - * last invocation. Initially, the "value" is bottom (undefined, NIL), - * until the function is invoked for the first time. After that, the - * result of the last invocation can be accessed by `operator* ()` - * @note deliberately non-copyable, since we capture a reference - * to `this` in order to write to the embedded ItemWrapper. - * (to alleviate, we'd have to re-link after copying/moving) - */ - template - struct FunctionResult - : public function - , util::NonCopyable - { - using Res = typename _Fun::Ret; - using ResWrapper = ItemWrapper; - - ResWrapper lastResult_; - - public: - /** by default locked to _invalid state_ */ - FunctionResult() = default; - - /** - * Create result-remembering functor by outfitting a _copy_ - * of the given function with an adaptor to _capture_ each - * produced result. - * @warning if function result is a value, it is copied. - */ - template - FunctionResult (FUN&& targetFunction) - : function{lib::meta::func::chained - ( std::forward (targetFunction) - , [this](Res res) -> Res - { - lastResult_ = res; - return std::forward (res); - })} - { } - - /** retrieve the last function result observed */ - Res& operator*() const { return *lastResult_; } - bool isValid () const { return lastResult_.isValid(); } - - explicit - operator bool() const { return isValid(); } - }; - - }} // namespace lib::wrap -#endif +#endif /*LIB_WRAPPER_H*/ diff --git a/src/steam/engine/node-builder.hpp b/src/steam/engine/node-builder.hpp index f4a2501a6..702b0821f 100644 --- a/src/steam/engine/node-builder.hpp +++ b/src/steam/engine/node-builder.hpp @@ -493,51 +493,15 @@ namespace engine { }; } - template - struct ClosureBuilder; - - template class TUP, typename...PARS> - struct ClosureBuilder> - { - using Params = TUP; - - static Params - buildParam (PARS ...params) - { - return {params...}; - } - - template - static auto - closeFront (VALS ...vs) - { - using lib::meta::_Fun; - using lib::meta::TySeq; - using lib::meta::func::PApply; - using ClosedTypes = TySeq; - using ParamBuilderSig = Params(PARS...); - auto partialClosure = PApply::bindFront (buildParam, std::make_tuple(vs...)); - using RemainingArgs = typename _Fun::Args; - using RemStripped = typename lib::meta::StripNullType::Seq; - using RemainingParams = typename lib::meta::RebindVariadic::Type; -// using idx = std::make_index_sequence; -// auto& makeParamAggregate = buildParam; - return [closure = move(partialClosure) - ] - (RemainingParams remPar) - { - return std::apply (closure, remPar); - }; - } - }; - + /** immediately close (≙ fix) some values in a parameter tuple, + * starting from left, while leaving the remaining values open + * to be supplied by automation or another parameter binding. */ template auto closeParamFront (PAR v1, PARS ...vs) { - using Params = typename WAB::Param; return adaptParam( - ClosureBuilder::template closeFront (v1,vs...)); + WAB::ParamClosure::template closeFront (v1,vs...)); } diff --git a/src/steam/engine/weaving-pattern-builder.hpp b/src/steam/engine/weaving-pattern-builder.hpp index d0675474b..c15017f86 100644 --- a/src/steam/engine/weaving-pattern-builder.hpp +++ b/src/steam/engine/weaving-pattern-builder.hpp @@ -138,6 +138,7 @@ #include "steam/engine/buffer-provider.hpp" #include "steam/engine/buffhandle-attach.hpp" /////////////////OOO why do we need to include this? we need the accessAs() template function #include "steam/engine/media-weaving-pattern.hpp" +#include "lib/meta/tuple-closure.hpp" #include "lib/meta/tuple-helper.hpp" //#include "lib/test/test-helper.hpp" ////////////////////////////OOO TODO added for test #include "lib/format-string.hpp" @@ -251,9 +252,9 @@ namespace engine { static constexpr uint FAN_I = PROT::FAN_I; static constexpr uint FAN_O = PROT::FAN_O; - using Param = typename PROT::Param; ///////////////////////////OOO integrate here a partial-closure-helper using TypeMarker = std::function; using ProviderRef = std::reference_wrapper; + using ParamClosure = lib::meta::TupleClosureBuilder; DataBuilder leadPorts; std::vector buffTypes; diff --git a/src/steam/mobject/output-designation.hpp b/src/steam/mobject/output-designation.hpp index 8a7e981e7..426b1c52e 100644 --- a/src/steam/mobject/output-designation.hpp +++ b/src/steam/mobject/output-designation.hpp @@ -35,6 +35,7 @@ #include "lib/hash-value.h" #include "lib/opaque-holder.hpp" #include "lib/meta/typelist-manip.hpp" +#include "lib/meta/typelist-util.hpp" namespace steam { diff --git a/tests/core/steam/engine/node-builder-test.cpp b/tests/core/steam/engine/node-builder-test.cpp index 14b0dcc94..26e201706 100644 --- a/tests/core/steam/engine/node-builder-test.cpp +++ b/tests/core/steam/engine/node-builder-test.cpp @@ -218,7 +218,7 @@ namespace test { .build()}; Time timeOfEvil{5555,0}; -SHOW_EXPR(invokeRenderNode(node,timeOfEvil)); + CHECK (15 == invokeRenderNode(node,timeOfEvil)); } diff --git a/tests/library/item-wrapper-test.cpp b/tests/library/item-wrapper-test.cpp index 85bb2a82d..c794e8ff4 100644 --- a/tests/library/item-wrapper-test.cpp +++ b/tests/library/item-wrapper-test.cpp @@ -24,6 +24,7 @@ #include "lib/util.hpp" #include "lib/wrapper.hpp" +#include "lib/wrapper-function-result.hpp" #include #include diff --git a/tests/vault/gear/activity-detector.hpp b/tests/vault/gear/activity-detector.hpp index 76fffe9e6..91152732c 100644 --- a/tests/vault/gear/activity-detector.hpp +++ b/tests/vault/gear/activity-detector.hpp @@ -71,6 +71,7 @@ #include "vault/gear/nop-job-functor.hpp" #include "lib/time/timevalue.hpp" #include "lib/meta/variadic-rebind.hpp" +#include "lib/meta/typeseq-util.hpp" #include "lib/meta/function.hpp" #include "lib/wrapper.hpp" #include "lib/format-util.hpp" diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 6ea9d1415..c84b8a499 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -58540,6 +58540,61 @@ + + + + + +

+ Das hat sich über längere Zeit herauskristalisiert. +

+
    +
  • + zunächst war das die einzige Möglichkeit, überhaupt in meta-Generierung von Typen einzusteigen +
  • +
  • + dann dachte ich, es wird durch die Variadics und Lambdas obsolet werden, und hab schon teilweise mit dem Rückbau begonnen +
  • +
  • + doch dann kam die Ernüchterung: für Variadics bin ich einfach zu blöd — dafür muß man andauernd rückwärts denken. +
  • +
  • + viele Jahre habe ich nun Erfahrungen gesammelt, was mit welcher Technik am besten geht; habe Helper für Tuples gebaut, die dann doch nicht gebraucht wurden +
  • +
  • + 2025 für die Umstellung der Render-Engine auf Tuples und strikte Typisierung war ich erneut mit den »tuple-likes« konfrontiert. Ich hab mir wieder durch Einschieben einer Abstraktion geholfen, welche allerdings nur mit Typ-Sequenzen einigermaßen sinnvoll zu implementieren ist. Damit gibt es nun drei Systeme zusammenhängender Metaprogramming-Helper, und alle werden wohl erhalten bleiben. +
  • +
  • + habe daraufhin begonnen, Header umzuordnen, um die Include-Linien möglichst sauber zu bekommen. +
  • +
+ +
+ + +
+ + + + + + +

+ Es ist klar, daß die Loki-Typlisten und Sequenzen erhalten bleiben, und in Zukunft sogar mehr zum Einsatz kommen, da ich nun im Bereich der Render-Engine viel mit Parameter-Tupeln arbeite. +

+ +
+
+ + + + + + + + + + @@ -58563,6 +58618,7 @@ +
@@ -58763,7 +58819,7 @@
- + @@ -58907,8 +58963,7 @@ ....durch std::apply und std::invoke

- - +
@@ -105693,8 +105748,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) das geht, weil durch das constexpr-if die Funktion jedesmal erneut instantiiert wird, mit dann jeweils anderem deduziertem auto-Returntyp

- - +
@@ -105721,8 +105775,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...denn im Grunde sind alle diese Bindings mit Lambdas relativ banal zu formulieren — es ist halt bloß relativ technisch, versaut den Code und erfordert vom Benutzer viel Präzision und Beachten von feinen Punkten. Da »der Benutzer« auf absehbare Zeit ich selbst bin, ist das — Määh. Ja ich kann das. Wääh

- - +
@@ -105732,8 +105785,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Das klingt nach einer Lösung, die billig zu haben wäre. Es sind ein paar Zeilen recht technischer Code im Node-Builder, der ohnehin in diesem Bereich „nicht mehr schön“ ist. Kann man also in jedem Fall mal einbauen — mein einziger Zweifel betrifft die Nützlichkeit und Relevanz; warum man ausgerechnet ein einziges erstes Argument schließen wollte, will sich mir nicht recht erschließen

- -
+
@@ -105743,8 +105795,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Das ist pre-C++11-Code, nur oberflächlich modernisiert, und bisher nur in einem Bereich testhalber verwendet (für Proc-Commands). Grundsätzlich möchte ich diesen Code aber erhalten, nicht loswerden. Risiko: es gibt wohl einige »Untiefen« — es ist nicht klar, wo Heap-Allokationen stattfinden, und auch der Umgang mit non-copyable oder move-only-Typen ist nicht wirklich ausgeleuchtet. Wahrscheinlich deshalb habe ich vor wenigen Jahren die beiden convenience-Wrapper vom alten Implementierungs-Framework abgekoppelt und direkt per Lambda implementiert — und dann seither doch nicht mehr benutzt (bestätigt die Zweifel bezüglich partieller Applikation nur eines Arguments, das ist dann doch ehr so ein Haskell-Ding)

- -
+ @@ -105785,8 +105836,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) denn std::make_tuple ist ein Template

- - +
@@ -105799,8 +105849,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...weil wir den Processing-Functor jeweils aus dem Prototypen kopieren, dann aber in der Anwendung des Binders nochmal das gespeicherte Element ins Ergebnis kopieren

- - + @@ -105809,8 +105858,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) zwar könnte man auf die Idee kommen, den Adapter hinter den Parameter-Functor zu setzen. Das läßt sich aber in dem hier gewählten cross-Builder-API nicht realisieren, da der Parameter-Functor sofort auf Kompatibilität mit dem Parameter-Tuple-Typ geprüft wird, und obendrein auch sofort dahingehend festglegt wird, daß er ein TurnoutSystem& als Argument bekommt. Ein schrittweises Aufbauen einer Funktor-Kette ist also nur beim Processing-Functor möglich. Es sei denn, man würde eine wesentlich elaboriertere Darstellung finden können, bei der ein Gesamt-Functor-Typ für die Parameter irgendwo in den Template-Argumenten aufgebaut wird.

- -
+
@@ -105824,8 +105872,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...da wir durch das Anwenden auf einen umgebauten Processing-Functor schwenken; deshalb kann auf diesen sodann erneut eine Adaptierung angewendet werden — selbst wenn diese dann schließlich das Parameter-Tupel complett schließt (denn ohne Parameter-Functor erfolgt der Aufruf implizit mit einem default-konstruierbaren Parameter-Tupel, und das leere Tupel ist uneingeschräntk default-konstruierbar)

- - +
@@ -105846,8 +105893,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) RebindVariadic geht nur für Klassen-Templates

- - +
@@ -105859,10 +105905,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + - + @@ -105958,6 +106004,30 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + + + +

+ Das war vielleicht der größte Brocken, und ich hab mich da seit einigen Jahren nicht rangetraut, weil ich eine tagelange »Big Bang«-Aktion fürchtete. Nun mußte ich mir aber für dieses Thema die function-closure-Utils genauer anschauen, und hab verstanden, wie die Definitionen zusammenhängen. Hinzu kommt, daß inzwischen schon ein gewisses Kern-Ökosystem steht, das gleichermaßen mit den variadischen Sequenzen umgehen kann. Das hat mich auf die Idee gebracht, das Thema mit kreuzweisen Brücken zu entschärfen — bei genauerer Betrachtung zeigt sich nämlich, daß ein erheblicher Teil der eigentlichen Manipulations-Funktionen nicht explizit auf NullType angewiesen ist, sondern sich im Wesentlichen auf lib::meta::Prepend abstützt. Und da nun klar ist, daß in Zukunft einmal TySeq einfach die Rolle von Types übernehmen wird, per Umbenennung, ist es möglich, an vielen Stellen Spezialisierungen daneben zu stellen (markiert mit #987), die dann wieder über die richtige Brücke zurück führen. Habe nun gute Hoffnung, daß sich die explizit auf die alten Typlisten angewiesenen Verwendungen schritweise isolieren lassen +

+ + +
+ +
+
+ + + +