I’m developing a Julia package that supports extensions. Currently I need to know:
Where should I store extension data locally? Store as artifacts, store in scratchspaces or somewhere else?
For the code in extensions, should I write plain code and use include (with return value so that I can better manage) or wrap code in a module?
To manage the extensions, I guess I need something like the Julia-Package system (but obviously not the real one). How can I use Pkg to manage those things (extensions may use other extensions and real packages), or should I build a system myself?
Are there any known ways (maybe design a special architecture?) to smoothly ban/disable/remove the effect of loaded code (like vscode)?
If I’m going to pre-compile the main package and extensions (for standalone software release or something else), what do I need to notice in extension-architecture design to let this process smooth?
I know there are really a lot of complicated things, but you can answer the questions one by one or simply post your thoughts. Thanks for your help~
ability extension (I may use the julia-method-feature to override or add new features for the main package) (e.g. originally I can deal with markdown, extensions can enable me to deal with bbcode, or provide more markdown parsing features like more codeblock types)
data extension (e.g. supporting more themes or more languages)
I think the weak dependencies added in Julia 1.9 can do part of the work, but yes, there are a few things I must solve myself. If I can completely control the extension thing (when to load extension, call something like ext1.initialize_setting(foo), etc) those can all be solved.
But I guess it’s not very likely to solve problem 4 if I choose to use this. But that’s not essential, only that it would be more user-friendly if it’s supported.
It sounds like what you want has potentially little to do with weak dependencies. Usually people can add external functionality to your package without any special dependency infrastructure in your package, via:
If you write generic code, people can pass new argument types to extend new behaviors.
If you write higher-order functions (that take functions as arguments), people can pass callback functions.
People can define new methods for your types, and/or new types for your methods, using multiple dispatch.
e.g. in your example of parsers, you could define some kind of AbstractParser interface for extending functionality — someone could define a new kind of parser in package X which uses your package by defining a new AbstractParser type and passing it to your functions. Users who want the new functionality would use package X with your package. Your package, on the other hand, would not need any dependency (weak or otherwise) on package X.
Well, of course I have many ways of extending, but the core problem does lie in my original questions (in this case, question 3 and question 5). Turning to the new feature for help does partly solve them.
Also note that there may be hundreds of extensions in the future and there might be something like paid extensions or what else, so I shouldn’t register them in General.