Skip to main content

Migration Walkthrough

This exercise takes a small order-line calculation from a SAL outline to PPJ C#, then compares both with the same test cases. It deliberately starts without a database so you can establish language and UI behavior before adding provider and transaction differences.

You need Team Developer for the source baseline, Ice Porter for conversion, Visual Studio with the installed PPJ templates/runtime, and an agreed target from the compatibility matrix. The outline below is teaching material to enter into a small application, not a complete importable .apt file. The C# sample is a complete helper and regression harness; it does not include proprietary PPJ binaries.

1. Define the Behavior

Create an order-line form with numeric fields for quantity, unit price, and discount percentage; a read-only total; and a Calculate button. Use a separate function, TryLineTotal, for the calculation.

The contract is explicit:

  • Null input is invalid. Quantity and price must be nonnegative; discount must be between 0 and 100 inclusive.
  • An invalid input returns false and sets the receive total to null, clearing any previous successful result.
  • Valid input returns true with quantity × price × (100 − discount) / 100.
  • This function does not round. A production application's rounding point and rule must come from its business requirements.

2. Run the SAL Baseline

Enter this function in Team Developer. The button calls it, displays the total on success, and displays a validation message on failure. Do not continue displaying an earlier total after a failed call.

Function: TryLineTotal
Returns
Boolean:
Parameters
Number: nQuantity
Number: nUnitPrice
Number: nDiscountPercent
Receive Number: nTotal
Actions
Set nTotal = NUMBER_Null
If nQuantity = NUMBER_Null OR nUnitPrice = NUMBER_Null OR nDiscountPercent = NUMBER_Null
Return FALSE
If nQuantity < 0 OR nUnitPrice < 0 OR nDiscountPercent < 0 OR nDiscountPercent > 100
Return FALSE
Set nTotal = nQuantity * nUnitPrice * (100 - nDiscountPercent) / 100
Return TRUE

Save a copy of the source and the SAL outline. Record the Team Developer version, locale, field formats, and actual results from the cases below. Check both the numeric result and what the form displays; formatting can conceal a numeric difference.

3. Convert and Inspect

Run Ice Porter using the installed release's conversion workflow, selecting the desktop or web target chosen for the exercise. Save the conversion options and log beside the source baseline. Resolve every warning affecting the calculation or form before treating the generated application as equivalent.

Open the generated solution and restore its configured packages. Preserve generated context scopes, event wiring, and receive-parameter declarations. Inspect the output for these translations:

SAL constructWhat to find in the C# output
Number / BooleanPPJ SalNumber / SalBoolean where compatibility requires them.
Receive NumberA correctly typed receive parameter, commonly ref SalNumber.
NUMBER_NullPPJ numeric null behavior, distinct from zero.
Calculate button actionGenerated event/message handling that invokes the function once.
Visual methodThe generated SalContext scope that preserves window context.

Exact class placement and generated names depend on the conversion options. The following equivalent, hand-written helper isolates the calculation for testing; it is not a claim that every Ice Porter version emits these exact lines.

using PPJ.Runtime;

public static SalBoolean TryLineTotal(SalNumber quantity, SalNumber unitPrice,
SalNumber discountPercent, ref SalNumber total)
{
total = SalNumber.Null;
if (quantity.IsNull || unitPrice.IsNull || discountPercent.IsNull)
return false;
if (quantity < 0 || unitPrice < 0 || discountPercent < 0 || discountPercent > 100)
return false;
total = quantity * unitPrice * (100 - discountPercent) / 100;
return true;
}

4. Compile and Run the Checks

Build the converted solution with its supported Visual Studio/MSBuild toolchain. Keep the installed PPJ package references; do not substitute an unrelated runtime assembly merely to make compilation succeed.

Download LineTotal.cs, add it to a test project referencing the same PPJ runtime, and call LineTotalSample.RunChecks() from that project's entry point or test method. It throws an exception if a case fails and returns normally if all eleven cases pass. In a console harness, print a success line after the call so a silent process exit is not confused with an unexecuted test.

The included checks initially exercise the equivalent helper. To validate your conversion, adapt the harness call to invoke the actual converted TryLineTotal method and its generated object, then run the form through the same cases. Passing the helper alone does not validate generated code or event wiring.

CaseQuantityPriceDiscountSuccessNumeric total
Ordinary212.500Yes25
Fractional result319.9510Yes53.865
Zero quantity012.500Yes0
Full discount212.50100Yes0
Negative quantity−112.500NoNull
Negative price1−10NoNull
Negative discount112.50−1NoNull
Discount too large112.50101NoNull
Each input null, separatelyOne null inputOther values validNoNull

Start every failure case with a non-null old total to detect stale receive values. Test a successful button click followed by a failed click. Also test keyboard activation, tab order, decimal separators, and the display format selected in the SAL baseline.

5. Add One Integration at a Time

After this baseline agrees, extend the same small application in this order:

  1. Load a price through a parameterized query; test no row, a null price, and a provider error. Preserve the SQL context.
  2. Save an order line in a test database; verify explicit commit and rollback ownership. Exercise a failed operation using the SQL error-flow trace.
  3. Generate a small order report; compare numeric values, rounding, grouping, and totals using the report lifecycle.
  4. For Web, run two separate user sessions with different orders and confirm isolation using the operations checks.

Keep expected and actual results, source/build identifiers, screenshots, and defect references together. Accept the baseline only when differences are either fixed or explicitly approved business changes. Archive the original application and the working migrated build before refactoring compatibility code.