Opening the book…
This page helps you recognize legacy PG patterns that show up in older problem libraries and online examples. The goal is to translate the useful idea into a PGML-first structure (see Introduction to PGML for modern PGML) without carrying forward fragile formatting or scattered grading logic.
If you pasted code from an old problem and it uses BEGIN_TEXT, &ANS, or raw Perl formatting, start here.
If you see a PopUp example online, treat it as a historical artifact, not a recommendation.
Use this page when: a copied problem looks strange or grades unpredictably.
Copy and edit (PGML-first rewrite)
# Legacy text block (do not use)
# BEGIN_TEXT
# The stock concentration is $c_stock uM.$PAR
# Find the final concentration: \{ans_rule(10)\} uM
# END_TEXT
# PGML-first rewrite
BEGIN_PGML
The stock concentration is [c_stock] μM.
Find the final concentration: [________]{$c_final} μM
END_PGML
Common failure and fix
Broken: $PAR and BEGIN_TEXT blocks mixed with PGML What you will see: raw $PAR output or missing blanks Fix: move all prompt text into BEGIN_PGML/END_PGML
Rewrite recipe (fast path)
- Identify the story text and move it into a PGML block.
- Move all numbers, ranges, and answer objects into Setup.
- Attach each answer object directly to the blank in PGML.
- Remove unused macros and leftover text-formatting codes.
- Render a few seeds to confirm the prompt, units, and grading.
Legacy patterns to recognize (and replace)
| Legacy pattern | Why you see it | PGML-first replacement |
|---|---|---|
beginproblem() call in DOCUMENT section |
Found in 78% of OPL files. Was once required for initialization but is now handled by DOCUMENT(). |
Delete the line. DOCUMENT() alone is sufficient. |
| BEGIN_TEXT / END_TEXT blocks | Pre-PGML format for the prompt text. | Use BEGIN_PGML / END_PGML for readable prompt text. |
| $PAR, $BR, and manual line breaks | Older formatting controls inside text blocks. | Use normal paragraphs, lists, or tables in PGML. |
| String-built HTML ("
" . $x . " ") |
Manual HTML assembly in PG strings. | Use PGML with variable inserts for clean text. |
ANS(num_cmp(...)) or ANS(str_cmp(...)) |
num_cmp appears in 46% and str_cmp in 7% of OPL files. Legacy evaluators from the pre-MathObjects era. |
Use MathObjects and PGML inline blanks: [_]{$answer}. See the table below for specific replacements. |
| ans_rule() without nearby answer object | Older blank creation with separate answer logic. | Attach answer objects directly to PGML blanks. |
| Manual rounding inside strings | Legacy formatting for display-only answers. | Use MathObjects and explicit tolerance rules. |
Deprecated or fragile behaviors
| Pattern | Why it is fragile | Preferred approach |
|---|---|---|
NchooseK($N, $K) |
Deprecated in PGchoicemacros.pl. Very common in OPL (1,000+ files). Returns K indices chosen from 0..N-1. | Use random_subset($K, 0..$N-1) from PGstandard.pl, or build an index array and @list[@indices]. |
shuffle($N) |
Deprecated in PGchoicemacros.pl. Returns a random permutation of indices 0..N-1. | Use random_subset($N, 0..$N-1) for a full permutation, or Perl's built-in list operations. |
new_match_list with print_q/print_a |
PGchoicemacros.pl legacy match list generates its own form fields, requiring ANS(str_cmp(...)). |
Use PopUp widgets (parserPopUp.pl) with PGML inline blanks. See Macro Demonstrations for both patterns. |
| PopUp menus for choices | Legacy UI pattern and inconsistent rendering. | Use DropDown or radio/checkbox patterns. |
| Hidden grading logic in text assembly | Hard to debug and easy to mismatch with the prompt. | Compute answers in Setup and attach to blanks. |
| Multiple unrelated Context() changes | Inconsistent parsing rules across blanks. | Set Context once and override only if necessary. |
num_cmp(), str_cmp(), fun_cmp() |
Legacy evaluators from pre-MathObjects era. num_cmp alone appears in 46% of OPL files. |
Use MathObjects (Compute(), String(), Formula()) with ->cmp() or PGML blanks. See table below. |
TEXT(beginproblem()) |
No longer needed. Appears in 78% of OPL files but DOCUMENT() handles initialization. |
Delete the line entirely. Use DOCUMENT(); alone. |
AnswerFormatHelp.pl |
Entire macro file deprecated in PG 2.17. | Use helpLink() from PGbasicmacros.pl (loaded via PGstandard.pl). |
compoundProblem.pl / compoundProblem5.pl |
Deprecated in PG 2.19. Legacy multi-section problem macros. | Use scaffold.pl with Scaffold::Begin() and Section::Begin(). |
| Old macro families loaded "just in case" | Adds noise and can mask missing dependencies. | Load only the macros needed for the prompt. |
Legacy answer evaluators (very common in copied code)
Before MathObjects existed, every problem used standalone evaluator functions like num_cmp() and str_cmp(). These still work but are discouraged because MathObjects provide richer error messages, tolerance handling, and direct attachment to PGML blanks. If you copy a problem from the OPL, there is roughly a 50% chance it uses at least one of these legacy evaluators.
Copy and edit (answer evaluator rewrite)
# Legacy pattern (do not use in new problems)
# $answer = 42;
# ANS(num_cmp($answer));
# ANS(num_cmp($answer, tol => 0.01));
# MathObjects + PGML rewrite
$answer = Compute("42");
BEGIN_PGML
Enter the answer: [_________]{$answer}
END_PGML
# Tolerance is set via: $answer->cmp(tolerance => 0.01)
| Legacy evaluator | OPL prevalence | What it does | MathObjects replacement |
|---|---|---|---|
num_cmp($x) |
46% (33,804 files) | Compares student answer to a number. Supports tolerance, strings like "DNE". | $x = Compute("42"); then PGML [_]{$x} or ANS($x->cmp()) |
str_cmp("text") |
7% (4,958 files) | Compares student answer to a string. Used for word answers, matching. | $x = String("text"); then PGML [_]{$x} or ANS($x->cmp()) |
fun_cmp("x^2") |
Common in math OPL | Compares student formula by sampling points. | $f = Formula("x^2"); then PGML [_]{$f} or ANS($f->cmp()) |
std_num_str_cmp() |
Low | Hybrid number/string comparator. Formally deprecated in PG 2.17. | Use Compute() with appropriate Context. |
numerical_compare_with_units() |
Low | Number comparison with unit checking. Formally deprecated in PG 2.17. | Use NumberWithUnits() from parserNumberWithUnits.pl. |
Key point: num_cmp() and str_cmp() are not formally marked deprecated in the PG source (they have been rewritten to use MathObjects internally), but the PG documentation recommends using MathObjects ->cmp() methods directly. New problems should always use MathObjects.
beginproblem(): safe to delete
beginproblem() appears in 78% of OPL files (56,953 of 72,734). It was once required to initialize problem output, but DOCUMENT() now handles all initialization. If you copy a problem that includes TEXT(beginproblem()), simply delete that line.
# Legacy (found in most OPL files) # DOCUMENT(); # TEXT(beginproblem()); # Modern (just DOCUMENT is enough) DOCUMENT();
PGchoicemacros.pl: widely used, mostly deprecated
PGchoicemacros.pl appears in over 1,000 OPL files, but most of its utility functions are now deprecated. If you copy a problem that loads PGchoicemacros.pl, check which functions it actually uses and consider whether a modern replacement exists.
| Deprecated function | Replacement | Example rewrite |
|---|---|---|
NchooseK(5, 3) |
random_subset() |
@pick = random_subset(3, 0..4); |
shuffle(5) |
random_subset() |
@perm = random_subset(5, 0..4); |
new_match_list |
PopUp widgets | Build PopUp objects and use PGML inline blanks (see Matching). |
new_select_list |
RadioButtons | Use parserRadioButtons.pl with PGML (see Multiple Choice). |
new_multiple_choice |
RadioButtons | Use parserRadioButtons.pl with PGML (see Multiple Choice). |
Not deprecated: PGsort is sometimes confused with PGchoicemacros.pl but is actually a core function from PGbasicmacros.pl (loaded via PGstandard.pl). It does not require loading PGchoicemacros.pl and is not deprecated.
Apply it today
- When you copy an older example, rewrite the text block into PGML first.
- Keep the macro list short and focused on what the prompt actually uses.
- Use seeds to reproduce any unexpected grading or formatting behavior (see Common Mistakes and How to Fix Them for common mistakes).
Next, depending on what you are doing:
- Once it is PGML-first, go back to PG Problem Files and rebuild from the minimal skeleton.
- Need macro help? Go to Common PG Macros.
- Not sure where setup ends and PGML begins? Go to Sections within a PG question.
This page titled 2.6: Legacy PG and deprecated patterns was last modified on Fri, 27 Feb 2026 15:11:18 GMT and is shared under a CC BY 4.0 license and was authored, remixed, and/or curated by Neil R. Voss.
The book could not be loaded just now.