What Parts Can Do - apps4work/co.a4w GitHub Wiki
-
Parts can do nothing - they just are. A Part can represent some data. It is, for example, the digital specific of a shirt. It doesn't do anything, it just is. Such a Part may have be instantiated from some other presentation of the shirt such as a JSON string or a DXF file.It is available for other Parts to work on. Or the Part may have already been worked on, so it presents the work product of those actions, as well as the input specification.
-
A part can be a collection of Parts, such as a collection of shirts. Collections may be able to do simple things, such as add or remove a shirt from the collection, and perhaps find a shirt with particular properties. This is an example of Part coming more that "just data".
-
A Part can be a Part function. Usually this takes one Part and makes one new Part. In general it can take any number of Parts, including zero, and produce one new Part. The one part that it produces could be a collection of Parts, so the production of a single part is not actually a limitation. The relationship between the Pat that it produces an the parts the parts that it is given is up to the function do define and to do. Part Functions can do anything you want to the part. [except that it is not allowed to break the rules of OPL].
The following is a categorization of useful types of Part Function.
Notation note: Part Functions are instantiated classes, that implement PartFunction
specifially apply()
. Therefore use of PartFunction Pf is written new Pf().apply(p)
in proper. Notationally, below, we abbreviate this to a Pf(p)
.
Part Wrappers
Typically a Part Function does not change the subject Parts, but it is not prohibited from doing so, unless the subject part declares itself immutable and declines (by throwing an ImmutablePartException
) all attempts to change it. THe more typical behavior to to wrap the subject Part so that it appears to a consumer to have more or different properties, by adding to or overriding the subject parts properties.
fixme: Part Wrappers are not actually Part Functions -- make it so
Part Filters
A Part Filter function changes the subject Part to appear different, for the purposes of a particular consumer but does not per se have a persistent effect.
Part p = part_from_somewhere();
Part p1 = filter(p);
g1(p1);
g2(p);
The Part that g2 sees is logically the same data as the Part that g1 sees, even if g1 successfully changes its subject part. The filter passes down any change to its subject part, so if g1 appears to alter p1 then filter() alters p in the corresponding way, and therefore g2 sees the change. In contrast, a PartWrapper can have a persistent effect.
Part p = part_from_somewhere();
Part p1 = wrapper(p);
g1(p1);
g2(p);
g2 will not see changes made by g1 to its subject Part.
Ofcourse, if g1 does not make any changes, the difference does not matter.
PartFixer
PartFixer is an abstract Class that helps in writing a Part Filter. (There is no Part Filter Class or inteface; 'filter' is a description of what it does, and does not, do).
PartFixer
offers to its subclasses each sub part and allows it identify and fix any parts. If the PartFixer supports updating the subject part, then it must also "unfix" values that are set. For example, if a Part Fixer "fixes" by doubling every number in the subject part, it must also halve any number that is passed to it before passing the number to he subject part.
PartFixer
operates only the first level children of the subject Part, but subclasses normally return new instances of themselves for children that they don't fix, which cascades the fixing to all levels of the subject Part's hierarchy.
Note again. PartFixer's are part filters. They do not change the subject Part.
PartFixers are inherently lazy. They do not 'fix' a property unless the property is requested by the client.
Lazy operations mean that the 'fixed' data is based on the subject Part's current data at the time of the request, rather than at the time of instantiattion.
Laziness can cause apparently anlous effects, that are only observable through performance or Exceptions. For example:
if G(L(p))
is executed, where L is a lazy funciton, as
1. Part p1=L(p);
2. G(p1);
An exception from L might occur during the execution of line 2. If L is a slow function, line 2 might execute slowly. Going further
1. Part p1=L(p);
2. Part P2=G(p1);
3. G2(p2)
The Exception and/or slowness might not occur until line 3. (and therefore would not occur on Line 2 in this or the previous example). What may be happening is that G2 is asking p2 for a value "X", P2 (which=G(p1)) asks G to ask p2, who asks L for the value of "x" from p. At that time, and only at that time, does p need to produce it's value, L need to fix it, to respond to G, to respond to G2.