Over here it was pointed out by @etardiff that \function definitions don’t support nested definitions. I was more than a little taken back by that statement. Tonight I played around and sure enough, you can’t nest anything inside a function, it’s simply not supported.
I notice, even the docs skirt around the topic.
Note that the \end marker can optionally specify the name of the function to which it relates, enabling function definitions to be nested inside procedures, macros or widget definitions.
… but notable by its absence, not inside functions!
… is true, and, the SetVariableWidget supports nesting (it most certainly does), it begs the question, what happened during development that prevented \function from supporting nesting?
The benefit of defining short, one-liners inside a function is obvious, especially when the function itself is tagged Macro or Global:
<!-- WRONG - DON'T DO THIS -->
\function .myfn(...)
\define x() ...
\define y() ...
[... <x> .... <y> ... ]
\end .myfn
<!-- THIS will work (sadly) -->
\define x() ...
\define y() ...
\function .myfn(...)
[... <x> .... <y> ... ]
\end .myfn
But now you’ve exposed <<x>> and <<y>> to the world (and stopped yourself from ever using the names anywhere else).
@jeremyruston Are we stuck with this anomaly or might things improve sometime in the future?
@CodaCoder perhaps what you ask for is feasible, I don’t know. However to me it appears to be a “category error” trying to nest functions in this way. I will explain why I think this;
A function in synonymous with a filter. Thats how I remember that a \fffunction is a fffilter. Thus the idea of a filter containing a procedure/macro/another filter is already well known, we nest filters this way;
When we “nest filters” we do so using filter notation such as [subfilter<anotherFilter>][<macroname parameter>] and now with custom operators defined in other functions [my.func[]], [function[myfunc]] and others.
If you wish to do the nesting, you are asking for, you can just use a procedure, custom widget etc…
On one hand
It seems to me a function, which is a filter, can only contain filter notated information, because it will be used as a filter in one or more places.
You could however construct a large string of filter notation, in a procedure, and use that in a function but not the other way around.
On the other hand;
Define (macros), Procedures, custom widgets are designed to contain any tiddlywiki script including wikitext, widgets, other macros and procedures. This is where we can nest things.
Since we can now nest pragmas inside procedure definitions, and custom widgets we can also nest the definitions of these different things including functions inside these.
\function x(as many local variables as you want:"This one is initialized")
The \define x(test) pragma had a problem, because the variable name in the definition here was testbut using it, users where forced to use <<__test__>> for “local” variables. This makes the whole system hard to understand and inconsistent.
Function and Procedures changed that behaviour. Now the user has the freedom to use their own names, which needs to think about variable names.
For you own sanity I would suggest, that you name variable names in a way, that allows you to identify the difference between global and local variables. eg: Let local vars start with an underscore
\procedure y(_some _local _variables)
Now it's possible to differentiate between `<<_variables>>` and `<<variables>>`,
where the later one is global and the others are local.
\end
Function definitions are filter expressions, which do not support wikitext features like the <$set> widget so it is not possible to embed the latter in the former.
There has been some discussion since v5.3.0 about the possibility of introducing a filter syntax for creating variable definitions. The most recent discussion was related to a proposed new interleave operator by @rmunn. I think @Mark_S also raised a similar discussion here on talk.tiddlywiki.org.
The very first line of the “Functions” tiddler says “a function is a named snippet of text containing a filter expression”. Do we need to add a note to clarify that filter expressions cannot contain widgets or pragmas, or is there something else you have in mind?
The $specialfunctiondefinitionmode attribute is because it is not actually currently possible to replicate a function/procedure/widget/macro definition pragma with a set widget, but it is planned to expose that functionality.
@jeremyruston (I’m not a fan of testing your thesis statement(s) but…)
Well, clearly. But you said the <$set> block was “equivalent to” the former block, i.e. the \function definitions. If .fn2 “ends up” inside a notional definition for .fn1 (using <$set>) that would make .fn2 inaccessible outside the block (as we’re agreed).
This is actually too confusing – I’m not confident I’m expressing myself clearly. So, code…
I would expect .fn2 to be in scope below. If what you say is actually the case (and why would I doubt you) then it should be out of scope (just as it is in the <$set> block):
\function .fn1(a,b) [<a>add<b>]
\function .fn2(a,b) [<a>subtract<b>]
Some text
{{{ [.fn2[...]] }}}
But I’m sure it would be in scope. Therefore, I don’t see the equivalence.
Hi @CodaCoder your example is equivalent to the following:
<$set name=".fn1" parameters="(a,b)" value="[<a>add<b>]">
<$set name=".fn2" parameters="(a,b)" value="[<a>subtract<b>]">
Some text
{{{ [.fn2[...]] }}}
</$set>
</$set>
In other words, the set widget generated by a definition pragma contains the entire remainder of the tiddler, including any further pragma definitions.
I don’t think there’s anything structurally different about functions. Everything that I have described about how the definition pragmas works applies to macros, widgets, procedures and functions. They all wrap the entire remainder of the tiddler.