# Reference

Plugins.ConfigurationType
abstract type Configuration <: ContextStage end

Stage that potentially changes the behavior of the program without evaluating previously unknown code.

source
Plugins.ContextStageType
abstract type ContextStage <: Stage end

Stage technique that generates a new stage context type, which can be used for dispatching or in @generated functions. Assembled types may be regenerated during a ContextStage, depending on TODO.

A context stage does not create a new world but run in the same world than the previous stage.

source
Plugins.EvalStageType
abstract type EvalStage <: Stage end

Stage technique that runs in a new world and generates a new stage context type.

source
Plugins.FieldSpecType
FieldSpec(name, type::Type, constructor::Union{Function, DataType} = type)

Field specification for plugin-assembled types.

Note that every field of an assembled type will be constructed with the same arguments. Possibly The constructor will be called when the system

source
Plugins.HookListType
HookList{TNext, THandler, TPlugin}

Provides fast, inlinable call to the implementations of a specific hook.

You can get a HookList by calling hooklist() directly, or using hooks().

The HookList can be called with arbitrary number of extra arguments. If any of the plugins referenced in the list fails to handle the extra arguments, the call will raise a MethodError

source
Plugins.ImmutableStructType
struct ImmutableStruct <: TemplateStyle end

Plugin-assembled types marked as ImmutableStruct will be generated as a struct.

source
Plugins.InitializationType
abstract type Initialization <: EvalStage end

A classical Stage that runs before the normal operation of the program.

Multiple initialization stages may run, but only before the first non-Initialization stage.

source
Plugins.MutableStructType
struct MutableStruct <: TemplateStyle end

Plugin-assembled types marked as MutableStruct will be generated as a mutable struct.

source
Plugins.OptimizationType
abstract type Optimization <: ContextStage end

Stage that does not change the functional behavior of the program, only its performance characteristics.

source
Plugins.PluginStackType
PluginStack(plugins, hookfns = [])

Manages the plugins loaded into an application.

It provides fast access to the plugins by symbol, e.g. pluginstack[:logger]. Collection methods and iteration interface are implemented.

The pluginstack is created from a list of plugins, and optionally a list of hook functions. If hook functions are provided, the hooks() function can be called to

source
Plugins.StageType
abstract type Stage end

Base type that represents a step of iterated staging.

Iterated staging allows the program to repeatedly self-recompile its parts. The first iterations are

Stage is the root of a layered type hierarchy:

• Direct subtypes of it (ContextStage, EvalStage) represent staging

techniques available in Julia.

• Downstream subtypes represent means of staging:

Initialization, Extension, Optimization, Configuration.

source
Plugins.TemplateStyleMethod
TemplateStyle(::Type) = MutableStruct()

Trait to select the template used for plugin-assembled types

Use MutableStruct (default), ImmutableStruct, or subtype it when you want to create your own template.

#Examples

Assembling immutable structs:

abstract type DebugInfo end
Plugins.TemplateStyle(::Type{DebugInfo}) = Plugins.ImmutableStruct()

Defining your own template (see also typedef ):

struct CustomTemplate <: Plugins.TemplateStyle end
Plugins.TemplateStyle(::Type{State}) = CustomTemplate()
source
Plugins.customfieldMethod
customfield(plugin::Plugin, abstract_type::Type, args...) = nothing

Provide field specifications to plugin-assembled types.

Using this lifecycle hook the system can define custom plugin-assembled types (typically structs) based on field specifications provided by plugins. E.g. an error type can be extended with debug information.

A plugin can provide zero or one field to every assembled type. To provide a field, return a FieldSpec.

The assembled type will be a subtype of abstract_type. To allow differently configured systems to run in the same Julia session, new types may be assembled for every instance of the system.

Metaprogramming may make you unhappy

Although plugin-assmebled types are designed to help doing metaprogramming in a controlled fashion, it is usually better to use non-meta solutions instead. E.g. Store plugin state inside the plugin, collect data from multiple plugins using lifecycle hooks, etc.

source
Plugins.customtypeFunction
customtype(stack::PluginStack, typename::Symbol, abstract_type::Type, target_module::Module = Main; unique_name = true)

Assemble a type with fields provided by the plugins in stack.

abstract_type will be the supertype of the assembled type.

If unique_name == true, then typename will be suffixed with a structure-dependent id. The id is generated as a hash of the evaluated expression (with the :TYPE_NAME placeholder used instead of the name), meaning that for the same id will be generated for a given type when the same plugins with the same source code are loaded.

Examples

Assembling a type AppStateImpl <: AppState and parametrizing the app with it.

abstract type AppState end

mutable struct CustomFieldsApp{TCustomState}
state::TCustomState
function CustomFieldsApp(plugins, hookfns, stateargs...)
stack = PluginStack(plugins, hookfns)
state_type = customtype(stack, :AppStateImpl, AppState)
return new{state_type}(Base.invokelatest(state_type, stateargs...))
end
end
The need for invokelatest

We need to use invokelatest to instantiate a newly generated type. To use the generated type normally, first you have to allow control flow to go to the top-level scope after the type was generated. See also the docs

Antipattern

Assembling state types is an antipattern, because plugins can have their own state. (This may provide better performance in a few cases though) Assembled types can make your code less readable, use them sparingly!

source
Plugins.depsMethod
Plugins.deps(::Type{T}) = Type[] # where T is your plugin type

The plugin type must have a constructor accepting an instance of every of their dependencies.

Examples

abstract type InterfaceLeft end struct ImplLeft <: InterfaceLeft end

abstract type InterfaceRight end struct ImplRight <: InterfaceRight end

Plugins.deps(::Type{ImplLeft}) = [ImplRight]

source
Plugins.enter_stageMethod
enter_stage(plugin::Plugin, stage::Stage, args...)

Lifecycle hook marking the start of the next stage.

Types are reasssembled at this point. If stage isa EvalStage, then the world is already updated. (execution reached toplevel)

source
Plugins.hook_cacheMethod
hook_cache(stack::PluginStack, hookfns)
hook_cache(plugins, hookfns)

Create a cache of HookLists for a PluginStack or from lists of plugins and hook functions.

Returns a NamedTuple with an entry for every handler.

Examples

cache = hook_cache([Plugin1(), Plugin2()], [hook1, hook2])
cache.hook1()
source
Plugins.hooklistMethod
function hooklist(plugins, hookfn)

Create a HookList which allows fast, inlinable call to the merged implementations of hookfn by the given plugins.

A plugin of type TPlugin found in plugins will be referenced in the resulting HookList if there is a method that matches the following signature: hookfn(::TPlugin, ...)

source
Plugins.hooksFunction
hooks(app)
hooks(pluginstack::PluginStack)

Create or get a hook cache for stack.

The first form can be used when pluginstack is stored in app.plugins (the recommended pattern).

When this function is called first time on a PluginStack, the hooks cache will be created by calling hook_cache(), and stored in pluginstack for quick access later.

source
Plugins.prepare_stageMethod
prepare_stage(plugin::Plugin, stage::Stage)

Lifecycle hook to prepare the plugin for the next stage. If the stage is an EvalStage and the plugin needs to evaluate code, this is the point to do it.

source
Plugins.request_stageMethod
request_stage(plugin::Plugin, args...)::Stage

Request a new stage iteration by returning a Stage representing it.

This lifecycle hook will be called repeatedly to ask plugins their wish to stage. If a plugin returns a Stage instance and the request is accepted, the stage will start immediately.

If more than one plugins ask for staging, their request will be merged if possible and only one stage will run. If the stages are incompatible, meaning that different sets of plugins handle the prepeare hook of the stages, then only a compatible subset of them will run.

Plugins should continue requesting staging until their wish gets fulfilled.

source
Plugins.setup!Method
setup!(plugin, deps, args...)

Initialize the plugin with the given dependencies and arguments (e.g. shared state).

This lifecycle hook will be called when the application loads a plugin. Plugins.jl does not (yet) helps with this, application developers should do it manually, right after the PluginStack was created, before the hook_cache() call.

source
Plugins.shutdown!Method
shutdown!(plugin, args...)

Shut down the plugin.

This lifecycle hook will be called when the application unloads a plugin, e.g. before the application exits. Plugins.jl does not (yet) helps with this, application developers should do it manually.

source
Plugins.symbolMethod
symbol(plugin)

Return the per-PluginStack unique Symbol of this plugin if it exports a "late-bind" runtime API to other plugins.

source
Plugins.typedefFunction
typedef(templatestyle, spec::TypeSpec)::Expr`

Return an expression defining a type.