Difference between revisions of "Help:Substitution"
m (→Overview) |
(No difference)
|
Latest revision as of 13:34, 27 June 2006
Substitution allows the use of templates as macros. It causes an automatic conversion of wikitext into the referring text when the referring page is saved; the template is macro expanded when the page is saved rather than, as usually happens, when the page is viewed.
It is done by putting the modifier subst:
after the double opening braces.
The result (in the form of the difference with the saved wikitext) can be seen before (or without) saving by pressing "Show changes".
Usage of a template through subst:
does not show up in page histories, backlinks, etc. The template could add pages to a category to track substitutions, but listing this category on a page may clutter the list of content-based categories the page is in. Also, comments outside noinclude tags are included in the wikitext. Thus a comment can be used to mention the template. It can even contain the values of the parameters, because substitution of parameters works even in comments.
Contents
Overview
For the discussion of substitution, an "ordinary template" is any page included by {{subst:pagename }} for pages in the template namespace or {{subst:fullpagename }} for pages in other namespaces. It's also possible to substitute variables and colon functions collectively known as "predefined templates".
In principle the rendered result at the time of substitution is the same as that of ordinary inclusion.
- There are exceptions, see below, for example:
- {{#expr:2*{{{p|3}}}}} gives 6
- {{subst:#expr:2*{{{p|3}}}}} gives Expression error: unrecognised punctuation character "{"
However, a change of an ordinary template after substitution does not affect the page in which it was substituted. A substituted variable depending on time no longer depends on time, etc. A substitution of e.g. {{#expr:2*3}} does not affect rendering at all.
The relationship between wikitext of a page and its rendering can be become easier to understand after substitution, because one has all wikitext together, and parameter substitutions have been performed.
It can also become more complex. Separately focusing on understanding a template call and understanding the template content can be easier. Wikitext after substitution is often more complex than when the required wikitext would have been written directly.
Unlike a template call (if one knows about templates), wikitext after substitution does not show how one can produce a similar result. The wikitext can be long and complicated, and therefore cumbersome to write directly, or it can be simple, e.g. a number resulting from a computation, but cumbersome to find directly. One may think that the wikitext is what one is supposed to write and find directly to get the result, even in cases where that would be very impractical.
In such cases documentation of the template call is useful. Just like in computer programming we change the source code and/or the data to produce new results, and we do not directly change the object file, here we would change the template calls and/or the templates, instead of changing the wikitext resulting from substitution directly.
Ordinary templates
In the case of substituting an ordinary template, the template tag is replaced by the wikitext of the template, with the parameter values substituted for the parameters. Even parameters in comments are substituted.
- Example: template:t2 ( talk edit history links ), containing
- <!--t2-->start-{{{1}}}-middle-{{{2}}}-end and called as
- {{subst:t2|[[a]]|{{tc}}}} gives the wikitext
- <!--t2-->start-[[a]]-middle-{{tc}}-end, rendering as
- start-a-middle-Template:Tc-end.
Substitution removes the noinclude parts and the includeonly tags.
Parameters:
- A substitution with p=r replaces {{{p}}} and {{{p|q}}} by r; this includes the cases that r is of the form {{{s}}} or {{{s|t}}}.
- A substitution with undefined p preserves {{{p}}} and {{{p|q}}}; the latter is not replaced by the default q (see below for a construct that is replaced by p if p is defined, and by q if not).
Thus, to document the included content of a template, one can apply substitution without parameters, save, and add nowiki tags. The replacement of a template tag by wikitext does not work recursively, there is no substall. For a workaround see optional substitution below.
Stepwise substitution of templates including other templates including more templates etc. can be useful for analyzing problems or documenting the expected behaviour of complex templates, for an example see m:Template talk:Lop.
Stepwise substitution for template names depending on the parameter default mechanism doesn't work as expected, this also affects parameter defaults in the left hand side of colon functions, see below for examples.
In the absence of parameters, alternatives are copying the source template as is, or editing the result of a saved {{ msgnw:pagename }} inclusion. For these techniques make sure to exclude <noinclude> parts manually, and likewise to remove <includeonly> tags.
Predefined templates
In the case of substituting a predefined template, without parameters depending on other templates, the tag is replaced by the result. Please note that subst: has to be added directly in front of the predefined template name without intervening spaces.
Applying subst to a variable works like applying it to a template. E.g. a timestamp:
- {{subst:CURRENTDAY}} {{subst:CURRENTMONTHNAME}} {{subst:CURRENTYEAR}}, {{subst:CURRENTTIME}} (UTC)
- 10 March 2005, 08:23 (UTC)
In the case of substituting a predefined template with a parameter depending on another template, that has to be substituted too, with a separate subst: modifier, otherwise the result is undefined.
- {{subst:UC:{{subst:tc}}}} gives IN, just like {{UC:{{tc}}}} does; UC is applied to the output "in" of Tc.
- {{subst:ns:{{subst:#expr:2*3}}}} gives Image.
- {{ns:{{subst:#expr:2*3}}}} gives wikitext {{ns:6}} rendered as File.
- {{subst:t1|{{subst:NAMESPACE}}}} gives the wikitext startHelpend
- {{subst:t1|{{subst:#expr:3*4}}}} gives the wikitext start12end
- {{subst:t1|{{subst:uc:AbCdEf}}}} gives the wikitext startABCDEFend
- {{subst:#expr:{{subst:3X|11*}}1}} gives the wikitext 1331
- {{subst:UC:{{subst:3X|abc}}}} gives the wikitext ABCABCABC
- {{subst:LC:{{subst:#expr:1/100000}}}} gives the wikitext 1e-05
- {{subst:#expr:2*{{subst:CURRENTDAY}}}} gives (at the time of writing) the wikitext 30
- {{subst:UC:{{subst:CURRENTDAYNAME}}}} gives (at the time of writing) the wikitext THURSDAY
However:
- {{subst:UC:{{tc}}}} gives the wikitext {{TC}} rendered as Template:TC.
- {{subst:ns:{{#expr:2*3}}}} stays {{subst:ns:{{#expr:2*3}}}}, rendered as {{subst:ns:6}}.
Summary: Substitution of the outer x: in a nested {{ x:...{{ y:...}} }} works only if all inner y: are also substituted.
Substitution of a predefined template does not work if the call contains an undefined {{{p}}}, not even if a default value is specified, as in {{{p|q}}}. For example:
- {{#expr:2*{{{p}}}}} gives Expression error: Unrecognized punctuation character "{".
- {{#expr:2*{{{p|3}}}}} gives 6
- {{subst:#expr:2*{{{p|3}}}}} gives the wikitext and rendering Expression error: unrecognised punctuation character "{"
Compare:
- {{uc:2*{{{p}}}}} gives 2*{{{P}}}
- {{uc:2*{{{p|q}}}}} gives 2*Q
- {{subst:uc:2*{{{p|q}}}}} gives the wikitext 2*{{{P|Q}}} rendered as 2*Q
and also (from above):
- {{subst:UC:{{subst:tc}}}} gives IN, just like {{UC:{{tc}}}} does; UC is applied to the output "in" of Tc.
- {{subst:UC:{{tc}}}} gives the wikitext {{TC}} rendered as Template:TC.
In the substitution of UC, the inclusion tag {{tc}} is treated as string just like {{{p|q}}}.
Derived template names
Substitution of a template whose name depends on another template like {{A{{B}}}} or a parameter like {{A{{{P}}}}}, can only be applied if template B is substituted too, or if the parameter P has a value. Like above, a specified default as in {{A{{{P|D}}}}} is not enough.
Saving e.g. {{subst:H:f {{NAMESPACE}}|enname=Substitution}} is rendered as wikitext, not the desired effect: {{subst:H:f Help|enname=Substitution}}.
However {{subst:H:f {{subst:NAMESPACE}}|enname=Substitution}} would be replaced by the result of {{H:f Help|enname=Substitution}} as expected for a substitution in namespace Help.
Summary: Substitution of the whole {{ x...{{ y...}} }} works only if all inner y are also substituted.
Partial substitution
Inside an ordinary template one can apply substitution to an ordinary template call containing a parameter, to replace it by the direct wikitext containing the parameter. It amounts to automatically merging the two templates (creating a "composite template" like a composite function). It is not possible if the inner and/or outer template is predefined. (However, manually merging e.g. a call of #expr inside another one is useful for increasing the accuracy of the result by avoiding intermediate rounding to 12 digits.)
This way one can dispense with the optional substitution technique described below, and apply substitution of the resulting outer template by simply using "subst:" (unless there are more nesting levels).
Example:
- {{subst:t}}}} gives the wikitext start-{{{1|pqr}}}-end, just that of template:t ( talk edit history links ), without noinclude parts and includeonly tags
- {{subst:t|a{{{p|q}}}b}} gives the wikitext start-a{{{p|q}}}b-end
Examples with double substitution:
- {{subst:3X|{{subst:t}}}} gives the wikitext start-{{{1|pqr}}}-endstart-{{{1|pqr}}}-endstart-{{{1|pqr}}}-endstart-{{{1|q}}}-end
- {{subst:3X|{{subst:t|{{{1|q}}}}}}} gives the wikitext start-{{{1|q}}}-endstart-{{{1|q}}}-endstart-{{{1|q}}}-end
Optional substitution
Suppose page B calls C. One can make page B suitable for both inclusion in A and multi-level substitution in A, as follows: use in B, in the call of C, instead of "subst:" a parameter "subst" that takes the value "subst:" or the empty string, with the latter as default, and carrying on the value of this parameter: {{ {{{subst|}}}C|subst={{{subst|}}}|..}}. Then B can be included in A with {{B|..}} or substituted in A with {{subst:B|subst=subst:|..}}. In the case of more levels, C can call D using the parameter subst carried on, etc.
Parameter {{{subst|}}} can also be applied to variables and/or parser functions, etc. Whether this is desirable varies, compare Help:Calculation#Substitution.
See also template:Example table with computations, with optional substitution ( talk edit history links ).
Cookbook
Adding optional substitution to an existing template X is simple:
- For each template or variable Y used within X, say {{Y|a|b|c}}, replace Y by {{{subst|}}}Y resulting in {{{{{subst|}}}Y|a|b|c}}.
- For ordinary templates add a parameter subst={{{subst|}}} resulting in {{{{{subst|}}}Y|a|b|c|subst={{{subst|}}}}} (predefined templates like colon functions and variables don't get the additional parameter).
This allows to use {{X|d|e|f}) as is, or {{subst:X|d|e|f|subst=subst:}) with recursive substitution, as far as all ordinary templates Y used within X support this technique. Even if they don't support it they are still substituted, but won't propagate this recursive substitution into templates or variables Z used within Y.
Using {{subst:X|d|e|f}] without additional parameter subst=subst: should be okay, otherwise it also won't work with additional parameter. For some templates substitution breaks their function, and for some predefined templates (see below) and variable REVISIONID it won't work as expected.
Partial substitution
Using a template prepared for optional subst=subst: only with ordinary substitution, without specifying parameter values, allows to insert its code into another template, like copy and paste, but all <noinclude> parts and <includeonly> keywords automatically stripped. Using templates within templates is expensive. If the "inner" template is good enough as it is, then inserting its code instead of calling it is a good idea.
A typical example for this technique is expanding, within another template, a template used as test expression in a #switch: like template:len ( talk edit history links ):
- Development code:
{{#switch: {{len|
parameter tag}}|0=
case 0 etc.}}
- Cookbook solution:
{{{{{subst|}}}#switch: {{{{{subst|}}}len|
parameter tag|subst={{{subst|}}}}}|0=
case 0 etc.}}
- Better solution: create template code by applying substitution using this wikitext:
{{{{{subst|}}}#switch: {{subst:len|
parameter tag}}|0=
case 0 etc.}}
Template:Len is prepared for optional substitution, therefore both solutions work, but the latter solution substituting its code is simpler and more efficient.
Composite operations
By {{A|{{B|p}}}} a template A is called with, as parameter, a call of template B with a parameter p. We could integrate such template calls to a single call {{C|p}} of a "composite template" C with parameter p.
- The wikitext for template C would be {{A|{{B|{{{1}}}}}}}, or with optional substitution the following construct:
- {{ {{{subst|}}} A|{{ {{{subst|}}} B|{{{1}}} |subst={{{subst|}}} }} |subst={{{subst|}}} }}
- The subst={{{subst|}}} is only necessary for recursive substitution as explained above.
If A and/or B is predefined the construct is similar, but without subst={{{subst|}}} for that template.
Delayed substitution
Normally substitution works when the relevant page is saved (not in preview) as explained above. For a template or any other page used like a template this is often not the desired effect, e.g. if a variable should be evaluated at the time of the inclusion, not before (creation of template) or after (rendering of page) the inclusion.
A technique known as "includeonly subst magic" can delay substitution until a template is substituted:
The code {{<includeonly>subst:</includeonly>
something}} doesn't substitute "something" at the time of the creation of the relevant template, but has the desired effect when the template is substituted. Please note that this works as expected only for substitution, not for normal (unsubstituted) inclusion.
For examples see "preload" in Help:Inputbox and "substitution" in Help:Variable.
Forced substitution
Some templates deliberately refuse to work without substitution, for an example see en:template:Conv-dist ( talk edit history links ).
This technique is essential for templates like en:template:prod ( talk edit history links ) producing some kind of timestamp, e.g. adding pages to dated categories.
- The following code in any template T outputs a warning unless recursive substitution with subst=subst: is in effect:
- {{{{{subst|}}}ifdef|{{{{{subst|subst:}}}ns:0}}|'''Warning'''}}.
- Output for {{T}} or {{subst:T}}: Warning,
- output for {{T|subst=subst:}}: Template:Ifdef,
- output for {{subst:T|subst=subst:}}: nothing (no remaining wikitext).
- This is a rare case where replacing ifdef by #if: doesn't work directly.
Parameter default considerations
Substitution of {{{p|q}}} (a parameter tag with default) results in the value of p if it is defined, and otherwise not in q but in {{{p|q}}} rendered as q. This works fine in e.g. plain text and links:
In other cases there are complications. With substitution a numeric expression containing {{{p|q}}} gives an error message. A string comparison is possible but one should realize that the string contains {{{p|q}}} and not just q if p is undefined.
Instead of {{{p|q}}} one can use {{{{{subst|}}}#ifeq:{{{p|+}}}|{{{p|-}}}|{{{p}}}|q}}, with substitution (subst=subst:) this results in the wikitext q if p is undefined, so this can be used in a numeric expression, e.g.:
{{{{{subst|}}}#expr:2*{{{{{subst|}}}#ifeq:{{{1|+}}}|{{{1|-}}}|{{{1}}}|1}}}}
which doubles the parameter if is defined, and otherwise returns 2, see template:T double ( talk edit history links ).
Attempts of direct substitution
- {{subst:#expr:{{{a|1}}}}} gives
- Expression error: unrecognised punctuation character "{"
- An unsubstituted inclusion {{#expr:{{{a|1}}}}} yields 1.
- {{subst:#ifexpr:{{{a|1}}}>7|1|0}} gives
- Expression error: unrecognised punctuation character "{"
- An unsubstituted inclusion {{#ifexpr:{{{a|1}}}>7|1|0}} yields 0.
- Parameter tags with default are compared as strings instead of comparing the default:
- {{subst:#if: {{{a|1}}}|1|0}} gives 1 like a simple inclusion: 1,
- {{subst:#if: {{{a|}}}|1|0}} gives 1, but inclusion yields 0,
- {{subst:#ifeq: {{{a|1}}}|7|1|0}} gives 0 like a simple inclusion: 0,
- {{subst:#ifeq: {{{a|1}}}|1|1|0}} gives 0, but inclusion yields 1,
- {{subst:#ifeq: {{{a|1}}}|{{{a|1}}}|1|0}} gives 1 like an inclusion: 1,
- {{subst:#ifeq: {{{a|+}}}|{{{a|-}}}|1|0}} gives 0 like an inclusion: 0.
Thus {{#ifeq: {{{a|+}}}|{{{a|-}}}|1|0}}, a common way to determine if a given parameter is really undefined and not only empty, works also with substitution. Please note that #if: and templates like ifdef don't get this nuance, in the case of #if: an intentional feature for backwards compatibility. For details see advanced templates, in essence now obsolete because #ifeq: unlike #if: solves this problem even if substituted.
URLs
Fullurl and localurl with an undefined parameter cannot be substituted at all, even if a default value is specified.
This is a variation of the case of derived template names.
- {{subst:fullurl:{{{1|a}}}}} gives {{subst:fullurl:{{{1|a}}}}}.
- {{fullurl:{{{1|a}}}}} gives http://www.lensovet.net/~sysadmin/w/A.
- {{subst:localurl:{{{1|a}}}|x=y}} gives {{subst:localurl:a|x=y}}.
- {{localurl:{{{1|a}}}|x=y}} gives /~sysadmin/w/index.php?title=A&x=y.
- {{subst:fullurl:a}} gives http://meta.wikimedia.org/wiki/A.
- {{fullurl:a}} gives http://meta.wikimedia.org/wiki/A.
Corrupted default value
The value of undefined parameters {{{1}}}, {{{2}}}, {{{3}}}, and others used with colon functions is corrupted in a predictable way. Instead of the literal string {{{1}}} the part between first and second "|" vertical bar or pipe in the colon function is used. In other words the second parameter of the colon function overwrites {{{1}}}, the third {{{2}}}, etc.
This is not only a theoretical case, a #switch: can have many parameters, and as shown below bug 5678 can also affect named parameters.
For an unsubstituted inclusion this is generally no serious issue: a parameter is supposed to be used in a template, and if it is not assigned a default value, it is supposed to get a value when the template is called. The exact behaviour where that's not the case is less relevant, though it's anyway erroneous.
Unfortunately with substitution the default values are also corrupted following the same pattern, only defined parameters still work. Some colon functions like ns: support only one parameter and are therefore not affected. Examples:
- {{subst:plural:1|{{{2|singular}}}|error}} gives error.
- {{plural:1|{{{2|singular}}}|error}} gives singular,
- The subst: error is already visible in a preview before the actual substitution.
- {{subst:#ifeq: error|{{{2|-}}}|error|{{{1|no}}}}} gives -.
- {{#ifeq: error|{{{2|-}}}|error|{{{1|no}}}}} gives no,
- Not equal is correctly concluded, but the else part gives different results.
- {{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|{{{s}}}|{{{2|@}}}}} gives {{{s}}}
- {{#ifeq: {{{s|+}}}|{{{s|-}}}|{{{s}}}|{{{2|@}}}}} gives @
- Same idea, here the {{{s}}} after the 2nd "|" clobbers an undefined {{{2}}}.
- {{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|.|o{{{3|ps}}}}} gives oops
- The "3rd" (actually fourth) parameter clobbers itself, oops instead of ops.
- {{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|.|o{{{4|k}}}|ops}} gives oops
- The extraneous "4th" ops corrupted the parameter default k.
- {{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|.|o{{{4|k}}}}} gives ok
- Without "4th" parameter the specified 4th parameter default k survived.
- {{subst:#if:|error|{{{1|void}}}}} gives error.
- {{#if:|error|{{{1|void}}}}} gives void.
- Similar the word error after the 1st vertical bar overwrites {{{1|void}}}.
- {{subst:#ifexpr:0|error|{{{1|zero}}}}} gives error.
- {{#ifexpr:0|error|{{{1|zero}}}}} gives zero.
- The same issue as before for another colon function.
- {{subst:#ifexpr:1|{{{0|okay}}}|-}} gives okay.
- {{#ifexpr:1|{{{0|okay}}}|-}} gives okay.
- For what's it worth, it doesn't hit an unnamed parameter {{{0}}}.
Because these examples actually substituted the shown code they won't reflect future fixes automatically. For the actual state of the underlying problem without substitution see ParserFunctions/5678.
- In the case of #switch: the bug can apply in wild and wonderful ways:
- {{#switch:a|a={{{1|c}}}|b={{{1|c}}}}} gives c,
- {{#switch:a|a|b={{{1|c}}}}} gives c,
- {{#switch:a|a={{{b|0}}}{{{d|0}}}|b=c|d=e}} gives 00, and
- {{subst:#switch:a|a={{{1|c}}}|b={{{1|c}}}}} gives c as expected.
- However:
- {{subst:#switch:a|a|b={{{1|c}}}}} gives a,
- {{subst:#switch:a|a={{{b|0}}}{{{d|0}}}|b=c|d=e}} gives ce.
- As shown this oddity isn't limited to unnamed parameters {{{1}}} etc., it can also hit named parameters, here {{{b}}} and {{{d}}}.
A similar problem does not occur with regular templates:
- {{subst:t2|error|{{{1|void}}} gives start-error-middle-void-end.
Workarounds
As mentioned above, instead of {{{p|q}}} one can use {{{{{subst|}}}#ifeq:{{{p|+}}}|{{{p|-}}}|{{{p}}}|q}}. This way parameter tags with defaults only appear as strings to be compared, and these do not seem to be affected by the bug.
For a switch inside a template, avoid listed switch index values being equal to names of parameters for which a default is supplied. This can be done by adding some prefix to the expression for the index and to each of its listed values.
If in
- {{#ifexpr:p|q|r}}
q and r are numeric expressions, it can be replaced by
- {{#expr:p*q+(1-p)*r}} (suitable if p is short)
- {{#expr:q+(1-p)*(r-q)}} (suitable if q is short)
- {{#expr:p*(q-r)+r}} (suitable if r is short)
(not the same if p is different from 0 and 1), and similarly for #if, #ifexist, and #ifeq.
If r=0 we can simply take
- {{#expr:p*q}}
Of course, if the expression is inside another expression we do not need another #expr.
See also
- w:Wikipedia:Template substitution - partly technical, partly policy
http://www.fayeunrauphotography.com/ kjøp cialis 520853 http://www.primetermites.com/ ジェネリックバイアグラ 5575 http://www.witch-ring.com/Generic-Viagra/ Comprando viagra sfnjy http://www.flweaver.com/ online Cialis kmt http://www.blogdemoteros.com/ tadalafil 5271