V4 Concepts Introduction

Dimensions and points

Abbreviations Used in This Manual

This manual will make use of the following abbreviations: ctx for context, dim for dimension, isct for intersection, p or pt for point.

Intersections and Bindings

Knowledge is represented by binding the intersection of two or more dimensional points to a value point. One way of conceptualizing this is through the intersection of two or more points in a multidimensional space. At that intersecting point is the value point. The process of associating the intersection of points to a value is called binding. Note that an intersection is itself a point along the Intersection dimension.

The syntax for specifying an intersection is [p1 p2 ... pn] where pi are the points to be intersected. A binding is done by associating a value point to an intersection. There are several ways to do this in V4.

Internal Modules

V4 defines a special dimension, IntMod, and points along this dimension are internally defined modules which the V4 runtime can execute. Syntactically, the user references an internal module like a procedural language module, that is name(p1 p2 ... pn) where name is the IntMod name and pi are the argument points. Internally, internal modules are handled as a two point intersection. The first point being the internal module point and the second being a list of points corresponding to its arguments.

Evaluating an Intersection

An evaluator is a process, which given an intersection, returns the value point associated with that intersection. If the value is itself an intersection then the process (usually) repeats until a non-intersection value is returned.

  Bind [Salary Emp:123] Int:25000 bind NId:Salary and Emp:123 to Int:25000
  Bind [Benefits Emp:123] Int:4000
  = [Salary Emp:123] evaluate the intersection of NId:Salary and Emp:123
  25000 V4 outputs 25000
  Bind [Cost Emp:123] Plus( [Salary Emp:123] [Benefits Emp:123] )
  = [Cost Emp:123] evaluate the intersection of NId:Cost and Emp:123
  29000 V4 outputs the sum of the two nested intersections

In the above example, the cost of employee 123 is defined to be the sum of his salary and benefits. The V4 interpreter evaluates the two nested intersections to Plus and the Plus intmod itself to return the answer of 29000.

Context

A context is an independent set of points with the constraint that no two points belong to the same dimension. Points can be added to the context. If a point is added to the context and another point of the same dimension already resides in the context then the new point replaces the old. For example if Int:20 were in the context and Int:15 was added, then the Int:20 would be replaced with Int:15. A point in the context can be referenced as dim* which means the point value for dimension dim in the context.

Context Frames

The context also supports a frame construct. This is the ability to, in effect, create a stack of linked contexts. Every context frame behaves as a new context set. Referencing a point in the entire context is done by searching the current frame for the dimension, then the prior frame, then the prior-prior, etc. When a frame is removed from the context, all points associated with the frame are also removed.

  Context Add Int:123 add the point Int:123 to the context
  Context Push NewFrame create a new context frame called NewFrame
  Context Add Int:456 add Int:456 to the context
  = Int* determine current Int point on context
  456
  Context Pop pop NewFrame off of context
  = Int* determine now current Int point
  123

In this example, Int:123 is added to the context, then a new frame is created and Int:456 is added. Since a new frame exists with no points, the Int:123 is not replaced but Int:456 is simply added to the new frame. The command 'Context Pop' removes the most recent frame and all points associated with it leaving Int:123 in the context.

Removing a Point from Context

A point can be explicitly removed from the context by using the dim:{undefined} construct. Adding this point replaces a defined point on dim with the undefined point. Note that dim~ may also be used.

Bindings may also be specified with an undefined point-

  Bind [xyz dim:{undefined}] value

The above binding will match only if dim is undefined in the current context.

See also 'Removing Context Points after Binding Match' in the Advanced V4 Concepts section.

Evaluating with Context

Much of the power of the V4 model comes from the ability to evaluate an intersection in a given context. Instead of completely specifying all points in an intersection to be evaluated, V4 permits partial specifications and pulls the remaining points from the current context. This is not easy to comprehend so a few simple examples are in order.

  Bind [Name Cus:123] "John Smith & Sons"
Context Add Cus:123
= [Name]
Alpha:"John Smith & Sons"

In this example Cus:123 is added to the context and the intersection [Name] is evaluated. V4 automatically incorporates all points in the context into the evaluation to come up with the answer. To paraphrase, the evaluation of [Name] is asking 'In the current context what is the name?' and since the context contains Cus:123 we are currently referring to that customer, thus the name in question must be that of customer 123.

The use of the context in evaluating intersections paves the way for a new class of programming environments that can dynamically react to a varying context. Programs need no longer require data to be explicitly defined and referenced. Instead programs can request data by its generic name and let the current context fill in the specifics. For example a context point of language (Language:English, Language:Spanish) can be used to change the prompts and messages on a screen for different users. The dimension point of Calendar (Calendar:Fiscal, Calendar:Yearly) can be used to show sales based on a fiscal year or a calendar year for different users in a large company. The use of dimensions for Prompts, ScreenPosition, and Format can be used to change the way screens and data are formatted based on user, group, or company preferences.

Ambiguity

This capability unfortunately does not come without a price and the two big issues to resolve are performance and ambiguity. The performance issue is getting the evaluator to work at the speeds needed to make this a usable product. As it turns out this is not as hard as it may seem and V4 is currently doing many real world problems on PC based platforms. The ambiguity issue can be demonstrated by the simple example-

  Bind [Name Cus:123] "John Smith & Sons"
Bind [Name Vendor:543] "Smith Supply"
Context Add Cus:123 Vendor:543
= [Name]
  ??? What name- vendor or customer?

Here we have both a customer point and vendor point in the context. What name do we return? The ambiguous nature of this request will be examined later in this manual. Suffice to say that ambiguity can be controlled and in some cases the availability of more that one answer is useful.

V4 provides many syntactic shortcuts to reduce the size of rules. This section briefly describes some of these.

Implicit Dimensions

Although the formal syntax for a point is dim:pointvalue, it is not always neccesary to specify the dimension. The following examples demonstrate how V4 will default a dimension based on the format of the value-

  123 Int:123 (V4 assumes an integer value is on the Int dimension)
  123.45 Num:123.45 (Real numbers default to the Num dimension)
  Now is the time Alpha:"Now is the time" (String literals default to the Alpha dimension)
  +123 Delta:+123 (Integer prefaced with a plus sign default to the Delta dimension)
  -123 Delta:-123 (Ditto for minus signs)
  Sales NId:SALES (Symbols default to the NId dimension)
  (pt1 pt2 ... ptn) List:(pt1 ... ptn) (PointTs enclosed in parentheses are assigned to List)

Two points should be noted. First that the example above of -123 references a point on the Delta dimension, not the Int dimension. Since Delta:-123 and Int:-123 are maintained identically internally this should cause no problems using negative integer literals. Secondly, symbols default to the NId dimension unless another dimension has been assigned to the symbol with the Point command.

Parser Recognized Patterns

Strings enclosed with single quotes are processed by the V4 parser in a special manner. If the string matches any of the patterns as defined by the Recognize command then the string is replaced. For instance, the command

  Recognize '([0-9]+)/([0-9]+)' 'DTInfo(UDate:{now} Month::\1 Day::\2)' Eval

defines a parser pattern that recognizes single quoted strings of the form 'mm/dd' and replaces them with valid V4 points on Dim:UDate for the month and day of the current year-

  [SalesToDate '6/15'] is equivalent to [SalesToDate UDate:030615] (if parsed in the year 2003)

Referencing all points on a dimension - dim.. or dim:..

The dim.. construct denotes all points on a dimension. When it is used in a binding it means that all points on the dimension can be matched. When it is used as a value it represents all the points currently defined on that dimension. This form may only be used on dimensions created with the PointCreate attribute.

  Bind [Sales Year..] Sum(EnumCL(Cus.. @[YearlySales Year*]))

The example above states that Sales for any year (Year..) is defined as the sum of YearlySales for that year for all customers (Cus..). Note how the '..' takes on slightly different meanings on the left and right hand portion of the binding.

Referencing all points on the NId dimension - NId...

The NId dimension is the default dimension for identifiers. It is possible and sometimes useful to reference NId.. in the left hand side of a binding. However doing this may result in much programmer grief unless great care is given. For this reason, the V4 compiler issues a warning whenever it sees the construct 'NId..' within a binding intersection. This warning may be suppressed by using the 'NId...' construct. It is identical in function to 'NId..' and its only purpose is to eliminate the compiler warning.

Referencing the current contextual value of a dimension - dim*

The asterisk is used after the dimension to reference the current value of a dimension. As with '..' above, it can have slightly different meanings as shown by the following example-

  Bind [Age Emp*] Int:43
Bind [Age Emp..] Div(Minus(Date:{now} [DateOfBirth Emp*]) 365)

In the first line, the age of the current employee is defined as 43. In the second example, the Emp* refers to the employee matched by the [Age Emp..] binding, or the current employee at the time of evaluation, not binding.

Referencing the prior contextual value of a dimension - dim**

The double asterisk is used after the dimension to reference the 'prior' value of a dimension. By 'prior' we mean the contextual value not in the current frame but in one of the prior frames.

Creating a new point on a dimension - dim+

New points on dimensions declared with the 'PointCreate New' attribute can be created with either the MakeP primitive or the dim+ construct.

  Context(EDim+)

The above example creates a new point on the EDim dimension and adds it to the current context.

Undefining a Context point - dim~

A point may be removed from the context by adding the undefined reference to the dimension- dim~.

  [pointa pointb ... | dim~]

Evaluates the intersection [pointa pointb] with any points on Dim:dim first removed from the context.

Removing a Point from the Context on Binding Match - ~dim

A point may be removed from the context on a binding match with the dim~ construct.

  Context Add 123 Add the point to the context
  [Int.. square] {Int* * Int*} Define 'square' of an integer
  [~Int.. squareRmv] {Int* * Int*} Define it again with auto-removal of Int point
  = [square] returns 15129
  = [squareRmv] also returns 15129
  = Int* fails because the Dim:Int point was removed from the context on the evaluation of [squareRmv]

Nested Point References - dim.point

Many programming languages support a dot construct that indicates a parent-child relationship or structure-field relationship. For example, Cus.Name references the Name element of the Cus structure (or relation). V4 has no such explicit parent-child relations but can achieve the same results. The example-

  Enum(Cus.. @EchoT([Cus* Id] [Cus* Name] [Cus* State]))

enumerates through all customers and outputs each customer's Id, Name and State. V4 implements a dot structure that allows you to mimic the traditional parent-child meaning. With V4 dim.point is taken to mean [dim* point]. With this we can rewrite the above example as

  Enum(Cus.. @EchoT(Cus.Id Cus.Name Cus.State))

which is less to type and much easier to read. The V4 compiler saves the results of the previous dot construct and permits abbreviations such as

  Enum(Cus.. @EchoT(Cus.Id .Name .State))

where only the first reference needs the 'Cus' prefix. Multiple nesting are allowed- the following two examples are identical-

  Order.BillTo.SlsRep.Manager.Name
[Name [Manager [SlsRep [BillTo Order*]]]]

Projecting a Point into Another Dimension - dim:=point

It is sometimes necessary to convert a point in one dimension into the equivalent point in another. This can be done with the Project module or, more easily with the ':=' construct. For example a floating point number can be converted to an integer (with rounding) in either of these two ways-

  Project(Dim:Int Float:123.567) returns Int:124
  Int:=Float:123.567 also returns Int:124

Projecting a Point into Another Dimension - point->dim

This form of projection is similar to the dim:=point format except that the arguments are reversed. This form permits the user to follow the dim with a period ('.') and then other points.

  a.b->c.d is the same as [Project(Dim:C [a* b]) d]

Creating One List from Another - isct/list

The EnumCL module is used to, in effect, convert one list into another. The form of this module is

  EnumCL(list @isct)

The action performed is to enumerate through each point in list, evaluate isct and create a list of the results of each evaluation. This list is then returned. An alternative way of doing this is with

  isct/list

which is internally converted to an EnumCL call.

Use of the Possessive - dim's pt

A single quote can be used in a binding in place of the dot-dot construct. For example, the following two examples are equivalent-

  Bind [Name Cust..] AggVal(Cust* Dim:Alpha 3)
Bind [Cust's Name] AggVal(Cust* Dim:Alpha 3)

The possessive may also be used within an intersection to be evaluated. The next four statements are also identical-

  Bind [Sale's State] [State Sale's ShipTo]
Bind [Sale's State] [State Sale.ShipTo]
Bind [Sale.. State] Sale's ShipTo's State
Bind [Sale's State] Sale.ShipTo.State

Caching the Result of an Evaluation - < pt pt ... >

Many types of database queries access the same database information several times. With V4, each access results in one or more evaluations. If hundreds of thousands or millions of points are being scanned or tallied then anything to reduce evaluations can improve performance. V4 supports a caching facility that lets the user determine when to cache and when not to. It would be better to have V4 automatically cache but because of the contextual nature this is not yet possible. The following example selects and tallies order by month-

  Bind [SumUpOrders Month..]
Tally(
    (Sum::Order.Amount By::DTInfo(Order.Date UMonth?) Bind::[MonthSales]) )

Evaluating SumUpOrders will evaluate 'In(DTInfo(Order.Date UMonth?)' twice for each order selected. If there are hundreds of thousands of orders then a better way would be to-

  Bind [SumUpOrders Month..]
Tally(
  (Sum::Order.Amount By:: Bind::[MonthSales]) )
Bind [Order.. Month] DTInfo(Order.Date UMonth?)

In the second example, the cached evaluation , will only be evaluated once per order.

Chained Evaluation - isct,isct

It is often useful to evaluate or return a secondary point if the primary intersection to be evaluated fails. For example if we wanted a customer's sales history, by month, for the last three years we might evaluate the list-

  EnumCL( Month:9401..9612 @[Sales Customer*])

which would evaluate the sales for the current customer over all months specified and return the list. However if we did not have any binding/record of sales for the customer for a particular month then we would get an error during the evaluation. This can be corrected with the Def module which tests to see if an intersection evaluates-

  EnumCL( Month:9401..9612 @Def(@[Sales Customer*] 0))

The Def module would return the sales if it evaluated otherwise 0. This works but is alot to enter. To get around this 'problem', the V4 evaluator will evaluate several intersections delimited by commas in an attempt to return a value. If the first intersection in a comma delimited list of intersections does not evaluate, V4 will evaluate the second. If it fails V4 will continue with the third. This continues until the end of the chain (the evaluation fails) or a successful evaluation takes place. Our example from above could be written as-

  EnumCL( Month:9401..9612 @[Sales Customer*],0)

Failed Evaluation of an Intersection

The ability to chain intersections as described above provides a localized method for dealing with evaluation failures. V4 also provides a more global, flexible approach to dealing with intersection evaluation failures. Bindings of the form-

  Bind [UV4:IsctFail ...] value

can be specified. These cause V4 to attempt to evaluate [UV4:IsctFail] in the context of all of the points in a failed intersection. For example suppose the following binding has been declared-

  Bind [UV4:IsctFail Name Cus..] Str("Cus #" Cus* "??")

and the intersection

  Cus.Name

fails, then V4 will attempt to evaluate [UV4:IsctFail] in the context of NId:Name and the current customer. The evaluation would then match the above binding and return "Cus #nnn??" as the name of the customer.

If the binding containing the UV4:IsctFail fails and is followed by another chained intersection (see above) then this processing is disabled during the evaluation of the chain, i.e. this is not handled recursively.

Evaluation 'In the Context Of'

It is sometimes useful to evaluate an intersection in a particular context. While V4 modules exist to do this, it is useful to be able to specify a context as part of the evaluated intersection. The syntax for this is-

  [ point1 point2 ... | context1 context2 ... ]

where the pointi are the points to be evaluated and contexti are points to be added to the context for the duration of the evaluation.

Infix versus Prefix Notation

V4 uses what is known as prefix notation for most of its operations. For instance to add two numbers, V4 uses 'Plus(num1 num1)' rather than 'num1+num2'. Some users find this awkward and prefer to use the more traditional infix notation. This can be done within V4 by enclosing an expression in braces. The following two examples are identical.

  If::GT(Order.Amt Div(Cus.YTDSales 1000))
If::{Order.Amt > Cus.YTDSales/1000}

Either method is acceptable and can be freely intermixed. The following table lists the allowed operators and V4 internal module equivalents

Table 1 - Infix Operators

+ Plus        = EQk
- Minus        == In
* Mult        < LT
/ Div        <= LE
// DDiv        > GT
% Percent        >= GE
~ Not        <> NE
| Or        & And
~= nIn

Dimension Synonyms

A dimension can be given multiple synonyms. If a dimension is referenced which is currently undefined then the V4 interpreter will attempt to evaluate-

  [UV4:DimSynonym NId:dimension]

where dimension is the name of the synonym. If the evaluation succeeds and returns a valid dimension point then that is used as the actual dimension.

The none Value of a Dimension

The CSMD model represents concepts as dimensions and instances of concepts as point on dimensions. The theoretical notion of none-ness seems contrary to the model. Why have a point to represent no points on a dimension? Pragmatically though, it can be quite useful. For instance one way to model an input form is to assign a different dimensions to each input element. Entered values become specific points on each of the dimensions. But what if a date or numeric element is blank? What point on the date/numeric dimension should be assigned? V4 resolves this issue by defining none values for many types of points including time and numeric. Alpha points do not require a none value because an empty string is a valid point.

The none values for time points is implemented with special values that cannot be confused with valid time points. For example, UDate:none is stored as zero (UDate:#0) because that is not a valid date. Other date-time points implement the none value in a similar fashion.

Numeric points cannot be handled this way because there are no inherently invalid values for numbers. Numeric none values are treated as special point values within V4, not as a specific numeric value. Nonetheless one might want a numeric none value to be considered identical to a particular numeric value. This can be done when a dimension is declared by specifying the NONE attribute within the Dimension command.

Projecting a none value into an integer or real point forces the point into its assigned none-value. If no such value has been defined then the projection fails.

  Dim Value Integer None 0 Defines a Value dimension, substitute Value:0 for Value:none
  Context Add Value:none Add point to context
  EQ(Value* Value:none) results in Logical:True
  {123 + Value*} results in Value:123
  Int:=Value* results in Int:0 (not Int:none)

Auto-Intersection Points

All evaluations within V4 are triggered by intersections and internal modules. Occasionally it is convenient to be able to force the intersection of a point. This can be done by declaring the AutoIsct attribute to a dimension. The following example show how-

  Dim Field AutoIsct
Point Field Name Address City
  Bind [Cus.. Name] AggVal(Cus* Dim:Alpha 3) Define name of customer as third field in aggregate
  Context Add Cus:xxx Add customer xxx to context
  = Name As if entered [Name]

Sample Points

Sometimes it is necessary to determine if a binding or rule exists on a specific point or dimension. This typically occurs in V4 bindings that are used to auto-construct other V4 bindings. The Def module can be used to see if an intersection is defined but the problem becomes selecting points to use to test. For example, suppose we had bindings such as-

  Bind [Order.. Column:Date] value

which defines the date of an order. Suppose we wanted to write a general rule such as

  Bind [TestDim.. Column..] true-or-false

which would return true if the Column point was defined on the shell dimension TestDim. We have no way of knowing what points can be associated with the dimension specified by TestDim- integer? date? alpha? ... To resolve this problem, V4 supports a 'sample point' for each dimension allowing our test to be written as-

  Bind [TestDim.. Column..]
Def(MakeI( MakeP(TestDim* Special::Sample) Column*) Logical:True Logical:False)
= [TestDim:Dim:Order Column:Date]

The evaluation tests whether or not '[Order:{sample} Column:Date]' is defined and returns true or false.

Removing Context Points after Binding Match

Once a point is inserted into the context it remains there until it is replaced by another point of the same dimension, it is explicitly removed, or the frame in which it resides is destroyed. It is also possible to have one or more points removed as a result of matching to a binding. Consider the example below-

  Context Add dim1:100 Add point to context
  [whatIs dim1..] Echo("dim1=" dim1*) Create binding
  Eval [whatIs] echos "dim1=100"
  [readAndRemove ~dim1..] Echo("dim1 was " dim1*) Another binding, note tilde prefix on dim1
  Eval [readAndRemove] echos 'dim1 was 100' AND removes dim1 from context
  Eval [readAndRemove] fails, dim1 no longer in context

The tilde prefix, '~', may only be used within an intersection. The dimension is removed from the context only after the succesful evaluation of the binding. If the evaluation fails, no dimensions are removed.

Inheritance - IsA Relations

Inheritance is a powerful feature of object-oriented languages. It lets you define rules and facts for entire families of data types. A similar facility is available within V4 when a dimension is declared with the HasIsA attribute. Consider the example below-

  Dim ShipDate UDate
Dim OrderDate UDate
Dim EntryDate UDate
Dim PickDate UDate
Here we have defined four dimensions, all of type UDate. If we wanted to define a rule that would give us the month associated with a date we could-
Bind [ShipDate.. Month] DTInfo(ShipDate* UMonth?)
Bind [OrderDate.. Month] DTInof(OrderDate* UMonth?)
...

This would allow use to conveniently get the associated month with any of the dates, but at the expense of having a separate rule for each dimension. If we had multiple dimensions and multiple rules the number of bindings would increase with the product of the two. With inheritance we can simplify this. In the example below we define a new dimension, GenDate, which is our generalized date. We use a special binding to declare each of the date dimensions to be an instance of the generalized date-

  Dim GenDate UDate
Dim ShipDate UDate HasIsA
Dim OrderDate UDate HasIsA
Dim EntryDate UDate HasIsA
Dim PickDate UDate HasIsA
Bind [UV4:IsA ShipDate..] Dim:GenDate
Bind [UV4:IsA OrderDate..] Dim:GenDate
Bind [UV4:IsA EntryDate..] Dim:GenDate
Bind [UV4:IsA PickDate..] Dim:GenDate
Bind [GenDate.. Month] DateInof(GenDate* Month?)

Here we only have to define one rule on GenDate, not separate rules for each dimension. In this example, it hardly seems worthwhile to add the four extra 'UV4:IsA' bindings to save on three 'Month' bindings. But as soon as we add another rule (such as Year!) we reduce the total number of bindings from eight (4 x 2) to six (4 + 2), with five rules we reduce the total number of binding from 20 (4 x 5) to nine (4 + 5).

The HasIsA attribute is not limited to a single level. If the declaration of dimension GenDate included a HasIsA then yet another level would be added.

It is important to note that 'UV4:IsA' bindings can be any form of V4 binding. We could just as well define ShipDate with several bindings-

  Bind [UV4:IsA ShipDate:900101..961231] Dim:GenDate
Bind [UV4:IsA ShipDate:>=970101] Dim:RecentDate
Bind [UV4:IsA ShipDate.. WhatIf:Debug] Dim:DebugDate

Here we have defined three different 'parent' dimensions for ShipDate based on date ranges and other contextual circumstances. This capability greatly extends the inheritance model found in classical object-oriented methodologies.

Multiple Matches

Sometimes an evaluation can result in more than one possible answer. In most cases, V4 returns what it considers the best answer and the fact that other possible answers were available is ignored. There are situations when it is necessary to work with more than one possible answer.

An example of this is in an order entry environment where a customer has been promised the best price. In any kind of large order-processing system, an item will have many possible prices depending on the item, the customer, the quantity ordered, the catalogue ordered from, other items in an order, and so forth an so on. In order to give the best price, one must be able to access all possible prices in a given situation and choose the smallest.

Another class of problems utilizes the ability of V4 to manipulate all possible matches in descending priority of goodness. To be able to reference the next best point is very useful in what-if scenarios. For example, suppose we are trying to determine if a new packaging system is worth the capital investment. The system can reduce shipping weight by 5% and costs $75,000. By reviewing shipments over the last n months and recosting we should be able to make an informed decision based on the amount saved over a given period. However our costing module is a black box which takes an order and returns the cost to ship it (weight is only a partial component of shipping costs, zones, shipping methods, time requirements all come into play). Rather than create a new order file with weights reduced by 5%, we would like to say, 'For this purposes of this scenario, reduce order weights by 5%. With V4 this can be done with:

  Bind [Weight Order.. Scenario:FivePC] Mult( [-] Real:0.95 )

This binding defines the Weight of all orders (Order..) in this what-if scenario as being 0.95 times what the weight would have been ([-]) had we not matched this binding.

Time

V4 supports the concept of time and the more general case of time varying points (such as the software releases or transaction processing) as a special type of dimension. In all other dimension types, the evaluator attempts an exact match of points to return a value. With points on a time dimension, V4 attempts a greater-than-or-equal match. For example:

  Bind [Name Cus:123 Time:100] "Miss Smith"
Bind [Name Cus:123 Time:150] "Mrs. Jones"
Context Add Time:120
= [Name Cus:123]
Alpha:"Miss Smith"

In this example, the evaluator requires an exact match on the NId dimension (Name) and Cus dimension, but not on the Time dimension. In the context of Time:120, the proper name for Cus:123 is "Miss Smith". The example below demonstrates the use of time within V4-

  Bind [MaritalStatus Person:John Time:10] "Single"
Bind [MaritalStatus Person:John Time:20] "Married"
Bind [MaritalStatus Person:John Time:30] "Divorced"
  Bind [What:IS List..] [`List*] What:IS evaluates at current (context) time
  Bind [What:WILL List..] [`List* | Time:{undefined}] What:WILL evaluates at undefined (future) time
  Bind [What:WAS List..] IsctVals( @[`List*] Int:2 ) What:WAS evaluates R* at one match before current
  Context Add Time:25
  [What:IS MaritalStatus Person:John] Alpha:"Married"
  [What:WAS MaritalStatus Person:John] Alpha:"Single"
  [What:WILL MaritalStatus Person:John] Alpha:"Divorced"

Relative Date Calculations

V4 supports an extensive suite of calcuations for UYEar, UQuarter, UMonth and UDate date types. The table below summarizes the allowed calculations. Note that these can be chained in any meaningful length.

Table 2 - Date Calculations

Start Calculation Description Example Result
date .num converts the date to the numth day of the month UDate:5/16/2008.10 UDate:5/10/2008
date +num adds num to the date UDate:current+3 three days from now
date -num subtracts num from the date UDate:1/1/2010-1 UDate:12/31/2009
date .first the first day of the month UDate:6/12/2005.first UDate:6/1/2005
date .last the last day of the month UDate:6/12/2005.last UDate:6/30/2005
date .half either the first or fifteenth day of the month depending on current date UDate:11/20/08.half UDate:11/15/08
date .month converts the date to the month in which the date resides UDate:3/22/07.month UMonth:3/07
date .qtr converts the date to the quarter in which the date resides UDate:3/22/07.qtr UQuarter:1/07
date .year converts the date to the year in which the date resides UDate:3/22/07.year UYear:2007
date .dow the closest date falling on the day-of-week UDate:7/22/09.mon UDate:7/20/09
date +dow the next date falling on the day-of-week UDate:7/22/09+mon UDate:7/27/09
date -dow the prior (or current) date falling on the day-of-week UDate:7/22/09-wed UDate:7/22/09
date .month the closest month relative to the date UDate:8/22/09.jan UMonth:1/2010
date +month the next month relative to the date UDate:7/22/09+sep UMonth:9/2009
date -month the prior (or current) month relative to the date UDate:7/22/09-sep UMonth:9/2008
month .num converts the date of the numth day of the month UMonth:5/2008.10 UDate:5/10/2008
month +num adds num to the month UMonth:1/2010+2 UMonth:3/2010
month -num subtracts num from the month UMonth:1/2010-1 UMonth:12/2009
month .current Converts the month to date within that month corresponding to today's date UMonth:3/2008.current UDate:3/5/08 (assuming today is fifth day of month)
month .first the first month of the year UMonth:6/2005.first UMonth:1/2005
month .last the last month of the year UMonth:6/2005.last UMonth:12/2005
month .half either the June or July of the year depending on month UMonth:11/08.half UMonth:7/08
month .qtr converts the month to the quarter in which the month resides UMonth:3/07.qtr UQuarter:1/07
month .year converts the month to the year in which it resides UMonth:3/07.year UYear:2007
quarter .num converts the quarter of the numth quarter of the year UQuarter:2005Q1.4 UQuarter:2005Q4
quarter +num adds num to the quarter UQuarter:2010Q3+2 UQuarter:2011Q1
quarter -num subtracts num from the quarter UQuarter:2010Q1-1 UQuarter:2009Q4
quarter .first the first month of the quarter UQuarter:2009Q3.first UMonth:7/2005
quarter .last the last month of the quarter UQuarter:2005Q4.last UMonth:12/2005
quarter .year converts the quarter to the year in which it resides UQuarter:2006Q2.year UYear:2006
year .num converts to the numth month of the year UYear:2008.10 UMonth:10/2008
year +num adds num to the year UYear:2010+2 UYear:2012
year -num subtracts num from the year UYear:2010-1 UYear:2009
year .current Converts the year to month within that month corresponding to today's date UYear:2008.current UMonth:5/2008 (assuming it is May)
year .first the first month of the year UYear:2005.first UMonth:1/2005
year .last the last month of the year UYear:2005.last UMonth:12/2005
year .Qn converts the year to the quarter UYear:2007.Q3 UQuarter:2007Q3

Below are some examples of date calculations.

  UDate:current-jan.1..current the date range from the beginning of the year to today
  Udate:current.month.half.1..current.month.half+6.1-1 from the first day of the current half of the year to the last day
  Udate:current-mon..current-mon+6 the current week from Monday through Sunday
  UYear:current.11.7-thu+21 the fourth Thursday of November - Thanksgiving

What Are UV4 Points

The UV4 dimension is a dimension reserved for triggering special V4 actions. Various exceptions, failures, and initializations are handled within V4 by evaluating an intersection containing a UV4 point. For example if an intersection evaluation fails then a behind-the-scenes evaluation of [UV4:IsctFail] may take place. If this evaluation succeeds then the result is returned as if it were the result of the original triggering evaluation.

UV4:AcceptorFail - Trapping Improperly Formatted Dimension Points

When the V4 parser rejects a dimension point (for whatever reason but usually invalid syntax), it creates an intersection of the form [UV4:AcceptorFail Dim:dimension Alpha:pointspecification] and evaluates it. If the evaluation succeeds then the value is is used as the point value.

  [UV4:AcceptorFail Dim:UDate Alpha..] UDate:{now} Use today's date on any erroneously specified dates

UV4:Acceptor - User Defined Acceptor for Point Values

The declared point type of a dimension usually defines the syntax of points on that dimension. The use of the Acceptor attribute in the declaration of a dimension along with a UV4:Acceptor binding enables the programmer to define a custom acceptor for dimension points.

When a dimension is declared with the Acceptor attribute, then the V4 parser creates an intersection of the form [UV4:Acceptor Dim:dimension Alpha:pointvalue] and evaluates it. The evaluation should return a point of the same dimension as dimension (although V4 does not enforce this).

If a dimension is declared with the ADPoint attribute then a slightly different intersection is evaluated. In this case [UV4:Acceptor adpoint Alpha:pointvalue] where adpoint is the point given for the ADPoint attribute.

If a point specification begins with the "#" character then this Acceptor processing is disabled and the value following the "#" is taken, as is, as the point value.

The example below maps Branch:Test to Branch:#1, Branch:Sales to Branch:#1,#2,#5, and all others by attempting to match the point value to one of the values of Branch.Id.

Example 1 - A Dimension Acceptor Example

  Dim Branch Int Acceptor
[UV4:Acceptor Dim:Branch Alpha..]
 TEQ(BrId:=Alpha*
   BrId:Test Branch:#1
   BrId:Sales Branch:#1,#2,#5
   Enum(Branch.. If::{Branch.Id = BrId:=Alpha*} Then::Branch*),Branch:#0)

Example 2 - Multiple Dimensions Using Same Acceptor Via ADPoint

  Dim OEPromo Int Acceptor ADPoint ETbl:70 Multiple
Dim OESource Int Acceptor ADPoint ETbl:41 Multiple
Dim OEType Int Acceptor ADPoint ETbl:174 Multiple
Dim Office Int Acceptor ADPoint ETbl:133 Multiple
[UV4:Acceptor ETbl.. Alpha..]
 Enum(ETbl.Entries If::{ETblE.Input = Str(Alpha* UC?)} Then::ETblE.ETblIV),
  EchoE("No entry (" Alpha* ") in Table #" Str(ETbl*) " - " ETbl.Name)

UV4:CodedRange - Initialize CodedRange Dimension

The UV4:CodedRange point is used to initialize a dimension's coded range table. It is invoked within the In module as [UV4:CodedRange dimension] and would most likely result in a call to the V4 module to initialize then range.

  Dim ProgId CodedRange DotDotToList Acceptor Displayer Multiple Defines CodedRange dimension
  [UV4:CodedRange Dim:ProgId] V4(Dim:ProgId Number::200500 Range::200501..200509) Defines the number 200500 to include the range 200501..20509
  {ProgId:#200503 == ProgId:#200500} results in Logical:True
  {ProgId:#200534 == ProgId:#200500} Logical:False

UV4:Definition - A Table or Macro Definition

The Set MacroSave and Set TableSave commands tell V4 to save the source code definitions. The definitions are store under bindings of the form [UMacro:macro UV4:Definition] and [UTable:table UV4:Definition].

  [UMacro:Demo UV4:Definition] returns the definition of the Demo macro

UV4:DimSynonym - Dimension Synonyms

When V4 parses a dimension reference to a non-existent dimension it attempts to map that dimension reference to an existing dimension by creating an intersection of the form [UV4:DimSynonym NId:dimreference] and evaluating it. If the evaluation succeeds and returns a point on the Dim dimension then that dimension is used. This allows the designer to create any number of synonyms for a dimension.

  [UV4:DimSynonym Div] Dim:Division Creates the synonym "Div" for the "Division" dimension

UV4:Displayer - Custom Point Displayer for Points on a Dimension

The UV4:Displayer point is used, along with the Displayer attribute in the Dimension declaration, to control the output formatting of a dimension's points. It is often used in conjunction with the Acceptor attribute and UV4 point. When a dimension point is to be displayed, V4 evaluates the intersection [UV4:Displayer dimension..] and output the result of the evaluation.

Note: This output formatting is disabled when the point is output as part of a trace or debug message by the V4 runtime. The Str module can be used to force formatting via this convention.

The example below demostrates a displayer for the Branch dimension. A Branch point is displayed as its corresponding Branch.Id value.

Example 3 - An Example of a Dimension Displayer

  Dim Branch Int Displayer
[UV4:Displayer Branch..]
 Is1(Branch* Branch.Id,BrId:UNK MakeP(Dim:BrId `EnumCL(Branch* @Branch.Id,BrId:UNK)))

UV4:DisplayerTrace - Custom Displayer for Points within Traces and Context Dump

The UV4:DisplayerTrace point is used is similar to the UV4:Displayer except that it is used by V4 to display point values when a context point is displayed (error traces, Context Examine dumps). This option may be used for special formatting of a point within a trace to make it easier to read and/or debug. It may also be used to inhibit or alter the value of a point within the context (such as a credit card number) that you do not want to inadvertantly display.

UV4:DotDotToList - Converting dim.. to a List

The dim.. construct is useful for referencing all points on a dimension. In some cases, however, the points on a dimension are not known ahead of time. The UV4:DotDotToList point can be used to trigger an evaluation which then returns a list calculated at that instant in time. Dimensions that refer to external databases should use this feature to determine, at run time, its points.

Note: The dimension must be declared with the DotDotToList attribute for this function.

  Dim UYear Local DotDotToList This attribute must be defined for the dimension
  [UV4:DotDotToList Dim:UYear] Transform(UYear:{now} First::{UYear* - 3} Last::{UYear* + 3}) Defines UYear.. to be the 3 prior years through the three following years

UV4:EvalStream - The name of the Evaluate output stream

The UV4:EvalStream point is the name given to the output stream when redirection to a file is specified with the Evaluate command. This can be used when multiple output streams have been created and this stream is no longer the default.

UV4:IsctFail - Trapping Evaluation Failures

The UV4:IsctFail point is used to "trap" evaluation failures and generate a point that is to be used as the result of the failed evaluation. It is most useful in providing values for missing database points. The UV4:IsctFail point is removed from the context before any nested processing occurs.

It is extremely easy to be burned by this feature. Understanding its operation is important. When an evaluation fails, the V4 interpreter checks to see if the UV4:IsctFail point has been defined. If not then the evaluation continues as a failure. If the UV4:IsctFail point is defined then all of the points of the failed intersection are added to a new context frame and then [UV4:IsctFail] is evaluated. If it returns a result then it is used as the value of the failed evaluation. If an intersection is followed by a ,point then this processing does not occur unless the following point also fails.

  [UV4:IsctFail Cus.. Id] Str("?CusId(" Cus* ")?") Defines a value if Cus.Id fails

UV4:EvalAE - Processing Points within the EvalAE Module

This point is used in the evaluation of EvalAE expressions. Tokens appearing within the module are evaluated via [UV4:EvalAE token].

UV4:EvalAEVal - Validating Points within the EvalAE Module

This point is used in the validation of EvalAE components. Points appearing within the module are evaluated via [UV4:EvalAEVal point].

UV4:EvalLE - Processing Points within the EvalLE Module

UV4:EvalLEStar - Processing Starred Points within the EvalLE Module

UV4:EvalLEVal - Validating Points within the EvalLE Module

This point is used in the validation of EvalLE components. Points appearing within the module are evaluated via [UV4:EvalLEVal point].

UV4:TableDefine - Attempt to define a V4 Table

The UV4:TableDefine point is used to define a V4 table at run-time if the table is not already defined. Whenever a table is referenced (ex: the Include command) and it is not currently defined then V4 will evaluate [UV4:TableDefine name] where name is the currently undefined table. If the evaluation results in the definition of the table then V4 continues. If the table is still undefined then an error is generated.

UV4:UOMCoerce - Coercing a Unit-of-Measure to another Type

UV4:UOMInitialize - Initializing Unit-of-Measure Tables

V4 Point Specification Summary

dim*Represents the point on dimension dim in the current context.
dim**Represents the point on dimension dim in the prior frame in the current context.
dim..Represents all points on the dimension.
dim:valueRepresents a particular dimension point. The syntax of value depends on the declaration of the dimension.
:valueA particular dimension point where the dimension is taken from the prior point.
dim:{Context}References the current value of the dimension in the context (same as dim*).
dim:{Now}References the point on the dimension corresponding to 'now'. This is only valid for time related points.
dim:{New}Creates a new point on the dimension.
dim+same as dim:{New}.
dim:{Sample}Creates a sample point for the dimension.
dim:{Undefined}Creates an “undefined” point for the dimension. This point may be inserted into the context to effectively remove a point from the context.
dim~same as dim:{Undefined}.
~pointOnly valid within a binding intersection. Specifies that the dimension of point is to be removed from the context after successfully matching the binding and evaluating the value.
dim:<valueAll points of the dimension less than value.
dim:<=valueAll points of the dimension less than or equal to value.
dim:>=valueAll points of the dimension greater than or equal to value.
dim:>valueAll points of the dimension greater than value.
dim:<>valueAll points of the dimension not equal to value.
dim:p1..p2Denotes points p1 through p2 on the dimension (example Int:1..10)
dim:p1,p2Denotes points p1 and p2 on the dimension (example Color:Red,Blue)
dim.pointIs equivalent to the intersection [dim* point]. More than one point is allowed in this construction. “Customer.SalesRep.Manager.Name” reads “the name of the manager of the salesrep for the current customer and expands out to [Name [Manager [SalesRep Customer*]]].
.pointAssumes dim.point where dim is the dimension of the prior dim.point construction.
intersection,pointIf the evaluation of the intersection fails then use point as the value. Multiple points can be given. [Sales Customer* Month:99-Jan],{[Sales Customer Year:1999] / 12},0 first attempts to evaluate the sales for the current customer for January 1999. If that fails then it tries to determine the sales for the entire year and divide by 12, and if that fails it results in 0.
intersection,,pointThe double comma can be used for debugging when you want to see the failure of the first intersection. With this construction, the point is ignored.
dim:=pointCoerces point into dimension dim. This construct can be used to convert a point on one dimension to another. Obviously it is only defined in certain cases. The V4 runtime supports many arithmetic, string, and date-time conversions. For example, Month:=Date* coerces the current date to the corresponding month.
point->dimCoerces point into dimension dim. This construct is similar to the above but can be followed with a period ('.') and additional points (ex: a.b->c.d).
intersection=valueThe binding of an intersection to a value point.
name[. . .]This is an array reference identical to Array([name] . . .)
name[Dim:dim . . .]An array declaration identical to BindQE([name] Array(Dim:dim . . .))
@pointA quoted point. Normally, the V4 interpreter evaluates each argument point of a module. Quoted points are not evaluated. Note that modules ending in ‘Q’ imply the quoting of one or more arguments.
`pointForce the evaluation of the point When this is a module argument and the result is a list then each point in the list is considered to be a separate argument to the module.
intersection*The evaluation of an intersection which is then inserted into the context.
point1/point2Equivalent to EnumCL(point2 @ point1). The point Maximum([Salary]/Emp..) evaluates the salary of all employees and returns the largest.
tag::pointA tagged point may only be used as an argument to a V4 internal module. The tag simply identifies the point as a particular type of argument. A single colon separates a dimension from its value point, two colons separate a tagged value from its point value.
tag?A tag value reference. A module containing a tag value reference usually returns the value specified. For example Str(stringpoint Length?) returns the length or number of characters in stringpoint.
tag:::pointThis syntax is, in most cases identical to the two-colon format. Within certain modules, a three-colon tag indicates no change if an error occurs. For example Str(string1 Before::string2) returns the characters of string1 up to the first occurance of string2. An error is generated if string2 does not appear in string1. However, with Str(string1 Before:::string2) the entire string1 is returned if string2 does not occur within it.
{ expression }All operations within V4 are via internal modules, there are no infix operators such as “+” or “/”. This can get confusing for most of us who are used to infix operations. The V4 interpreter will convert a traditional infix expression to prefix form when the expression is enclosed in braces. For example {Rep.Sales * [Commission]} is converted to Mult(Rep.Sales [Commission])
module(arg1argn)A module reference.

V4 Interpreter Command Introduction

The V4 evaluator is a text command driven interpreter. It is used to both load bindings into V4 areas and to evaluate intersections, usually with bindings and information previously loaded.

Command Format

All commands in V4 are of the form:

  Command arguments

where Command is the V4 command and arguments is the argument string for the command. Commands are usually a single line with the end-of-line indicating the end of the command. However there are cases where multiple lines are required. V4 can usually determine this from the syntax. In several rare cases, V4 cannot determine the end of a command and a semi-colon must be used to end the command. Note that this is true of all commands embedded within a macro.

Abbreviations

Commands may be abbreviated to the shortest unambiguous string. 'Evaluate' can be abbreviated to 'Ev', 'Dimension' to 'D'. In general, it is a good idea to use at least the first three characters for readability.

Comments

Comments may be included anywhere by enclosing them in '/*' and '*/'. Any line beginning with an exclamation point '!' is also treated as a comment line. The one exception to this are lines beginning with '!{/' and '!}/' which are also considered macro header and trailer lines, not comments. This is used as a compatibility feature between V3 and V4.

Device Logicals

Logical device names may be specified on any file references within V4. A logical device is a name followed by a colon which precedes the filename and replaces the usual device-directory path of the filename. Logicals allow the V4 designer to re-target files to different directories without having to change any V4 code. Logicals also allow V4 code to be ported to many different operating systems without having to worry about the operating system specific syntax.

On VMS systems, logicals are handled directly by the operating system. On Unix systems, logicals are defined as symbols within the shell and become part of the V4 process environment. On NT systems logicals are defined either in the registry or as symbols in the command shell. In Windows95/98 symbols are defined in the command shell.

When a logical specifies multiple directories, V4 searches in the order the directories are listed. When a new file is to be created, V4 will first search all directory paths looking for an existing file. If one is found, it is replaced. If no file is found then a new file is created in the first directory path.

The V4 startup switch '-s' may be used to define logicals for the duration of a V4 process. The command Set Logical may also be used to (re)define logicals within a V4 process.

Macros

Macros may be defined within the V4 interpreter by enclosing one or more V4 commands within a macro body. The format of a macro is-

  {/macroname( argumentlist )
macro body - one or more V4 commands
}/macroname

Note that the macroname must be given to both begin and end the macro. The argumentlist is an optional list of dummy arguments. Multiple arguments are separated with commas.

A macro is invoked as if it were a V4 interpreter command. A macro invocation must include both the macro name immediately followed by a left parenthesis. If the macro call does not involve arguments then a right parenthesis follows the left parenthesis. Arguments may be any valid V4 lexical token. If macro argument consisting of multiple tokens must be enclosed within '<...>'. If the argument includes a '>' then the argument may be enclosed within '<<...>>'. A null argument may be specified as '<>' (see the 'If Defined' command).

Arguments may be specified in the order in which they appear in the declaration or named with the 'name=value' construct. If all the macro arguments begin with the same letter then that letter may be omitted when using the name=value construct. This can be useful as it allows one to create unique argument names (that do not conflict with similar V4 points) yet allow the caller of the macro to use the normal spelling.

There are two special constructs allowed within the argumentlist. The first is the '*'. When this is given then additional arguments may be included in a macro call (i.e. arguments that are not defined within the formal argument list. Any/all of these arguments are aggregated into a single list and may be referenced within the macro as 'udaList' (undefined argument list). A general syntax for these arguments is allowed. The format is: name[.name ...]=value where name is either a simple name or dim:value. Any number of these may be concatenated together with the dot construct. See the examples below for typical usage.

The udaList value is actually a list of lists. Each sublist within udaList represents a single argument. The sublist is itself a list of two values. The first value represents the left-hand side of the argument assignment, the second is the value of the argument assignment. See the examples below for typical usage.

The second special construct within the argumentlist is '...'. When this is given then '...' is allowed within the macro call. All subsequent text on the next and subsequent line is considered to be a single BigText value which continues until '</macroname> is encountered. The string may be referenced as 'btArg' within the macro. Any of the BigText options (ex: Javascript) may follow the ...

Macro arguments are not evaluate as part of the macro call. You can force the evaluation of a macro argument by prefacing it with a backquote (`).

If a reference to a macro argument (within the macro body) is followed with a dollar sign ('$') then the argument is converted to a V4 string. If the argument is followed by two dollar signs ('$$') then the argument is converted to a form that is suitable as the argument to another macro.

Example 4 - Macro with Optional Arguments

  /* Use common prefix "a" for arguments (ex: aDD argument not confused with NId:NN in [DD Func*]) */
{/DESC(aText, aExample, aDD)
If Defined aText
 Context Add Desc:{new}
 Bind [Func Desc*] Func*
 Bind [Text Desc*] Alpha:aText
End
If1 Defined aExample Bind [Example Func*] Alpha:aExample
If1 Defined aDD Bind [DD Func*] Alpha:aDD
}/DESC
  DESC("This is a desc") Only the aText argument is defined
  DESC(<>,"An example") Only the aExample argument is defined
  DESC(Example="An Example") Equivalent to the prior example

Example 5 - Macro with Associated multi-line text argument

  {/hce(aName,aHCL,aDesc,...)
Context Push macroFrame
Context Add vac+
Bind vac.type hce
Context Add hce:aName
Point hce aName
Bind hce.vac vac*
Bind hce.name aName
If1 defined aHCL Bind hce.hcl hcl:aHCL
Bind hce.desc aDesc
If1 defined bTArg Bind hce.text vbt:btArg
Context Pop macroFrame
}/hce
/* Example macro reference */
hce(rptCCPReview,desc="CSS for CheckPoint Review Report",...
table { empty-cells: show; border-collapse: collapse; background: transparent ; font-family: Arial; font-size: smaller ; border: 1px solid white; }
td { border: 1px solid darkgrey; padding: 2px; }
a:link { text-decoration: none; color: transparent }
a:visited { text-decoration: none; color: transparent }
a:hover { text-decoration: underline }

Example 6 - Macro with Undefined Arguments

  {/dtd(aName,aV4Type,aDimOptions,aDesc,aHSE,aDefault,*)
Context Add vac+
Bind vac.type dtd
Context Add dtd:aName
Point dtd aName
Bind dtd.vac vac*
Bind dtd.v4Type aV4Type
If1 defined aDimOptions Bind dtd.dimOptions aDimOptions
Bind dtd.desc aDesc
If1 defined aHSE Bind dtd.hse aHSE
If1 defined aDefault Bind dtd.default aDefault
If1 defined udaList Eval Enum(udaList @BindEE(MakeQI(dtd* `List.1) List.2))
}/dtd
DTD(dtdUTime, v4Type=UTime, Desc="Generic Time",default="0:00",hse=verifyTime,
   vas:table.source:MIDAS.format=internal,
   vas:html.defaultValue="DEFAULT ''",vas:html.hEvent:onblur=,
   vas:xdb.dbEngine:mySQL.colDef="Time",vas:xdb.dbEngine:mySQL.colDefault=NULL,
   vas:table.default=none)
 
The value of udaList in the above call is-
(((vas:table source:MIDAS FORMAT) internal) ((vas:html DEFAULTVALUE) "DEFAULT ''") ((vas:html hEvent:onblur) hse:verifyTime) ((vas:xb dbEngine:mySQL COLDEF) "Time") ((vas:xdb dbEngine:mySQL COLDEFAULT) NULL) ((vas:table DEFAULT) None))

Common V4 Errors and Problems

Err: Isct/IntMod cannot continue in column 1 of next line

V4 uses parenteses to enclose module arguments. Often a module will span several lines. Often a module will references other modules. This leads to nested levels of parenthese which can become confusing to match. To reduce confusion, V4 mandates that all continued bindings and point specifications be indented. Any V4 text appearing in column 1 (excluding comments) are assumed to be the start of a new interpreter command or binding. If you have not matched up parenthese or brackets correctly, V4 may still think it is continuing a binding while you think you are starting a new binding. This error is the result. Check the lines prior to the error and make sure all brackets and parentheses are matched.

Err: BindList exceeds max size

V4 stores binding by the point with the highest Bind value in the binding intersection. Most of the time everything works out fine. But sometimes, often within a Tally this error is generated. The solution can be very easy or very difficult. Here are some suggestions-

Make sure that the By points in the Tally have Bind values in the dimension declaration.

Try altering the order of points within a binding. If two dimensions have the same Bind value then the first is used. Altering the order of points in the By argument alters the points in the binding intersection at the end of the Tally.

Assign a higher Bind value to a dimension.

When all else fails you may have to create a compound dimension. This can get messy. It involves creating a new dimension that combines the values of two or more other dimensions and then using the BindEval attribute when defining a dimension to glue it all together. The example below demonstrates how to combine point on an AC (aircraft) dimension with those on the UMonth dimension.

Example 7 - Using the BindEval Attribute on a Dimension

  Dim AC Local BindEval
Dim ACMon Int Bind 6
[AC.. UMonth.. SchVisit Value..] BindQE([ACMon:=Pack1616(AC* UMonth*) SchVisit] Value*)
[AC.. UMonth.. SchVisit] [ACMon:=Pack1616(AC* UMonth*) SchVisit],0

Another option is to use the Array module to eliminate bindings altogether.

Example 8 - Using the BindEval Attribute on a Dimension and V4 Arrays

  Dim AC Local BindEval
Eval BindQE([SVArray] Array(Dim:Logical AC.. [FcstMonthList]))
[AC.. UMonth.. SchVisit Value..] Array([SVArray] AC* UMonth* Value::Value*)
[AC.. UMonth.. SchVisit] Array([SVArray] AC* UMonth*)

Err: Cannot save binding ([...]) without point with bind potential

At least one of the points in the binding intersection must belong to a dimension with the Bind attribute. See the Dimension command for details.

Err: module fail - dim* - not in context

This literally means that you attempted to grab a value from the context that was not there. In most cases this caused by a missing at-sign ("@") or Do tag.

  Enum(Int:1..10 EchoT(Int*)) generates an error because the EchoT is evaluated as an argument before the Enum starts processing
  Enum(Int:1..10 @EchoT(Int*)) works correctly because the EchoT evaluation is deferred until Enum processing

Err: No binding found

This error can have multiple causes. Here are a few of the most common.

The intersection you are evaluating is missing a point (and that point is not in the context).

The intersection you are evaluating has too many points. Move the offending point(s) into the context or to the right of the "|" delimiter.

You are confusing two similar dimensions as shown below-

  [Answer Money:0..100] "xxx" this is the target binding
  [Answer {[Value] * 10.0}] this fails because {[Value] * 10.0} returns a point on the Num dimension, not Money

Err: Exceeded max number of nested Isct's

You have nested down too many intersection/module levels. This is most often the result of intersection being recursively invoked. This may sometimes occur in strange and unexpected ways. The examples below demonstrate some of the more common constructs leading to this error.

  [UV4:Acceptor Dim:X Alpha..] X:=moduleorintersection By attempting to project the result of moduleorintersection back into dimension X, you are triggering the Acceptor logic for that dimension. Use the MakeP() module instead of projection
  [X:whatever Y:whatever NId..] xxxx It is usually a bad idea to define intesections with "NId.." because points on that dimension are used throughout. If the xxxx includes an intesection of the form [nidpoint] then it will probably recurse because both dimensions X & Y have points in the context.

Problem: Aggregate value periodically appears as garbage

This is most likely caused by having variable length strings within a BFAggregate. Check all string values to ensure that they are the same length. The FixedLength Column option can be used to force all values to the same length.

Problem: Test for point equality failing

Two conditions must be satisfied for one point to equal another. First they both must have the same value, secondly they must be on the same dimension. Use the EQk or In modules when you want to compare just values.

Problem: Output showing point name, not its value

The most likely cause for this is forgetting to enclose a point in brackets-

  EchoT("The answer is " Value) results in the output: The answer is Value
  EchoT("The answer is " [Value]) results in the correct output reflecting the evalution of [Value]

Problem: Evaluation of [UV4:IsctFail] not working as expected

A common cause is the use of the Optimize? tag within the Do module. Refer to this module for more information.

xv4 Startup Switches

Command Line Syntax

This section describes the startup options for xv4.exe. The xv4 program can be used to both interpret V4 language statements and manage any area (file) that is in a valid V4IS format.

Using xv4 as an interpreter is done with either of the following two command formats-

  xv4 Starts up the V4 interpreter and immediately accepts input on stdin.
  xv4 file Starts the V4 interpreter and immediately begins interpreting the V4 commands in " Param:file "."

xv4 is also used to obtain information on a V4 area, to rebuild an area, or perform a corrective procedure such as rebuilding the index. A V4 area may be updated while it is currently being accessed in a multi-user environment as long as the proper sequences are followed. The examples below demonstrate several ways of using xv4.

Example 9 - Viewing Basic Parameters of a V4IS Area

  xv4 -l area.dat
V4 1.300 - "Data that thinks like us"
Protected by U.S. Patent 6,470,490 - MKS Inc. (2003)
  Bucket Size 16384
  Version 1.300
  Next Available Bucket 4 (Number of buckets = 4)
  Compress Records over 100 Bytes
  Maximum Record Length 16360
  Data Storage Mode 0 Number of levels in directory 3
  Fill Percentage on Rebuild 0
  Allocation Increment 0
  Record Count 1316
  Global Buffer Count 0
  Lock Max 0
  Created Mon Jan 06 21:47:23 2003
  Free Space: none

Example 10 - Rebuilding the Index While an Area is Being Accessed

 
xv4 -x -pCW area.dat First lock down the area to prevent further access
xv4 -x -k area.dat Rebuild the indexes
xv4 -x -pR area.dat Reopen the area and allow access

Example 11 - Compressing a Text v4b File

  xv4 -zt data.v4c data.v4b
  data.v4b => data.v4c (45%)

xv4.exe Startup Switches and Options

-a Normally V4 traps memory errors, if -a is given then V4 will not trap the error and abort. This option is useful when running xv4 with a debugger.
-B Automatically break on the first evaluation.
-bc num To set block count on sequential dump (default from area)
-bo num To set initial bucket offset for linking index-only areas
-bs num To set block size on sequential dump (default from area), to change block size on sequential restore from that of original area, to change block size on a reformat (default from source area)
-bsr num To change block size & record size to handle records of length num
-cb num To change Global Buffer Count (on -or only)
-cl num To change Lock Max for area (on -or only)
-d num To dump out bucket num for area
-da To dump out all buckets within an area
-dd To dump out all data buckets in an area
-di To dump out all index buckets in an area
-dl bkt To search for index bucket(s) linking to specified bucket- bkt
-f num To set fileref on restore to num
-fm To set fileref to that of mergefile
-fs To set fileref from sequential dump (default)
-h Outputs brief help text.
-i file To declare an initialization file (v4i)
-ii use default v4.v4i ini file
-k area To rebuild the index of the specified area (must be used with -x). The use of the -pCW option is also strongly if the area is currently being accessed.
-l To list the V4IS parameters for the inputfile
-lu To list summary disk bucket space utilization for inputfile
-lud list detailed (by bucket) space utilization
-m megabytes To set max number of wasted space in area (use with -lu), to dump or restore a maximum of num records
-oc new old To copy existing old area into another new area. Both areas must already exist. This option is for updating a V4 area in place, possibly while it is being accessed. It must be used in conjunction with the -pCW option.
-of new old For fast (via vsort) restore of the old area, header file, or sequential file to the new area.
-oo new old To restore area from sequential inputfile to file
-om file To merge records in sequential inputfile into file
-or new old Creates a clean version of the old area as the new area. Note: this option should only be used if the old area is in a non-corrupt state.
-os seq old Dumps all records in the old area to a sequentail new area.
-osh hdr old Creates a header only hdr area from an existing old area.
-pb area To generate a bugchk for the area.
-pl area Privileged - List users in the area.
-pR area Privileged - Reset shared segment for the area.
-pCE area Privileged - Locks out area and issue error if access attempted. This means any users currently accessing the area will receive an error on the next access attempt.
-pCR area Privileged - Allow future reads on the area but block any process attempting to update the area.
-pCW area Privileged - Block all access to the area.
-pK area Privileged - Open area and force clear of lock table
-pO file Privileged - Reopen a closed area
-pB num area Privileged - Zap global bucket num for area.
-pJ num area Privileged - Test locks on area n*million times.
-pL lid area Privileged - Zap lock with specified lock-id lid for area.
-pN num area Privileged - Sets next available user number to num for the area.
-pS file Privileged - Re-synch lt->LocksIDX for area
-re [num] Set runtime echo number
-ro string Set the V4 user startup option string. This can be referenced with V4(UserOptions?).
-rpx value Set #x# parameter to the specified value
-rpxQ value Set #x# parameter to the specified value enclosed in double quotes
-rpxq value Set #x# parameter to the specified value enclosed in single quotes
-rq Runs in quiet/silent mode
-rs list Only run in 'If Section xxx' where xxx is in list.
-rt num Set trace to num.
-S V4 will output a date-time/cpu stamp with each status line. This is the same as the Set Trace Timestamp command.
-s logical=value Locally assigns value to logical (environment symbol), to open file and read multiple logical=value lines within the file.
-u Reads the multiple Unicode descriptor files from the V4 home directory and creates a parsed binary v4UnicodeInfo.bin file within the home directory.
-v area Verifies integrity of the area's index-data links.
-vf area Verifies integrity of an area with foreign-only keys.
-X Informs V4 that it is to execute a single file (to follow on command line) and then force an exit when the end-of-file is reached.
-x Denotes OK to update existing file/area
-y text Sets the V4 input prompt to text.
-zb new old Compress the existing old file and write out to the new file. This compression may be performed on any (text or binary) file.
-zt new old Same as -zb except that the old file must be a text file. This option must be used when compression v4b's => v4c's.
-zx new old Expand an old compressed file to new.
-% num To set fill percent on rebuild/restore

Standard Filename Extensions

.v4 - V4 source file.

.v4a - A compiled V4 area or V4 data aggregate file.

.v4b - A tab or comma delimited data file.

.v4c - A compressed .v4b file.

.v4d - A dictionary file (no longer used).

.v4i - A startup include file (see next section).

.v4r - A results file (created by EchoS output).

.v4x - An external V4 dictionary file (replaces v4d files).

V4 Runtime Information Files

V4 loads information from several text files each time it is started. These files contain mandatory dimensions, error message text, colors, country information, etc. The location of these files varies by operating system. On Windows based systems, the files must reside in the same directory as the xv4.exe executable. On all other operating systems, these files reside in a directory pointed to by the v4_Home logical.

The remainder of this section describes the current V4 startup information files.

Kernel Dimensions - v4Kernel.v4i

The v4Kernel.v4i file contains Dimension commands that defined the mandatory kernel V4 dimensions. This file must be Included for V4 to operate properly.

Example 12 - Startup of V4 without Mandatory v4Kernel

  xv4
= {2 * 2}
?V4E- Please "INCLUDE v4" first.
i v4
= {2 * 2}
  Int:4

Error Messages - v4ErrorMsgTable.v4i

All V4 error messages, warnings, and status comments are contained in the file v4ErrorMsgTable.v4i. The format of this file is mnemonic<tab>message-text. An internal V4 error references a message mnemonic which is then found in the error file. The corresponding message-text is then formatted and output. The message-text may contain substitution specifiers of the form %nt where n is a number from 0 to 9 and t is an format type code. Substitution arguments are numbered from 1 to 9. The 0th argument is reserved for position-free type codes.

Table 3 - Format Type Codes within V4ErrorMsgTable.v4i

Code Description
d An integer (decimal) number
i Same as 'd' - an integer number
g A floating point number
f Same as 'd' - a floating point number
s A null terminated ASCII string
p An ASCII string truncated to 10 characters.
P A V4 point
T A V4 tag name
D A V4 dimension name
Y A V4 point type (Integer, UDate, BigText, etc.)
E A V4 internal module formatted into standard V4 error message prefix
M A V4 internal module name
F The current source file and line number
A The contents of ctx->ErrorMsgAux (holds partial error messages from low level routines).
This argument is always specified as '%0A'
O The operating system error message corresponding to the argument error number
  ModArgAllEval %1E Argument (%2i %3D..) - %0A
  Str(Int.. hohoho) evaluation of this results in...
  [ModArgAllEval] Str() fail - Argument (1 Int..) - No implicit list of points associated with Dim:Int output

Colors - v4Colors.v4i

This file describes all points within any dimension of type Color. Each line consists of the following information- index<tab>name<tab>hexvalue where index is a unique integer value for a color, name is the name of the color and hexvalue is the 24-bit hexadecimal value of the color.

The default color list is taken from the WWW list of standard colors.

HTML Content Types & Default Extensions - v4HTMLContentType.v4i

This file provides a map between standard WWW MIME types and file extensions. Each line is of the form MIME-type<tab>extension-list where MIME-type is a standard two-part MIME specification and extension-list is a list of one or more file extensions denoting that type.

Locale Specific Information - v4CountryInfo.v4i

This file specifies each country within a dimension of type Country and locale information about each country. The format of the file is shown by the V4 table below.

  Table CountryInfo Country Information Table
   Col UNCode Int the United Nations country code
   Col UNAbbr Alpha the United Nations country abbreviation
   Col UNName Alpha the United Nations country name
   Col IntDialCode Int the international calling code for the country
   Col IDD Int the internal direct dial prefix within the country
   Col NDD Int the international direct dial prefix within the country
   Col ITeleMask Alpha the format of international telephone numbers within the country
   Col NTeleMask Alpha the format of national telephone numbers within the country
   Col DateMask Alpha the format of dates
   Col MonthMask Alpha the format of months
   Col DateTimeMask Alpha the format of date-times
   Col Calendar Alpha the type of Calendar (0=Gregorian, 1=Julian, 2=Islamic, 3=ISO, 4=Hebrew, 5=Chinese, 6=Hinud)
   Col Language Int the language index (see v4LanguageInfo.v4i) for the country
   Col YMDOrder Int the year-month-day ordering
   Col Currency Alpha the currency character
   Col Prefix Logical TRUE if currency character is prefix, FALSE if suffix
   Col Delimiter Alpha the delimiter character for large numbers
   Col DelNum Alpha the number of digits between delimiters (usually 3); this may be list for unusual numeric delineations (see India)
   Col RadixPt Alpha the radix (decimal) point character
  EndTable  

Language Specific Information - v4LanguageInfo.v4i

This file describes the various ways different concepts are output in V4. It, as with all the v4i files, is a tab delimited text file. The first column of each line indicates the type of line and what follows. The second column is a language indicator. The first few lines of this file define the current languages. The third column is a calendar indicator. The calendar codes are 0=Gregorian, 1=Julian, 2=Islamic, 3=ISO, 4=Hebrew, 5=Chinese, 6=Hindu. The different line types are given below.

LANGID - Defines the supported languages.

SDOW - Short (abbreviated) days of the week.

LDOW - Long days of the week.

SMOY - Short (abbreviated) months of the year.

LMOY - Long months of the year

CMASK - Two calendar masks. The first is for dates, the second is date and time.

RELTIME - Relative times (yesterday, today, tomorrow, now, hours, minutes, seconds).

LOGICAL - Various ways true and false can be identified.

NOVALUE - Up to three ways that no value can be specified for a point.

SNUMS - The first 20 integers as words (0 - 19).

TENS2090 - Multiples of ten from 20 to 90.

NUM000 - Multiples of 1000, starting with 100.

ORDSFX - Ordinal suffixes for integers 0-9

TZONES - Timezone abbreviations in the form 'abbr,abbr,...=GMTOffset'

DISTANCE - Labels for various distance units (see the GeoCoordinate point type) where: meter=0, kilometer=1, mile=2, feet=3, yard=4, nautical mile=5

SPEED - Labels for various speeds (distance * 100 + time where time is: second=1, minute=2, hour=3, day=4, millisecond=5, microsecond=6)

GEOLBL - Label values for GeoCoordinate points