Nested SetVariableWidgets inside \function

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!

However, if the claim that…

The \function pragma is […] a shortcut syntax for the SetVariableWidget.

… 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?

Thanks for reading.

1 Like

@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.

There’s a lot to what you say, but this should work…

\function f1(...)
 \function f2(...)
  [...]
 \end f2
 [...]
\end

If it’s a SetVariableWidget that can only do filter stuff, the above nesting should be allowed.

Perhaps show me what the intermediate or end result you would expect.

Some of the solutions in the thread I linked.

:sleeping: time here.

Okay, this should be obvious…

\function .srgr(s) [search-replace:g:regexp<s>,<s>]
\function .reesc() 
[.srgr[\-].srgr[\!].srgr[\.].srgr[\$].srgr[\{].srgr[\}].srgr[\<].srgr[\>].srgr<osq>.srgr<csq>]
\end .reesc

.srgr should be nested inside .reesc

hmmmm, why so complicated?

\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 test but 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

Just some food for thoughts
-mario

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.

Not to me, as posted above but in I am nesting functions in a widget, it works for a procedure as well, to similar effect.

As I suspected. The docs are misleading, then.

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?

@jeremyruston
Let’s just talk about \function as a shortcut form of <$set>, which is what the docs claim right now. In code…

<$set ... >
 <$set ... >
     ...
 </$set>
</$set>

\function .fn1(...)
 \function .fn2(...) [ ... ]
 [ ... .fn2[...] ... ]
\end .fn1

The former, or support my latter (please).

Hi @CodaCoder

In fact, consecutive function definitions result in nested set widgets, so in a sense function definitions are already nested.

You can use the “parsetree” preview mode of the Internals plugin to see this. The wikitext:

\function .fn1(a,b) [<a>add<b>]
\function .fn2(a,b) [<a>subtract<b>]

Some text

Results in a parse tree equivalent to:

<$set $specialfunctiondefinitionmode="yes" name=".fn1" value="[<a>add<b>]">
<$set $specialfunctiondefinitionmode="yes" name=".fn2" value="[<a>subtract<b>]">
<p>Some text</p>
</$set>
</$set>

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.

Hidden attributes? Wow.

So what happens here?

<$set $specialfunctiondefinitionmode="yes" name=".fn1" value="[<a>add<b>]">
<$set $specialfunctiondefinitionmode="yes" name=".fn2" value="[<a>subtract<b>]">
<p>Some text</p>
</$set>
</$set>

{{{ [.fn2[...]] }}}

Looking at the former code block, .fn2 should be in scope. Looking at the latter code block, it should be unavailable.

.fn2 in the filtered transclusion is not in scope because it is not within the <$set> widget.

Remember that the set widgets that are generated by the definition pragmas wrap everything up to the end of the tiddler in which they appear.

@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.

In a nutshell, you (we) can’t have it both ways.

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.

Astonishing. \function is a whole new concept – structurally, at least.

Thanks.

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.

You’ll be less than astonished to hear I’m…

facepalm-2583654279