Call Graph and Neighbourhood
Call Graph reads who calls a function or method and what it calls in turn; Neighbourhood reads a construct's own structural neighbours - what it extends, implements, composes or references - radiating out by hop. Here deliverAll() (delivery.ek9) calls describeNotification() and the dispatcher route(), both declared in notifications.ek9 - so the call graph crosses the project's two files. To play it in the IDE: Help > Lessons > Understanding a codebase…, or ek9 -ide -lesson call-graph.
Start from
The code the lesson starts from: copy it into a file of your own and follow the steps.
notifications.ek9
#!ek9 <!- The shared project for the 'type-hierarchy' and 'call-graph' Analyse lessons: a small abstract hierarchy (Notification), a trait one subtype implements (Loggable), a dispatcher (NotificationRouter) with handlers for two of the three subtypes - the third falls back to the entry point's own body - and a function that reads any Notification polymorphically, so Type Hierarchy, Dispatcher, Call Graph and Neighbourhood each have something real to show. -!> defines module lesson.relationships defines trait Loggable logTag() as pure <- rtn as String: "LOG" defines class Notification as abstract summary() as abstract <- rtn as String? default operator ? EmailNotification extends Notification with trait of Loggable override summary() <- rtn as String: `${logTag()}: emailing the customer` default operator ? SmsNotification extends Notification override summary() <- rtn as String: "texting the customer" default operator ? PushNotification extends Notification override summary() <- rtn as String: "pushing to the app" default operator ? NotificationRouter route() as dispatcher -> n as Notification <- rtn as String: "unrouted" private route() -> n as EmailNotification <- rtn as String: `sending by email: ${n.summary()}` private route() -> n as SmsNotification <- rtn as String: `sending by sms: ${n.summary()}` defines function describeNotification() -> n as Notification <- rtn as String: `notice: ${n.summary()}` //EOF
delivery.ek9
#!ek9 <!- The second file of the shared 'relationships' project: functions that call across both files - buildNotifications constructs the three subtypes, deliverAll calls describeNotification (notifications.ek9) and NotificationRouter's dispatcher for each one. -!> defines module lesson.relationships defines function buildNotifications() <- rtn as List of Notification: List() of Notification rtn += EmailNotification() rtn += SmsNotification() rtn += PushNotification() deliverAll() -> notifications as List of Notification stdout <- Stdout() router <- NotificationRouter() for n in notifications stdout.println(describeNotification(n)) stdout.println(router.route(n)) defines program Deliver() deliverAll(buildNotifications()) //EOF
Step 1: Who deliverAll() calls, and who calls it
Open delivery.ek9, put the caret on deliverAll(), then choose Analyse > Call Graph.
Step 2: Reading the diagram
deliverAll sits in a rose "you are here" box. Above it, Callers (1): Deliver, the program that calls it. Below it, Calls (5), each bordered in its kind's colour from the key at the top: Stdout() and NotificationRouter() teal - constructors; println mauve - a method; describeNotification green - a function; and below the pane's edge - scroll down to it - NotificationRouter.route in yellow, the dispatcher, with the handler each type reaches beneath it. A dashed border would mark a polymorphic call - one that resolves to more than one target.
Step 3: A construct's own neighbourhood
Open notifications.ek9, put the caret on EmailNotification, then choose Analyse > Neighbourhood.
Step 4: Reading the edges
Neighbourhood of EmailNotification: 9 constructs and 10 edges, two hops out (Hops 2, Dir both), with EmailNotification in the bold box at the centre. Beside it Loggable, the trait it implements, and around it the functions and the router that use it - describeNotification, deliverAll and NotificationRouter; Notification, the class it extends, and buildNotifications sit further out - scroll down to them. The Kinds row picks which links count: the structural four (extends, implements, composes, references) are ticked; calls, injects and dispatches are not - tick one, or change Hops, and the picture redraws.
The result
That is Call Graph and Neighbourhood: deliverAll() (delivery.ek9) calls describeNotification() and route() - both declared in notifications.ek9, so the graph crosses the project's two files without being told to - and EmailNotification's neighbourhood showed what it extends and implements and what uses it, two hops out by the structural kinds. Analyse > Call Graph (⇧⌘C) and Analyse > Neighbourhood (⇧⌘B) both read the caret's own construct; AI assistants get the same data from ek9_query_call_graph and ek9_query_construct_neighbourhood.
Where this lesson comes from
- For AI assistants - the MCP tool
ek9_query_call_graph,ek9_query_construct_neighbourhood.




