ek9_query_dispatchers
Answers first: routing[] - per dispatcher method its dispatchOn type, typesWithOwnHandler, typesUsingInheritedHandler (served by a supertype's handler) and typesFallingBack (to the dispatchOn entry point's own body), with routingCovers when the lists are whole - then the full dispatcherMethods[] with resolutionTable; on a sealed type, allowedSubtypes[]. Do not read the class and simulate it.
When to use it
How does a dispatcher method route - which subtypes have their OWN handler and which fall back to the base handler - one call with symbol:'<dispatcher class>'. No file needed; on a sealed type, its allowed subtypes.
When not to use it
- General supertype/subtype inheritance graph (not dispatch-specific) - use
ek9_query_type_hierarchy. - Caller/callee relationships of a method rather than the dispatch table - use
ek9_query_call_graph. - Structural info (fields, methods, modifiers) or the callable member list of a type - use
ek9_query_construct(structure) orek9_query_effective_api(callable surface). - Which dispatchers reference a sealed type (cross-reference not yet emitted here) - use
ek9_query_referenceson the sealed type.
Details
Auto-detected (no 'mode' parameter): routing[] is present for a dispatcher, allowedSubtypes[] for a sealed type, and a type that is neither returns dispatcher:'not_applicable' with a message (or 'not_found' when there is no enclosing type at the anchor). Dispatcher shape: dispatcherMethods[] + dispatcherMethodCount - drawn from the FULL inheritance chain, so an entry point or handler declared in a supertype is included - each method with signature, pure, dispatchType(+Fqn), allowedSubtypes[] when the dispatch parameter type is sealed, and handlers[] (handlesType and routedTypes per handler), plus top-level sealedTypeDispatched (the FQ sealed supertype handled). ROUTING (present when the workspace is compiled): resolutionTable[] has one row per concrete type that can arrive - typeName, typeGenus, category DIRECT (handler names this exact type) / INHERITED (won via a supertype, with resolvedVia and cost) / ENTRY (the dispatch type itself, when it is concrete - served by the entry point, not a gap) / FALLBACK (no handler; the entry point's own body runs) - plus totalTypes, directCount and inheritedCount. dispatchUniverse says how far to trust the gap analysis: 'sealed' (closed by the compiler, gaps provable), 'hierarchy' (a trait / abstract class / abstract function base - gaps real but a snapshot, since another implementor may be declared later), or 'open' (an Any base). For sealed and hierarchy you also get fallbackCount, unhandledTypes[] (the FALLBACK rows - routing[].typesFallingBack is the same list) and exhaustive, and routing[].routingCovers says the lists are whole. For 'open' those are DELIBERATELY ABSENT and a note explains why: an Any base admits every type in the program and every type not yet written, so 'types you did not handle' has no fixed answer and a fallbackCount of 0 would read as a false all-clear. Sealed shape: allowedSubtypes[] (simple-name strings) + subtypeCount. Note a class is reported as a dispatcher only when it has a NON-OPERATOR entry point: argument-taking operators such as '==' are marked as dispatchers internally so they resolve on the actual type, and that is not a user-level dispatcher.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
among | array of string | Names to answer FOR: 'which of these ...' - the name lists shrink to these and amongUnmatched names the ones that are not in the answer. Bare names, 'mod::Type' or 'Type.member'; a MODULE name stands for every construct in it ('which in scale.m07 do not ...' = amongUnmatched). | |
column | integer | 0-based char offset of the target identifier on 'line' (an IDE cursor). OMIT it and pass symbol:'<name>' instead, or omit both and the first identifier on the line is taken (right for a declaration line). Reuse a column from ek9_inspect_symbol_at_cursor verbatim. | |
file | string | The EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site. | |
line | integer | 1-based line of the declaration or a reference - OMIT it and pass symbol:'<name>' to let the tool find the line (a model counting lines in a file miscounts); if you do count, use ek9_read_file(lineNumbers:true). | |
symbol | string | A construct NAME alone ('Shape', 'sample.deps.core::Validator') - no file needed, the tool finds it workspace-wide; or, with file (+ line), the identifier you mean there. |
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 4 recorded are shown.
Not a dispatcher status
Request
{
"symbol" : "Circle"
}
Response
{
"fullyQualifiedName" : "probe.wire::Circle",
"genus" : "CLASS",
"meta" : {
"serverMs" : "<timing>"
},
"note" : "Type is not sealed and not a dispatcher",
"status" : "not-applicable",
"type" : "Circle",
"typeLine" : 10,
"typeSourceFile" : "wire.ek9"
}
Dispatchers shape
Request
{
"file" : "MyRecord.ek9",
"line" : 5
}
Response
{
"fullyQualifiedName" : "com.example::MyRecord",
"genus" : "RECORD",
"meta" : {
"serverMs" : "<timing>"
},
"note" : "Type is neither a dispatcher nor a sealed type",
"status" : "not-applicable",
"type" : "MyRecord",
"typeLine" : 5,
"typeSourceFile" : "MyRecord.ek9"
}
Any base routing
Request
{
"symbol" : "AnyRenderer"
}
Response
{
"dispatcherMethodCount" : 1,
"dispatcherMethods" : [ {
"directCount" : 1,
"dispatchType" : "Any",
"dispatchTypeFqn" : "org.ek9.lang::Any",
"dispatchTypeLine" : 6,
"dispatchTypeSourceFile" : "org-ek9-lang.ek9",
"dispatchUniverse" : "open",
"entryLine" : 10,
"entrySourceFile" : "anyBase.ek9",
"handlers" : [ {
"handlerLine" : 14,
"handlerSourceFile" : "anyBase.ek9",
"handlesType" : "Circle",
"handlesTypeFqn" : "probe.anybase::Circle",
"handlesTypeLine" : 6,
"handlesTypeSourceFile" : "anyBase.ek9",
"name" : "render",
"routedTypes" : [ "Circle" ]
} ],
"inheritedCount" : 0,
"method" : "render",
"name" : "render",
...
Cut short here: 37 more lines. The whole recorded call.
See also
- Fixes E05260