Topic on Extension talk:Variables

how to undefine a previously-defined variable?

8
Summary by MGChecker

There are no plans to support undefining a previously defined variable for minuscle performance benfits.

2600:1700:1B0:BA0:A82F:CAEB:C7F7:8FAF (talkcontribs)

I have a template whose behavior changes based on the existence of a variable. It uses {{#varexists...}} for this purpose. I'd like to be able to define/undefine this variable multiple times, e.g.

#vardefine:debug_flag}}
{{My Template}}
{{#varundef:debug_flag}}
{{My Template}}

But currently there is no way that I know of to undefine a variable after defining it. --~~~~

Dinoguy1000 (talkcontribs)

To be honest, I've never had any use for #varexists; instead, I just define variables with a dummy value (e.g. {{ #vardefine: foo | 1 }}) and then test if the variable has a value with an #if. That way, if I need to later undefine the variable, I can simply clear its value via {{ #vardefine: foo }}.

194.230.155.242 (talkcontribs)

It is a feature that this is not possible, thus a definition of a variable can never be done.

Instead, I recommend Dinoguys approach of checking if a variable is empty. --MGC

2600:1700:1B0:BA0:988E:1F3E:9575:814C (talkcontribs)

What do you mean by "it is a feature"? What is the advantage of {{#varundef}} not existing? I guess I will have to do it the way Dinoguy1000 suggested. Equivalently, no one ever needs to use {{#varexists}} -- they can always use {{#if}}. But then, why does {{#varexists}} exist?

Dinoguy1000 (talkcontribs)

I would have to check this, but at a glance I'd guess that {{ #varexists: foo | ... }} is very slightly more efficient than {{ #if: {{ #var: foo }} | ... }} (at the very least, it does make the intention of the code clearer). I wouldn't say to avoid using #varexists entirely, but to use it only for variables that are fully static flags (i.e. the variable is defined - or not - in only one place in the template, and it isn't touched afterwards except to check for it). Certainly, now that I've taken a closer look and thought about it a bit, I'll be going over my own templates and using it where appropriate (after testing to see how it stacks up to #if: #var:, in terms of template limits, at least).

2600:1700:1B0:BA0:2D95:883D:C0D7:C5DC (talkcontribs)

I wouldn't recommend you change all of your templates for an infinitesimal efficiency improvement. You will be giving up the option of doing what I mentioned in my initial post. If you have a thousand references to your template on a page, and you only want the variable to be defined for the first half of them (maybe you're doing a binary search), you won't be able to do it.

Dinoguy1000 (talkcontribs)

I'm keenly aware of the gotcha's here, believe me. The changeover would be to benefit code readability (and thus maintainability); any potential efficiency improvement (even an infinitesimal one) would just be a nice bonus.

Dinoguy1000 (talkcontribs)

Revisiting this now that I've looked a bit more into it: careful use of #varexists can save a significant amount on the NewPP parser report metrics (in particular "Preprocessor visited node count", "Post-expand include size", and "Template argument size"), over my go-to {{ #if: {{ #var: construction.

For example, this version of "Template:Chapter" on my wiki (the current version as of writing this, but it won't be for long), as used on the current version of the page "Dark Yugi (manga)" (where the template is transcluded 338 times), results in the following NewPP report:

NewPP limit report
Cached time: 20210907163321
Cache expiry: 1209600
Dynamic content: false
[SMW] In‐text annotation parser time: 0.017 seconds
CPU time usage: 4.748 seconds
Real time usage: 8.358 seconds
Preprocessor visited node count: 64228/1000000
Preprocessor generated node count: 60933/1000000
Post‐expand include size: 418313/2097152 bytes
Template argument size: 35083/2097152 bytes
Highest expansion depth: 17/40
Expensive parser function count: 0/100
Unstrip recursion depth: 1/20
Unstrip post‐expand size: 112756/5000000 bytes
Lua time usage: 2.450/20.000 seconds
Lua virtual size: 14.27 MB/50 MB
Lua estimated memory usage: 0 bytes

However, changing the first line in the template:

<includeonly>{{ #vardefine: $smw | {{ #var: $smw | {{ #if: {{ #show: }} | off | on }} }}<!-- standard implementation -->

to

<includeonly>{{ #varexists: $smw || {{ #vardefine: $smw | {{ #if: {{ #show: }} || 1 }} }}<!-- standard implementation -->

and line 40 from

}}{{ #vardefine: $chapter-name | {{ #ifeq: {{ #var: $chapter-mode }} | number || {{ #ifeq: {{ #var: $smw }} | on | {{ #show: {{ #var: $chapter-pagename }} |?English name }} }} }}

to

}}{{ #vardefine: $chapter-name | {{ #ifeq: {{ #var: $chapter-mode }} | number || {{ #if: {{ #var: $smw }} | {{ #show: {{ #var: $chapter-pagename }} |?English name }} }} }}

...results in the following report:

NewPP limit report
Cached time: 20210907165826
Cache expiry: 1209600
Dynamic content: false
[SMW] In‐text annotation parser time: 0.015 seconds
CPU time usage: 4.776 seconds
Real time usage: 8.623 seconds
Preprocessor visited node count: 63678/1000000
Preprocessor generated node count: 60933/1000000
Post‐expand include size: 417637/2097152 bytes
Template argument size: 35083/2097152 bytes
Highest expansion depth: 17/40
Expensive parser function count: 0/100
Unstrip recursion depth: 1/20
Unstrip post‐expand size: 112756/5000000 bytes
Lua time usage: 2.570/20.000 seconds
Lua virtual size: 14.3 MB/50 MB
Lua estimated memory usage: 0 bytes

Note in particular that "Preprocessor visited node count" dropped from 64228 to 63678, and "Post-expand include size" dropped from 418313 to 417637.

However, as things stand, I am unable to use this method in more places in "Template:Chapter", since other variables I'd like to use it on are always defined, and communicate meaningful state if they are empty (there is no way around this, since subsequent transclusions may store nonempty values to these variables, and then empty values again, and so on). For example, changing line 28 from

}}{{ #vardefine: $chapter-subseries | {{ #if: {{ #var: $chapter-series }}

to

}}{{ #vardefine: $chapter-subseries | {{ #varexists: $chapter-series

...would result in "Preprocessor visited node count" dropping further to 60641, and "Post-expand include size" dropping to 371846, but would not work correctly in some cases of multiple transclusions of the template on the same page, as explained above. However, you don't even need to look past $smw to find suboptimal behavior: because it can be defined but empty, it must be tested on line 40 via {{ #if: {{ #var: $smw }} ..., instead of being able to just use {{ #varexists: $smw ...!

This could be fixed in one of two ways: add a function to undefine a variable entirely, or add a way to test for variable existence that considers empty-but-defined variables to not exist (whether by a modification of #varexists, or the introduction of a new parser function).

(I am, of course, aware of Scribunto and Lua - and we do use modules for a number of things on the wiki already - but we currently only have one editor who is able and willing to develop and maintain modules for us, and they don't have much time to spend on the wiki; I've tried learning myself, but could never get the hang of it.)