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