(source) C. Scott Ananian: Ideas/A Dozen Visions for Wikitext/Varargs

Variable-length/structured arguments

Have you ever had to stare at a template like this and try to figure out what in the world it is doing?

Confusing template

Well, most of what it is doing it just passing arguments through to its children!

Here’s something to help with that mess.  In wikitext, template arguments are unstructured strings which can make it difficult to manipulate them.  Recently we landed PFragment support in Parsoid and core (phab:T374616), which allows you to embed structured data in wikitext.  This allows us to add parser function constructors, which create structured data values:

{{#list:one|two|three}}

The output of the {{#list}} parser function here is not a plain string, but instead a structured list which can be passed to other templates or parser functions and further manipulated.  We can extract the first element of the list using {{#first}}, for example:

{{#first: {{#list:one|two|three}} }}

We can also create a key/value or named-argument list:

{{#kv: name=Moth | caption=Variable Drab Moth }}

This is a two-element list whose first element is the key name and value Moth, and whose second element is the key caption and value Variable Drab Moth.

Note that there is no new syntax added to wikitext so far, this is just internally creating a new structured-data output type for transclusions. And in fact you can do this even without changes to wikitext internals; the ArrayFunctions extension does this by passing around a base64-encoded JSON string value (to ensure it does not contain wikitext special characters) and decoding the value whenever access to the structured value is required.

Using these structured types, we now have a reasonable way to do variable-length argument lists.  In current wikitext, this would typically be done by suffixing the argument names: you’d have name1, caption1, name2, caption2, etc and the source of MyTemplate would have ten or twenty copies of identical code to process each argument, depending on whatever the maximum number of arguments was expected to be:

{{MyTemplate
|name1   = A
|caption1= Apple
|name2   = B
|caption2= Banana
}}

But now we can write this instead:

{{MyTemplate
|files={{#list:
 {{#kv:name=A|caption=Apple}}|
 {{#kv:name=B|caption=Banana}}
}}}}

And we can iterate over the files argument as a structured list of key/value pairs.

Note that #list is just syntactic sugar for #kv, since {{#list|one}} is the same as {{#kv|one}} which wikitext treats as shorthand for {{#kv|1=one}}. Yes, wikitext is 1-based, not 0-based.  Still no new syntax required.

If we’re willing to reserve the argument name ...,[1] we can use these structured arguments to implement safe argument forwarding. We propose to make {{{...}}} evaluate to a structured key/value pair list of all of the current template’s arguments. We can then manipulate those using the methods operating on structured data. If a key/value pair list is passed to a transclusion as an argument named ... it is expanded into the argument list, allowing invocations like:

{{Template:Infobox
|type=movies
|...={{{...}}}
}}

where arguments are safely forwarded to a child. This solves a long-standing limitation of templates which has been the cause of a lot of unreadable template code, and which required the addition of parent frame access in the design of Scribunto.

This requires new semantics for the argument named ... but still no new syntax.

Next section: Annotations

  1. Or lint away any existing uses of ... as an argument name on the projects.
C. Scott Ananian [[User:cscott]]