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:

  defines program
    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:

  defines program
    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!
      stdout.println(greeter.greet("Alice"))

Correct:

greeter as Greeter!
      stdout.println(greeter.greet("Alice"))
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: connect, program, construct, application, injection, link, inject, defines, wiring, migrate, share, declare