Local functions

I was recently told to use functions to have clearer filters in my code. That’s a good idea.

But it is not so practical when you can’t encapsulate functions within procedure or function. If your tiddler is tagged as $:/tags/macro these functions will be exported to the outside, which can lead to bugs elsewhere. And that’s not clean anyway.

Short of that, we could have functions/procedure that would not be exported even if they should have. For instance, we could have functions or procedures whose name begin by private. not be exported. That would be easy enough to implement (in the senshttps://talk.tiddlywiki.org/t/inputting-a-function-into-a-function/8404e that many things would be left unchanged) and give nearly all the things I was asking for.

Besides,exporting procedures with tag $:/tags/macros is about OK but also functions is not so much. If we required a $:/tags/function tag, then that would be a way to export all function of a tiddler (which would cover most of my needs and could be used to ban any unwanted export of function, thus achieving my goals with a slight modification of where functions are exported.

Comments welcomed of course. I don’t pretend to be the Owner of the Truth.

I am not sure what you assume is correct;

\procedure procname()
   \function design-mode() [{$:/config/design-mode}]
body of procedure
\end procname
  • This is a

in the above case the design-mode function is only available to the procedure procname.

Rather than tag the tiddler containing the definition with a global/macro tag you can import it where you want this definition to be used \import [[my proc definition]]

You can encapsulate one function (read filter) inside another function but you must use the filter syntax.

\function funcname(value)  [subfilter<otherfunction>addprefix[pre-]]

Tagging tiddlers with $:/tags/Global and $:/tags/Macro is used to make them global.

That’s achieved by the \import pragma at eg: $:/core/ui/PageTemplate

\import [subfilter{$:/core/config/GlobalImportFilter}]

$:/core/config/GlobalImportFilter contains the filter that makes “stuff” global.

So if you need private macros, procedures or functions, you should not tag them but instead use the \import pragma where you need it.

Also have a look at the ImportVariablesWidget() for even more granularity.

I think we do have everything needed to solve the problems described in the OP. – But be aware of the increased mental complexity that you will introduce to your code.

@TW_Tones Yes I know of the \import. But this leads to a naming difficulty. Say my foo procedure is in $:/user/myplace/macros/foo then my imported function would have their own tiddler in for instance $:/user/myplace/macros/foo/myfun which is odd because now functions are in macros directory (procedure being macros-as-they-should-have-been). If I place them in $:/user/myplace/functions/foo::myfun I can mitigate this but that’s quite a lot of visibility for something private!

Now, as for the encapsulated declaration, tonight I had the impression it was not working. After your message, I checked it again. And I found out what was breaking my code: encapsulation does work but only if declared inner function are one liner. See below.

\procedure notOK()
\function good() [[good]]
...
\end

procedure broken()
\function bad()
  [[bad]]
\end
...
\end

my real-life function was:

\function .firstLevel(depth)
  [all[]]
 :filter[{!!partnum}split[.]count[]match<depth>]
\end

I like to have only one filter run per line.

I am afraid I dont follow the first paragraph in your reply.

  • You remain in control of all the naming here.
  • Nothing is truely private in tiddlywiki but if you want some security by obscurity I have some methods.

Sorry I should of added when you do this, define multiline anything inside another you need to close the end; However I tend to keep all functions as single line.

\function good() [[good]]
...
\end good

Here ^^^^

And for consistency lose the whole procedure \end notOK

When nesting we need to indicate which end belongs to which pragma or the parser can not tell what you intended.

1 Like

Wrong.

Nested definitions need a “named” \end xxx marker. That’s true for macros, procedures and functions.

\procedure works()
\function good()
  [[good]]
\end good
<<good>>
\end

<<works>>

As always: Improvements / pull requests for the documentation are very welcome.
-m

@pmario You wrote:

As always: Improvements / pull requests for the documentation are very welcome.

The problem lays in the PR mechanism for updating docs. Docs are not code. We should not use PR but for code or config setup. Definitely not for doc.

It is not that it’s a technical bad idea, but that’s a question of “mood”. Writing or correcting doc is rather a creative process (sometimes a bit dull too…). You would want a straightforward mechanism. You have an idea, you write it down somewhere on the web immediately to fix what you think is broken and this should automatically produce a call for acceptation to the doc owners. If granted, the changes should then be incorporated in the online doc and in the git repository at the next push/release by the project owner.

I may be wrong, but I don’t feel comfortable with this PR mechanism for docs. Perhaps we should have a tutorial on that matter. It could be a boost for the community.

1 Like

I have remarked that in a tiddler tagged $:/tags/Macro functions are only exported if there is a least one \procedure or \define.

Isn’t it a signal that we’d better have tag $:/tags/Function to export macro? Or does it means that if we don’t export function defined in the macro/procedure tiddler, this macro/procedure won’t be able to call them? But if my previous tag was adopted, it would not be a problem. It would also allow to have one tiddler per exported function or procedure which is the way I like to organize my code.

That is not correct. Perhaps there was some other problem preventing the function from being parsed.

Also notethat we already have $:/tags/Global which is semantically appropriate for all definitions.

Thank you @jeremyruston Oh yes you’re right! I can’t see what was wrong with my original test code, but I succeeded a new test proving me that your point is valid (of course!).

Why have specialized export tags when you have a global one?