Up to this point, we have pretended that when abuild builds an item, it recursively reads the interface files of all its dependencies. Although this is the effect of what the interface system does, it is not exactly what happens. In this section, we will explain what really happens.
     Internally, abuild implements an
     Interface object and an
     InterfaceParser object.  Each
     InterfaceParser instance contains one
     Interface object.  We use one
     InterfaceParser instance to load each
     Abuild.interface file and all of its
     after-build files.  The scope of
     reset and reset-all
     statements is the InterfaceParser
     instance.
    
     Internally, an Interface object maintains
     a list of variables, each of which has a declaration and a list
     of assignments.  Each declaration and assignment is marked with
     the file location (file name, line number, and column number) at
     which it appeared.  Additionally, assignment information includes
     any flag that the assignment may be conditional upon.  Abuild
     does not actually maintain the value of a variable.  It only
     maintains the list of assignments.  Values of variables are
     computed on the fly as they are needed.  For list variables, all
     assignment statements are maintained.  For scalar variables, we
     store first all fallback assignments in the opposite of the order
     in which they appeared (with later fallback assignments being
     pushed onto the beginning of the history), the one normal
     assignment (as more than one normal assignment is an error), and
     then all override assignments in the order in which they appear
     (with later assignments added to the end of the history).  When
     we perform a reset operation on an interface
     variable, we do not store the reset
     operation (other than to record that it happened for purposes of
     showing it in the --dump-interfaces output).
     Rather, we actually clear out the variable's assignment history.
     We discuss this further momentarily.
    
     When a build item or another Interface
     object attempts to retrieve the value of a variable, abuild
     determines what flags, if any, are in effect and filters out any
     assignments that are connected with flags that are not set.
     Then, for list variables, the results of each remaining
     assignment are appended or prepended to the list, depending upon
     whether the list was declared as append or
     prepend.  For scalar variables, only the last item
     in the assignment history is used.  In this way, if there were
     only fallback assignments, the first fallback assignment would be
     at the end of the list.  If there were any override assignments,
     the last override assignment would be at the end of the list.  If
     there were only normal assignments, the normal assignment would
     be there.  It is important that we maintain all of this
     information because we might filter out some assignments based on
     flags.  We discuss this in more depth below.
    
     One Interface object may
     import other
     Interface objects.  When one
     Interface object imports another, the
     object merges the imported object's variable history with its
     own.  Any declarations or assignments that are exactly duplicated
     (that is, they have the same file location as a previously seen
     operation) are ignored.  This is important since we may import
     the same interface file through more than one path.
    
     The import process is the only part of the interface system
     implementation that is affected by the scope of a variable
     (whether the variable is a normal recursive variable or was
     declared non-recursive or local).
     Specifically, when importing an interface, if the variable was
     declared as local, the declaration and assignments
     are both ignored by the import process.  If the variable was
     declared as non-recursive, the declaration is always
     imported, but only assignments that were made in the item that
     owns the interface are actually imported.  For example, suppose
     A imports B's interface
     which in turn imports C's interface.  In
     this case, A would not see the affect of any
     assignments to non-recursive variables that were made in
     C since it does not directly import
     C's interface.  It would also not see
     declarations or local variable assignments to any local variables
     in either B or C.
    
     There is a subtle aspect of how reset works
     in connection with loading interfaces as a result of the fact
     that a reset actually clears the assignment
     history of a variable at the time of the reset operation rather
     than storing the reset as part of the
     history.  For example, suppose you have interfaces
     Q and R and that
     R imports Q,
     Q assigns to variable
     A, and R resets
     variable A.  If interface
     S imports just R,
     it will not see Q's assignment to
     A because that assignment is not part of
     R.  On the other hand, if
     S imports both Q
     and R in any order, it
     will see Q's
     assignment to A.  If the reset operation were
     actually part of the assignment history rather than being a local
     operation, then whether or not S saw
     Q's assignment to A
     would be dependent upon the order in which
     S loaded Q and
     R.  For items that are not in each other's
     dependency chains, the order is not deterministic.  This could
     cause very strange side effects: if one build item depended on
     other, it could sometimes not see all of that item's interface
     because of some third item that did a reset.  Note also that
     abuild uses a single interface parser to load a given interface
     file and any after-build files, so a reset in an after-build
     actually does effectively remove the effect of any assignments to
     that variable in the file that loads it.  Since a reset in an
     after-build file is not visible to the item itself, this is a
     useful construct for clearing interface variables that a build
     item means to set for its own use but not for its dependencies.
     For an example of this construct, see Section 27.1, “Opaque Wrapper Example”.
    
     When a variable assignment is prefixed by a
     flag statement, the assignment entry that
     goes into the variable's assignment history is associated with
     the name of the build item and the flag.  When a variable value
     is retrieved, abuild filters out any assignments that are
     marked with a flag that is not set.  This makes it possible for
     abuild to store exactly one representation of each interface
     object rather than having to keep track of different instances
     for each possible combination of flags.  It also makes it
     possible for different build items to actually see different
     results for the same interface objects depending upon what flags
     they are requesting.
    
     Abuild only turns on interface flags when it retrieves variable
     values for export into the automatically generated file used by
     the back end (the dynamic output file,
     first introduced in Section 17.1, “Abuild Interface Functionality Overview”).  It
     does not have any flags set when it references variables inside
     of other Abuild.interface files.  For
     example, if A does this:
     
declare X string declare Y string X = v1 flag f1 override X = v2 Y = $(X)
     the value of Y will
     always be v1 in every
     build item's dynamic output file regardless of whether or not
     that build item sets the f1 flag in its
     dependency on A.  This is because that is
     the value that X had at the time when
     Y was assigned since the flag was not in
     effect during the parsing of the interface file.  The value of
     X in the dynamic output files
     will be dependent upon whether the flag is
     in effect for the dependency on A because
     abuild does set flags before generating the dynamic output
     files.  This makes sense when you consider that abuild reads
     each Abuild.interface file once for each
     platform and that values of variables are not computed until they
     are needed.