User:J. Noel Chiappa/TemplateExpansionNote1

From Citizendium
Jump to navigation Jump to search


The account of this former contributor was not re-activated after the server upgrade of March 2022.


OK, so now that I have thought about this a bit, I think my earlier supposition was partially right, and whether or not you call templates B and C directly, or through an intermediary BC template which calls them both, 'sorta' doesn't make a difference - and in either the old or the new parser.

The reason is that template expansion is just that - expansion of a string. It's not a procedural language where first one procedure gets executed, and then another, ad seriam.

The 'sorta' is there because due to a quirk, in your particular case it might! I explain at the very end...


To make this a little more explicit, here's why Zach's hack is useful, in the old parser, (but not in the new, if I'm correctly understanding the details of how the old and new parsers work - if I'm not, a lot of the rest of this note is crap and can be ignored :-). Also, to the extent you already understand this, my apologies in advance, I'm in part writing this out in detail to clarify my own understanding.

Anyway, if you have an expression of the form:

1 {{#if: test1 | {{A|arglist}} {{#if: test2 | {{B|arglist}}

In the old parser, which evaluates arguments before it does conditionals, the first thing that happens is that every instance of arglist gets expanded into the long form. So you wind up with this ginormous string:

1a {{#if: test1 | {{A|expanded_arglist}} {{#if: | test2 {{B|expanded_arglist}}

And of course the whole thing recurses - to the extent that either testN or expanded_arglist contains a template call, those template calls are further expanded.

Only when all template substitution has run to completion does it then runs down that fully-expanded string, checking the testNs, and discarding the text for those which aren't true, giving you (finally):

1b {{B|extended_arglist}}

The new parser does the 'runs down the tests' first, so directly after 1 you'd wind up with something like:

2a {{B|arglist}}

which would then expand into:

2b {{B|extended_arglist}}

(same as 1b).

Zach's hack, of writing such expressions as:

3 {{ {{#if: test | A | B}} | arglist}}

means that in the old parser, the first thing that happens is:

3a {{ {{#if: test | A | B}} | expanded_arglist}}

(note only one copy of expanded_arglist now, as opposed to two in 1a above), and then you get:

3b {{B|expanded_arglist}}

(just like 1b and 2b above).

And of course, in the new parser, his trick buys you nothing, since even if you start with 1, you go from 1 to 2a to 2b without ever going through 1a.


With that as an warmup, here's why (and sorry this is so long, I know it gets kind of grind-the-cranky after a while, but as I'm sure you know through painful experience, in programming the devil is always in the details :-) it 'sort of' doesn't make any difference (in either parser) whether you code the thing you were trying to do last night as

a {{#if: test2 | {{B|arglist}} }} {{#if: test2 | {{C|arglist}} }}

(note same test in both) or:

b {{#if: test2 | {{BC|arglist}} }}

(where template BC just calls template B and C with its own arguments).

Clearly, in the old parser, evaluation of form a procedes as:

a1o {{#if: test2 | {{B|expanded_arglist}} }} {{#if: test2 | {{C|expanded_arglist}} }}

a2o {{B|expanded_arglist}} {{C|expanded_arglist}}

but look at what happens (I think; maybe it does the BC expansion after it does the #if, but it doesn't matter, because you wind up in the same place in the end, see b2n1-b3n1 and b2n2-b3n2 below) in the old parser with b:

b1o {{#if: test2 | {{BC|expanded_arglist}} }}

b2o {{#if: test2 | {{B|expanded_arglist}} {{C|expanded_arglist}} }}

b3o {{B|expandedarglist}} {{C|expandedarglist}}

Note that b3o = a2o! Now, let's look at case a in the new parser:

a1n {{B|arglist}} {{C|arglist}}

a2n {{B|expanded_arglist}} {{C|expanded_arglist}}

No help there, a2n = b3o = a2o - and with case b in the new parser:

b1n {{BC|arglist}}

and at this point I don't know if the new parser goes either:

b2n1 {{B|arglist}} {{C|arglist}}

b3n1 {{B|expanded_arglist}} {{C|expanded_arglist}}

(arglist is expanded first) or

b2n2 {{BC|expanded_arglist}}

b3n2 {{B|expanded_arglist}} {{C|expanded_arglist}}

(BC call is expanded first), but it doesn't matter which it does, because in the end b2n1 = b3n2 = a2n = b3o = a2o.

I.e. you always wind up with both B and C sitting there with a fully expanded argument list - which was the point of my comment at the top about how "it's not a procedural language where first one procedure gets executed, and then another".


However, in your particular case, it does make a tiny bit of difference, and doing the BC template is better (although only in the old parser)! Here's how:

You're trying to write an expression of the form:

1 {{#if: test1 | {{A|arglist}} }} {{#if: test2 | {{B|arglist}} }} {{#if: test2 | {{C|arglist}} }}

In the old parser, that expands to:

1a {{#if: test1 | {{A|expanded_arglist}} }} {{#if: test2 | {{B|expanded_arglist}} }} {{#if: test2 | {{C|expanded_arglist}} }}

which is clearly the worst of all possible worlds. Zach's hack, combined with the AB trick, recasts it into:

2 {{ {{#if: test | A | BC }} | arglist}}

In the old parser, this expands as follows:

2ao {{ {{#if: test | A | BC }} | expanded_arglist}}

and then we get (I think) either:

2bot {{ A | expanded_arglist}}

or

2bof {{ BC | expanded_arglist}}

2cof {{ B | expanded_arglist}} {{ B | expanded_arglist}}

depending on whether "test" is true or not.

In other words, you go from a max of 3 copies of "expanded_arguments" (with the 'classical' approach, in the old parser) to 2.

In other words, the new-hack approach (Zach's hack plus your trick) is suppressing (at the peak size of the expansion) the expansion of either i) the arglist for A (when you're doing BC), or ii) for BC (when you're doing A), which is useful.


But all the other cases: new-hack in the old parser, or either classical or new-hack in the new parser, all still wind up with 2 copies of the expanded_arguments.

Unless of course there are conditionals in the expanded_arguments, and those are being evaluated before the call to the BC template duplicates the expanded_arguments - I think that might be the way the new parser operates, but I don't fully understand it yet. If so, that will reduce the size of expanded_arguments before it is duplicated.

And sorry this was such a saga!