attempt to re-use the same traits as much as possible
NOTE: new code not passing compiler yet, but refactored old code
does, and still passes unit test
this is a subtle change which, given all interfaces were used in a logically
consistent way, should not cause any observable change to the yielded elements.
But it changes runtime behaviour, insofar now the evalutaion is initiated
lazily, when first requesting a result type. Prior to this change, the
constructor immediately issued a call to the yield() extension point,
which presumably has the side-effect of preparing the core and initiating
any embedded evaluation, in order to get at the first result; it might
even detect an empty state.
Given the fact that all access operations on the iterator front-end perform
an empty check (and possibly throw at that point), this call is redundant.
surprising behaviour encountered while covering more cases
...obviously the return type of ExpandFunctor::operator()
was inferred as value, even while the invoked functor, from which
this type was deduced, clearly returns a reference.
Solution is simple not to rely on inference, moreover since we know
the exact type in the enclosing scope, thanks to the refactoring which
made this ExpandFunctor a nested class
NOTE:
as it turned out, this is not a compiler bug,
but works as defined by the language:
on return type inference, the detected type is decayed,
which usually helps to prevent returning a reference to a temporary
...while this implementation works now, it is still very complex and intricate.
I am still doubtful this is a good approach, but well, we need to try that route....
but possible only for the iterator -> iterator case
Since we can not "probe" a generic lambda, we get only one shot:
we can try to bind it into a std::function with the assumed signature
This is a consequence of the experiments with generic lambdas.
Up to now, lib::meta::_Fun<F> failed with a compilation error
when passing the decltype of such a generic lambda.
The new behaviour is to pick the empty specialisation (std::false_type) in such cases,
allowing to guard explicit specialisations when no suitable functor type
is passed
Basically we want to support two distinct cases, just by slightly adapting
the invocation of the expansion functor:
Case-1: classical monadic flatMap:
the Functor accepts a value yielded by the source iterator
and builds a new "expaneded" iterator
Case-2: manipulation of opaque implementation state
the Functor knows internal details of the source iterator
and thus takes the source iterator as such as argument,
performs some manipulation and then builds a new sub-iterator
A soulution to reconcile those two distinct cases can be built
with the help of a generic lambda
this solution makes me feel somewhat queasy..
stacking several adaptors and wrappers and traits on top of each other.
Well, it type checks and passes the test, so let's trust functional programming
The plan is to use a monad-like scheme, but allow for a lot of leeway
with respect to the src and value types of the expand functor.
A key idea is to allow for a *different* state core than used in the source
...but does not work as intended:
* just forming an IterStateWrapper does not trigger SFINAE cleanly in all cases
* IterStateWrapper can be formed, even when some of the extension points are missing;
this will be uncovered only later, when actually using one of the operations
but beyond that, the basic type selection logic can work this way
Here, the tricky question remains, how to relate this evalutaion scheme
to the well known monadic handling of collections and iterators.
It seems, we can not yet decide upon that question, rather we should
first try to build a concrete implementation of the envisioned algorithm
and then reconsider the question later, to what extent this is "monadic"
This can be seen as a side track, but the hope is
by relying on some kind of monadic evaluation pattern, we'll be
able to to reconcile the IterExplorer draft from 2012 with the requirement
to keep the implementation of "tree position" entirely opaque.
The latter is mandatory in the use case here, since we must not intermingle
the algorithm to resolve UI-coordinates in any way with the code actually
navigating and accessing GTK widgets. Thus, we're forced to build some kind
of abstraction barrier, and this turns out to be surprisingly difficult.
...which was deliberately represented in an asymmetric way, to verify the
design's ability to cope with such implementation intricacies. So basically
we have to kick in at LEVEL == 1 and access the implementation differently.
This exercise just shows again, that treating tree structures recursively
is the way to go, and we should do similar when coding up the query-API
for the real GTK toolkit based window elements...
...which can be helpful when a function usually returns a somewhat dressed-up iterator,
but needs to return a specific fixed value under some circumstances
- fix some warnings due to uninitialised members
(no real problem, since these members get assigned anyway)
- use a lambda as example function right in the test
- use move initialisation and the new util::join
this fixes a silly mistake:
obviously we want named sub-nodes, aka. "Attributes",
but we used the anonymous sub-nodes instead, aka. "Children"
Incidentally, this renders the definitions also way more readable;
in fact the strange post-fix naming notation of the original version
was a clear indication of using the system backwards....
up to now, we allowed only initialisation with a precisely matching type.
But this special case seems worth supporting, since it typically occurs
within the "object builder" syntax based on Rec::Mutator
the intention is to rely solely upon this abstract interface
in order to navigate the structure of the actual UI, so the
resolution process remains decoupled from the technicalities
of the actual UI toolkit set.
Through implementation of the corresponding unit test we'll determine
what it actually takes to build such a path resolution algorithm...
obviously, we get a trivial case, when the path is explicit,
and we need a tricky full blown resolution with backtracking
when forced to interpolate wildcards to cover a given UICoord
spec against the actual UI topology.
Do we need it?
* actually not right now
* but already a complete implementation of the ViewSpec concept
requires such a resolution