Re: Text terminal rendering design



It is going to take me some time to absorb all of this advice. I
think I can see why I should keep special IDs for Symbols, but it
will require some thought. However, there are a few misunderstandings
that I think can be cleared up easily.

H. S. Lahman wrote:
Responding to Guild...
One is that one needs to associate coordinates with a symbol.
Presumably the client tells you that when asking for a symbol to
be displayed. It would be tempting to put the coordinates in
[Symbol] as attributes.

That is not tempting me in the slightest. I think that would be a
horrible thing, actually! If I had coordinates as attributes of
Symbol then each symbol could only be displayed at one point on the
screen. That alone is more than enough reason not to do it, without
even considering the other reasons.

Whoever is doing the drawing knows the entire finite set of legal
coordinates and it is either directly or indirectly in a distinct
relationship for each of those coordinates. On the other end of each
relationship is a Symbol that needs to be drawn at those coordinates.
I fail to see how any design could be better than that for managing
the position at which a symbol is drawn.

To illustrate:
* (0,0) 1
+-----------+
| * (1,0) 1 |
+-----------+
[Terminal]--| * (0,1) 1 |--[Symbol]
+-----------+
| * (1,1) 1 |
+-----------+

Now I am how giving a reference to a Symbol to the client forces me
to lose what I know about the specific subclass of the Symbol and
therefore forces Terminal to do a dynamic cast. If I give the client
a key into a hash table for Symbols, then I can allow the client to
work with symbols abstractly while maintaining concrete references
within the subsystem.

Of course, instantiating relationships is still not a job for the
factory, since the relationships between a Symbol and the Terminal
are formed at a very different time from the construction of the
Symbol.

The client has some client class Icon of objects that are in a
1:* relationship with a symbol, i.e., Icon objects must always
have an associated symbol. If that symbol is represented
according the the client's view of the symbol, it is immediately
available when each Icon is being constructed. However, if the
client uses an address handle it must wait for the SymbolFactory
to finish instantiation and that time could leave an Icon in an
inconsistent state where an asynchronous process could access it.

That 1:* relationship is an example of where that mapping can get
messy. Why does the client need to know that there might be two
different [Symbol] objects needed to process the display request?

I don't know the answer. It seems to me that the client does not need
to know that. I should not be expected to devise a reason for
something that I feel is unnecessary.

I was referring to the possibility of having two alternative designs,
yours and mine. I was trying to explain why yours was better than
mine. In each design the client only has to deal with one
representation.

That is purely a problem of the way that your UI software needs to
deal with particular terminals. At its level of abstraction all
the client wants to do is display a single symbol, Icon.

In my example, Icon was not a symbol. Icon was a class of objects
where each object needed a symbol. Presumably each object also
represents the semantics that are associated with that symbol. My
point was only that Icon was in a 1:* relationship with Symbol and
any class that had a 1:* relationship with Symbol would have worked
just as well.

I am not sure what you are suggesting this as an alternative to.
My current design does almost exactly this, but instead of having
DataAcquisitionStrategy get data, it gets a Symbol object and we
skip the SymbolFactory step. The rest is entirely the same,
including allowing someone or anyone to check the terminal type
and invoke a converter.

Then I missed something in your explanation. As I understood it,
if you did not need a conversion you invoked a different factory
method -- either in the same [SymbolFactory] subclass or in a
different [SymbolFactory] subclass -- to deal with a situation
like sourcing from the DB or getting data directly from the
client.

That seems to be correct.

If a different method is used for direct, DB, or symbol sourcing,
then the caller has to understand the context of where the
initialization data comes from. If combinatorial subclassing is
used, then instantiating the relationship requires applying the
rules for terminal type and data acquisition at the same time. In
addition you need to encode a unique method for every combination
of data sourcing and terminal type.

That is true as well. Conversion from one format to another is by
nature a combinatorial problem, it seems. When I say 'conversion' I
mean converting a DB format to the terminal format just as much as I
mean converting a Symbol object from one encoding to another.

There is only one way to limit the size of the combinatorial
explosion and my current design supports it.

You have to convert to an intermediate data format and accept an
almost inevitable loss of information. The intermediate format allows
the conversion to proceed in two steps and avoids the effort of
writing a complete set of conversion procedures. This is supported in
my design simply by using one factory to get a Symbol in the
intermediate format and then another factory to convert to the final
format.

A Symbol is only added to the R1 collection when it needs to be
displayed according to the client's UI needs. Therefore, a Symbol
can be created at any time before it needs to be displayed and it
can be added to the R1 collection many and various times after
being created.

That confirms my suspicions of a disconnect over the semantics of
2DArray. Why would the UI create a symbol if it wasn't going to be
displayed immediately?

Just as we have been discussing, creating a symbol is a nontrivial
task involving conversions and DB lookups. It might need to be done
when time is available for such things. The moment at which the
screen is to be updated is frequently not that time.

That only makes sense if one wants to create all the /available/
symbols displayable by a terminal at startup.

I don't think it matters when the client wants to create the symbols.
If the client agrees with you and wants to make them all at startup,
that is no business of the text terminal subsystem. If the client
wants to do it at various times during the running of the
application, that is also harmless.

0..1 R1 displays *
[Terminal]----------------------[Symbol]
To allow for Symbols that are not displayed. If that is the
source of our misunderstanding then I strongly apologize.

That will be true if you instantiate Symbols at startup (or for
other reasons than display). As I indicated above, that is a
disconnect we had.

We have been discussion instantiation of Symbols for other reasons
than display, haven't we? Symbols are often an intermediate step in a
conversion process, and those Symbols are not in any relationship
with a Terminal.

And I cannot imagine why you see it as impossible for the client to
want symbol creation to be at a time other than startup or display.
.