Introducing Multi-valued Variables

When I try the above on the preview site, I get Filter error: Missing [ in filter expression. If I change it to [my.function(multivaluedvarname),<anothervarname>,[a constant]] then I don’t get any error (displays all tiddler titles since my.function is undefined). Maybe the current code is only handling the parens syntax for the first argument?

I’m trying the above because I’m skeptical about using special syntax for this. To me it seems better to use an operator to handle the MVV (though difficult to come up with a good name for it).

Unless I misunderstand the code, in order for any javascript operator to make use of an MVV, code has to be explicitly added as you’ve done for the title operator (i.e. [(myvar)] is shorthand for [title(myvar)]).

Do you envision use cases beyond just the title operator for this? If so then will the special case code be added? If not, then it seem like a very big decision to lock in new syntax for not much gain.

Maybe there are gains to be had with this syntax and user defined functions? That’s why I was trying the syntax I quoted from your post. To try to understand the benefits from the user defined function perspective.

Adding this as an operator would involve much less “lock in”. In fact, even with the special syntax, a dedicated operator might still be worthwhile since an operator can have variables as arguments.

Contrived example:

function concat.vars(a1, a2, a3)
[varlist<a1>] :all[varlist<a2>] :all[varlist<a3>]
\end

{{{ a b c :let[[v1]] [concat.vars[v1],[v1],[v1]] }}}

=> a b c a b c a b c

Did you consider the possibility of implementing let as an operator rather than a filter run prefix?

Thanks @btheado funnily enough I just fixed that bug here.

Newly written operators can choose to just use the operand property that gives multi-valued operands, and avoid special cases.

Writing that made me realise the title operator doesn’t use that technique so I pushed an update here.

Reviewing the current list of operators I haven’t come up with any more existing operators that would seem to benefit from multi-valued operands, but I’d welcome suggestions.

However, there is plenty of scope for new operators that take advantage of multi-values - for example, some revised, more concise list operators for manipulating multiple lists at once.

I’ve also just pushed an update allowing multivalued parameters for user defined functions.

With the latest update your example works as expected when updated to use the latest syntax:

\function concat.vars(a1, a2, a3)
[(a1)] :all[(a2)] :all[(a3)]
\end

{{{ a b c :let[[v1]] [concat.vars(v1),(v1),(v1)] }}}

I am dubious about allowing filter operators to have side effects. It’s bad enough that this PR introduces a filter run prefix that has side effects.

There are also ergonomic considerations. I find that the :let filter run prefix or the prefix jumps out much more prominently than operators when visually scanning the text of a filter.

The implementation would be tricky because of backwards compatibility. Filter operators currently return an array of results or an iterator. There would have to be some form of overloading to allow filter operators to also return variables that need to be set for the scope of the remainder of the filter.

3 Likes

The count[] operator could be a candidate for special MVV handling.

Sadly, I don’t think we can make count(var) do anything useful because it conflicts with the existing semantics.

However, counting the number of items in a multi-valued variable is still very simple:

<$let a={{{ [all[tiddlers]] }}}>
<$text text={{{ [(a)count[]] }}}/>
</$let>
1 Like

In order to be able to test and adapt to MVVs in wikis that I don’t want to fully upgrade to the current prerelease, I made a plugin from the core tiddlers in the merged PR. This way I can activate and deactivate MVVs simply by enabling and disabling the plugin in $:/ControlPanel.

It’s a bit late, maybe, but the 5.4.0 release is still a ways off, so it might still be useful for some folks.

$__plugins_yaisog_multi-valued-variables.json (99.3 KB)

PS: Just to throw it out there: Might it be a good idea to automatically generate plugins from PRs, for targeted testing and such?

I think there is no need to make it configurable. The changes should be backwards compatible. If you do not need MVVs, just do not use them. There is a completely new syntax to use them. If you use standard variable syntax there should be no changes.

For new functionality, that is intended to be a plugin → yes.

For generic functions, that will be part of the core → no.

We can not guarantee that those temporary-plugins go away after the new TW version is released. They will cause problems, which will be hard to find and maintain. We do not have the capacity and the mechanisms to get rid of outdated stuff.

Every PR can be tested in isolation with the Netlfy PR preview functionality see: Introduce multi-valued variables and let filter run prefix by Jermolene · Pull Request #8972 · TiddlyWiki/TiddlyWiki5 · GitHub

I made it specifically to test MVVs (and only MVVs) without upgrading my wikis to the prerelease. When I eventually upgrade to v5.4.0, I can just remove the plugin, which is easier to do that to remove all the individual tiddlers.

Upgrading whole wikis is always a hassle, and I might like to cherry-pick individual PRs for inclusion to solve a particular problem. Plugins make this easier than tracking individual tiddlers for later removal.

I thought this might be useful for others, but YMMV. I’m not making anyone use it. :man_shrugging:

That’s why we want users to test the whole prerelease and give feedback, if there is something going wrong.

The prerelease will be updated till 31st Jan. 2026, when it goes into “feature freeze”, where only bugs will be fixed until it is released.

OK, I’m trying to do my part in response to

I’m never sure whether my own skills are at fault, but I’m getting unexpected results with title(MVV) in the modifier position of a filter run.

Hidden content below just shows my own failure to note that title (even in MVV usage) can't be harnessed in modifier role.

If AboutTiddlers is MVV for tiddlers with About tag, I assumed

{{{ [tag[Community]title(AboutTiddlers)] }}}

should yield tag intersection, same as (what does work):

{{{ [(AboutTiddlers)tag[Community]] }}}

But instead it’s not working to constrain prior list. Oddly, when negated !title(MVV) it DOES work as expected (=constraining filter’s existing set of values):

{{{ [tag[Community]!title(AboutTiddlers)] }}}

Here’s screenshot of experimentation at tw-com:

see https://tiddlywiki.com/#title%20Operator

The title operator is a selection constructor. Thus, it ignores the result of all filter operators that precede it. Note, however, that !title is a selection modifier, so it does handle preceding filter results. To apply a title filter as a selection modifier, use field:title(AboutTiddlers).

-e

1 Like

I do appreciate the way title[HelloThere] and field:title[HelloThere] differ — as selection constructor vs modifier. Of course, a filter such as [tag[Community]title[HelloThere]] does replace all prior filter contents with the one new value.

I especially don’t see how adding field: would be at all logical in the MVV case where we’re not referencing a tiddler field called title in any way… :thinking:

At any rate, it’s still not behaving as modifier when I swap in field:title:

SO, question: is there any way to leverage MVV in modifier role (say, taking xyz existing filter run, and “straining” it through the MVV list to get the intersection)?

EDIT: ANSWER: Yes, the intersection filter run prefix is exactly up for the job:

{{{ [tag[Community]] :intersection[(AboutTiddlers)] }}} works

1 Like

Right now, title[] and function[] are the only filter operators that work with MVVs, field[] does not.

As you already found out, :intersection works, because it uses title[] (implicitly). BTW, I proposed an intersection[] operator that works with MVVs here, so we don’t need an extra run (which can cause trouble if there are more than one preceding runs, since it cannot apply to only one of them). Give it an upvote if you like.

Also, check out the short documentation for the title operator. It has all the answers to your initial questions.

1 Like