Wrong macro called

Some time ago, I asked about what macro was called. Specificcally, if I have a macre fubar in the present tiddler (not tagged $:/tags/Macros) but also elsewhere in other macro tiddlers (tiddlers tagged $:/tags/Macros), I was told the local one would be called. This I never got in fault so far.

But if the current tiddler is also tagged $:/tags/Macros then the fubar macro to be called can be one on another tiddler! This is indeed always the case in one of my project.

The point is, we cannot have private macro, callable only from the current macro tiddlers, and that’s a pity. It can transform working code into deadly traps. As of now, simple would-be-private macros have to be named with very specific name. In my case, these macro are marshaling and reverse-marshaling macros for GUI update of data. All screens (tiddlers for editions) have the same.

If you tag a tiddler $:/tags/Macros, you instruct the system to make all your macros, that are contained in that tiddler to be global. Doing so, means you know, that you need to have unique macro names.

One core feature of TW is, that it has a mechanism, that allows plugins to overwrite core shadow tiddlers. It allows users to overwrite plugin tiddlers. … And so on. … In the end: User content wins.

If the user decides to have global macros with the same name, … The last one wins. → That’s a feature. Plugins use this mechanism all the time.

So if you tag 2 tiddlers with $:/tags/Macros you can decide which tiddler is evaluated as the last one. … The last one wins. … It’s all your decision.

If you use the following code, you get a draggable list of all your global macros. You can drag & drop sort the order, how they are evaluated. … The last one wins!

<<list-tagged-draggable "$:/tags/Macro">>

If you don’t want to have all your macros to be global, use the \import [[filter]] pragma. … It allows you to define the tiddler, where your “private” macros come from. … private macros can have the same name. … The import pragma can be compared to the “#include” command of dot-h header files in C.

That’s wrong. You can do whatever you want. … It has been your decision.

Did you check for typos in your “local” macro definitions?

@pmario Yes I checked for typos. I got a lot of checks before discovering that feature.

Thank you for your explanation. This is a feature. IMO it would need to be emphasized in the docs. Hum… I have a lot of improvements to propose. I must/shall begin proposing this kind of stuff.

As for \import, it had passed below my radar and I was blissfully ignorant of it.

Thank you for the <<list-tagged-draggable>> macro too. So many things to know and manage in tiddlywiki! I won’t use it for managing macros priorities as I think any priority should me made explicit in code and not in masked metadata. But I could have a use of the mechanism for yet to happen needs. I prefer go the importing way instead if I can use it nicely.

The official doc about \import is rather short:

\import <filter-expression>
New in: 5.1.18 for importing macro definitions from tiddlers identified by a filter expression

So I did some experiments. What I found out:

  • you can’t import within $:/tags/Macros tagged tiddlers. The tiddler would be totally useless. You can’t have proper private macros by this trick.
  • only normal tiddlers can import. If my tiddler import the tiddler which has the macro that the macro it shall call needs’ then this will function. But this is not the outer world thatt should decide what the private macro will be so this is not an answer to my need.

what is needed is that $:/tags/Macros tagged tiddlers can import their own tiddlers and be glad with it, and that the macros thus important are known by the importer but not by any other tiddlers (except those that would import itself or the pseudo-private macros tiddler it imported itself, but these cases would not qualify as normal cases).

Is there hope along this way?

Going back to my painful naming of macros…

There are three ways to import macros:

  1. \import SomeTiddler
    at the beginning of the tiddler. The scope of the imported definitions is the entire tiddler.

  2. \import SomeTiddler
    at the beginning of a macro definition. The scope of the imported definitions is the macro definition in which the \import occurs.

\define myMacro(...)
\import SomeTiddler
... rest of macro content goes here...
\end
  1. Use the <$importvariables filter="[[SomeTiddler]]">...</$importvariables> widget surrounding some specific macro content. The scope of the imported definitions is restricted to only the enclosed content.
\define myMacro(...)
... some macro content goes here...
<$importvariables filter="SomeTiddler">
... dependent macro content goes here...
</$importvariables>
... more macro content goes here...
\end

Note that in my examples, I show importing a single tiddler with a specified literal title ([[SomeTiddler]]). However, you can also import a whole set of tiddlers all at once by using a filter expression; e.g.,

  • \import [prefix[MyPrivateMacros]]
    or
  • <$importvariables filter="[prefix[MyPrivateMacros]]">...</$importvariables>

enjoy,
-e

3 Likes

Wahooo @EricShulman many thanks! That’s exactly what I need. I’ve just tested it. It rocks!!!

I’d like to do this in a macro tiddler called //fu//:

\define outer()
\import [all[current]]addsuffix[/bar]]
just <<inner>>
\end

with tiddler //bar// like this:

\define inner() great

calling outer from a third tiddler should write //just great// but of course it just print //just// because the import clause is interpreted in the context of the third tiddler and not in the context of the //fu// tiddler. Is there a way to specify the source code tiddler within a filter? Actually, to make outer work, I have to explicitly import fu/bar. An other valid possibility would be to import `./bar’ which would probably be the most readable solution.

I’m asking that because I don’t think it clever that defining //outer// need requiring to know what is the name of the tiddler where it is defined.