Right. \function
has some similarities to both \define
and $let
, but it’s not exactly like either. Here’s a quick comparison:
- I tend to write all my functions with.periods and avoid using periods in macro names or variables, just so it’s very clear which is which, but I used periods in all the names here for consistency.
What \define
does: defines a string of text as a variable. The text will get literally pasted (not evaluated in advance) wherever you use the variable, and then rendered at the same time as the rest of the tiddler. (You can see the difference in Definition and Definition #2.)
- defines a variable
- can’t be used as a custom filter operator; see the results when we try to use it in the $list.
What $let
does: defines a string of text as a variable. If this text can be evaluated (like a transclusion), it will be evaluated at the point where $let is used, and the final value will be substituted wherever you use the variable.
- defines a variable
- If you use a filtered transclusion (as I did with
test.let
), the value of <<test.let>>
is set to the first result returned by the filter.
- If you want to preserve the full list, you’d have to use
test.let={{{ [tag[HelloThere]] +[format:titlelist[]join[ ]] }}}
, and then retrieve it with [enlist<test.let>]
- can’t be used as a custom filter operator
- is evaluated once; a string defined with
\define
is evaluated (if applicable; at the same time as its context) each time you use the variable. This means $let is sometimes more efficient, however…
- everything inside $let will get rerendered every time the value of the variable changes
What \function
does: defines a filter as a variable. The filter will get evaluated in context every time you use the function; the results differ depending on how you use it.
- can be used as a variable;
<<test.function>>
= the first value of the filter. To keep the full list, you need to use format:titlelist[]join[ ]
(just like using $let with filtered transclusion).
- can be used as a filter operator if the name of the function contains at least one period.
- functions like a subfilter/a standard filter operator, and can return more than one result
- can also be called within a filter using the
function
operator: function<test.function>
= test.function[]
- can take one or more parameters (like
\define
and \procedure
can), which will be substituted with the values you specify when you use the function. This is the trick I used with starts.with[H]
:
You can name any number of space- or comma-separated parameters in the function definition and use them as variables in the function’s filter. When you call the function (as a variable or inside a filter), the values you specific will be substituted in the order they’re given and used to evaluate the function.
\function another.function(tag, prefix, suffix) [tag<tag>prefix<prefix>suffix<suffix>]
{{{ [another.function[tag],{!!prefix},<suffix>] }}}
is equivalent to
{{{ [tag[tag]prefix{!!prefix}suffix<suffix>] }}}
- You can use
$let
or \define
to define a static filter and then call it in a filter with subfilter<my-filter>
or filter<my-filter>
, but you can’t do the kind of variable substitution that you can with \function
.
Re: macros vs. procedures…
Procedures are just the modern version of macros—and like macros, they don’t evaluate prior to substitution. The only major difference is the way they handle variables and text substitution:
Procedures can be more efficient since they’re not doing substitution. You still need \define
for instances where you do need this kind of substitution, though, and I also like to use it to define static strings:
\define tag-list() tag1 tag2 tag3
\procedure tag-list() tag1 tag2 tag3
<!-- ^^ mean the same thing, but \define makes more sense to me when defining is really all I'm doing. -->