Re: test for default history content

On 02-04-14 16:10, Jim Barnett wrote:
> If getTargetStates isn't needed to dereference history states, then it can be
> dropped altogether, because it is returning the same thing as transition.target.

Indeed. Which is how I'm using it.

>
> - Jim
> On 4/2/2014 5:27 AM, Ate Douma wrote:
>> On 02-04-14 00:10, Jim Barnett wrote:
>>> Ate,
>>>     There is a problem if getTargetStates does not dereference history states.
>>> computeEntrySet calls it to produce the initial list of states for
>>> addDescendentStatesToEnter to expand.  If getTargetStates doesn't dereference
>>> history states, they will get added to the statesToEnter list before
>>> addDescendentStatesToEnter gets called - and history states should not be on
>>> statesToEnter. Furthermore, computeExitSet calls getTargetStates, and it will
>>> also need to know what the actual dereferenced target state set is.
>>
>> Right. And I realize I already solved this differently, and IMO elegantly, in
>> my implementation :)
>>
>> The 'hint' leading to my implementation was the fact that
>> addDescendantStatesToEnter (also) stores the state parameter in statesToEnter.
>> And is expected to do so as it recursively is invoked for derived states which
>> were not yet initially added to the statesToEnter.
>>
>> What I thus did instead is the following (in pseudo language):
>>
>>   procedure computeEntrySet(transitions, statesToEnter, statesForDefaultEntry)
>>      enterableTargets = new OrderedSet()
>>      historyTargets = new OrderedSet()
>>      for t in transitions:
>>          for s in getTargetState(t.target)):
>>           if isHistoryState(s):
>>             historyTargets.add(s)
>>           else
>>             enterableTargets.add(s)
>>      for s in enterableTargets:
>> addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry)
>>      for h in historyTargets:
>> addDescendantStatesToEnter(h,statesToEnter,statesForDefaultEntry)
>>      // unmodified below
>>      for t in transitions:
>>           ancestor = getTransitionDomain(t)
>>           for s in getTargetStates(t.target)):
>>               addAncestorStatesToEnter(s, ancestor, statesToEnter,
>> statesForDefaultEntry)
>>
>> This way, no history state is added to enterableStates because
>> addDescendantStatesToEnter only does this for non-history states.
>>
>> Note that addAncestorStatesToEnter will work just fine with a history state as
>> parameter.
>>
>> Finally, concerning computeExitSet: this also isn't a problem in my
>> implementation because I already 'compile' the source of a history transition
>> to that of its parent state, and actually (thus) can 'compile' the
>> transitionDomain and the targets of a transition at document load time.
>>
>> In pseudo-language in the algorithm, this also can easily be catered for if
>> you update getTransitionDomain as follows:
>>
>>   function getTransitionDomain(t)
>>     tstates = getTargetStates(t.target)
>>     if not tstates
>>         return t.source
>>     state = t.source
>>     if isHistoryState(t.source):
>>       state = t.source.parent
>>     if t.type == "internal" and isCompoundState(state) and
>> tstates.every(lambda s: isDescendant(s,state)):
>>         return state
>>     else:
>>         return findLCCA([state].append(tstates))
>>
>> The above can further be optimized by filtering out the history targets from
>> being passed to the lambda expression or from the findLCCA(stateList), but it
>> isn't necessary either.
>>
>> With the above minor improvements, the getTargets(transition) as well as the
>> getTransitionDomain(transition) procedures can remain 'stateless' (not history
>> state aware) and can be compiled at load time.
>> If you add history dereferencing to getTargets(transition) this no longer will
>> be possible, so IMO is something we should try not to do.
>>
>>>
>>> It's a big gap in the algorithm that getTargetStates isn't defined - I'm
>>> assuming that it was in an earlier version, and got lost somewhere.
>>>
>>> In any case we need multiple fixes so that: 1) history states don't end up on
>>> the statesToEnter list and 2) default history executable content gets recorded.
>>
>> See my above proposed changes, AFAICT it solves 1) elegantly and then 2) no
>> longer is an issue (already solved by the earlier update to the algorithm).
>>
>> Regards,
>> Ate
>>
>>>
>>> - Jim
>>> On 4/1/2014 2:45 PM, Ate Douma wrote:
>>>> On 29-03-14 20:26, Zjnue Brzavi wrote:
>>>>> On Sat, Mar 29, 2014 at 1:24 PM, Jim Barnett <1jhbarnett@gmail.com
>>>>> <mailto:1jhbarnett@gmail.com>> wrote:
>>>>>
>>>>>     Zjnue,
>>>>>       I agree that we need more tests, but why would defaultHistoryContent
>>>>> need
>>>>>     to get passed to getTargetStates?  It's just an accessor function.
>>>>> Though I
>>>>>     do think we have to consider how getTransitionDomain and findLCCA should
>>>>>     handle history states. They ignore them at the moment, and _maybe_ that's
>>>>> ok...
>>>>>
>>>>>     - Jim
>>>>>
>>>>>
>>>>> Hi Jim,
>>>>>
>>>>> Perhaps as quick background, my implementation follows (atm) the proposed
>>>>> algorithm pretty much verbatim, in order to aid debugging for cases like this
>>>>> and to make getting started with SCXML a little easier for myself and others.
>>>>>
>>>>> Simply put, the recently published changes to the algorithm for
>>>>> defaultHistoryContent support are not satisfying test579.
>>>>>
>>>>> While the getTargetStates function seems pretty harmless, it is also
>>>>> hisory-aware and can redirect a transition target.
>>>>
>>>> Hi Zjnue,
>>>>
>>>> Sorry for chiming in this late, and going back to this earlier message, but
>>>> I'm puzzled by the above statement.
>>>>
>>>> I can find no indication in the algorithm nor in the specification text that
>>>> the getTargetStates function is supposed to do anything more than just
>>>> returning the direct target(s) of a transition.
>>>>
>>>> It seems to me that the problems you encountered are actually *caused* by the
>>>> the history-awareness and dereferencing in your getTargetStates implementation.
>>>>
>>>> AFAICT the pseudo algorithm expects it will take care of the history
>>>> dereferencing itself in the addDescendantStatesToEnter procedure.
>>>> If you do this upfront in you getTargetStates implementation, the
>>>> addDescendantStatesToEnter never will get to 'see' a history state as it is
>>>> supposed to, and neither can it then handle the default history content as
>>>> just was added.
>>>>
>>>> I just completed the implementation of the current algorithm for Apache
>>>> Commons SCXML (although not yet committed), and I now can successfully run
>>>> test579, so it seems to me the proposed change simply works as expected.
>>>>
>>>> But maybe I'm overlooking some other specification requirements for
>>>> getTargetStates?
>>>> I'd appreciate some pointers in that case :)
>>>>
>>>> Regards, Ate
>>>>
>>>>
>>>>> In the case of test579, the <initial> transition, targets <history id="sh1">,
>>>>> but is effectively redirected to <state id="s01" >, skipping any executable
>>>>> content of <history> along the way.
>>>>>
>>>>> Please take a look at my code for getTargetStates and getTargetState below
>>>>> [1].
>>>>>
>>>>> It is only with the following two lines present in getTargetState:
>>>>>                      if( defaultHistoryContent != null &&
>>>>> h.parent.exists("id") )
>>>>> defaultHistoryContent.set(h.parent.get("id"),
>>>>> h.transition().next());
>>>>> ..that 579 passes.
>>>>>
>>>>> As mentioned, I did not look at it in depth and will not be able to spend more
>>>>> time on it over the next few days unfortunately.
>>>>>
>>>>> So in summary, after adding the published additions to the algorithm, test579
>>>>> did not pass.
>>>>> It was only after the changes to getTargetStates that it did.
>>>>> Hope this helps for now.
>>>>>
>>>>> Thanks,
>>>>> Zjnue
>>>>>
>>>>> [1]
>>>>>
>>>>>      function getTargetStates( node : Node, ?defaultHistoryContent :
>>>>> Hash<Iterable<Node>> ) : List<Node> {
>>>>>          var l = new List<Node>();
>>>>>          if( !node.exists("target") )
>>>>>              return l;
>>>>>          var ids = node.get("target").split(" ");
>>>>>          var top = node;
>>>>>          while( top.parent != null && !top.isTScxml() )
>>>>>              top = top.parent;
>>>>>          for( id in ids ) {
>>>>>              var ts = getTargetState(top, id, defaultHistoryContent);
>>>>>              for( tss in ts )
>>>>>                  l.add( tss );
>>>>>          }
>>>>>          return l;
>>>>>      }
>>>>>
>>>>>      function getTargetState( s : Node, id : String, ?defaultHistoryContent :
>>>>> Hash<Iterable<Node>> ) : List<Node> {
>>>>>          if( s.get("id") == id )
>>>>>              return [s].toList();
>>>>>          else {
>>>>>              for( child in s.getChildStates() ) {
>>>>>                  var ss = getTargetState(child, id, defaultHistoryContent);
>>>>>                  if( ss != null )
>>>>>                      return ss;
>>>>>              }
>>>>>              for( h in s.history() ) {
>>>>>                  var hh = getTargetState(h, id);
>>>>>                  if( hh != null ) {
>>>>>                      if( defaultHistoryContent != null &&
>>>>> h.parent.exists("id") )
>>>>> defaultHistoryContent.set(h.parent.get("id"),
>>>>> h.transition().next());
>>>>>                      return historyValue.exists( h.get("id") ) ?
>>>>>                          historyValue.get( h.get("id") ) :
>>>>>                          getTargetStates( h.transition().next(),
>>>>> defaultHistoryContent );
>>>>>                  }
>>>>>              }
>>>>>          }
>>>>>          return null;
>>>>>      }
>>>>>
>>>>>
>>>>>
>>>>>     On 3/28/2014 8:51 PM, Zjnue Brzavi wrote:
>>>>>>
>>>>>>         I've added test579 to the suite.  Let me know if there are problems
>>>>>>         with it or if you think there need to be more/different tests.--
>>>>>>
>>>>>>
>>>>>>     Hi,
>>>>>>
>>>>>>     Not had a very good look yet, but it appears we'll need to pass
>>>>>>     defaultHistoryContent to getTargetStates as well, as it is another area
>>>>>>     where the algorithm is skipping past some history elements without
>>>>>>     considering their executable content. This diff passes test579 :
>>>>>> https://github.com/zjnue/hscxml/commit/4b9091470d3c7c1995e6b41900535e0437ec3eb4
>>>>>>
>>>>>>     Another test or 2 on the subject is probably a good idea.
>>>>>>
>>>>>>     Best regards,
>>>>>>     Zjnue
>>>>>
>>>>>     --
>>>>>     Jim Barnett
>>>>>     Genesys
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>>
>

Received on Wednesday, 2 April 2014 14:39:33 UTC