How do programs connect to applications for dependency injection?

← Dependency Injection · Ref: Q231

Programs declare their dependency source using 'with application of AppName'. This links the program to a specific application definition that provides its injected dependencies.

BASIC LINKING

A program declares its application after the parameter list:

  MyProgram() with application of MyApp
    service as ServiceType!

The compiler verifies that MyApp registers a concrete ServiceType.

MULTIPLE PROGRAMS, ONE APPLICATION

Several programs can link to the same application. Each program gets its own injection of the registered components:

  ProgramA() with application of SharedApp
    svc as ServiceType!
  ProgramB() with application of SharedApp
    svc as ServiceType!

PROGRAMS WITHOUT DI

Programs that do not need injection simply omit 'with application of':

  SimpleProg()
    stdout <- Stdout()
    stdout.println("No DI needed")

Stdout is a built-in, not an injected component.

WHEN TO USE APPLICATIONS

Use 'with application of' when your program needs components, services, or other registered dependencies. Programs that only use built-in types and local variables do not need an application.

See Q111 for component basics. See Q117 for singleton lifecycle. See Q227 for compile-time validation.

See Q326 for @Bean equivalent. See Q327 for Spring Boot comparison.

See Q672 for program-application link details.

Example

defines module qa.di.program.app

  defines component

    Greeter as abstract
      greet() as abstract
        -> name as String
        <- message as String?

      default operator ?

    FriendlyGreeter is Greeter
      override greet()
        -> name as String
        <- message as String: `Hello, ${name}!`

      default operator ?

  defines application

    SharedApp
      register FriendlyGreeter() as Greeter

  defines program

    // === PROGRAM WITH APPLICATION: has injection ===

    ProgramWithDI() with application of SharedApp
      stdout <- Stdout()

      greeter as Greeter!
      stdout.println(greeter.greet("Alice"))

    // === SECOND PROGRAM: same application ===

    AnotherProgram() with application of SharedApp
      stdout <- Stdout()

      greeter as Greeter!
      stdout.println(greeter.greet("Bob"))

    // === PROGRAM WITHOUT APPLICATION: no injection needed ===

    StandaloneProgram()
      stdout <- Stdout()

      // No injection fields, no application needed
      stdout.println("Running without DI")

Common mistakes

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

stdout.println(greeter.greet("Alice").toUpperCase())

Correct:

stdout.println(greeter.greet("Alice"))

E08150 — Injection fields must use abstract component types. Injecting the concrete FriendlyGreeter directly bypasses the abstraction that enables substitution. See ek9 -h E08150 for details.

Incorrect:

greeter as FriendlyGreeter!

Correct:

greeter as Greeter!
Other ways to ask this
  • What does 'with application of' mean in EK9?
  • Can multiple programs share one application in EK9?
  • Do all EK9 programs need an application?
  • How do I use the application construct in EK9?

Coming from another language?

Java Spring: @SpringBootApplication auto-scans, no explicit linking per class. Guice: modules bound to Injector, no per-program declaration. .NET: IServiceCollection configured in Startup, all classes share one container. Python: no language-level DI linking. Go: no language-level DI. Rust: no language-level DI. EK9: explicit 'with application of' per program, multiple programs can share one application, programs without DI omit the clause entirely.

Keywords: program, construct, application, injection, link, inject, defines, wiring, migrate, share, declare, connect