Skip to content

Generated Code

The Effects module generates plain .NET artifacts — interfaces, classes, and DI registrations — that wire your services together without requiring LanguageExt at the infrastructure layer.

Capability Interfaces

For each target type, the generator emits an IHas* interface:

public interface IHasEmailService
{
    public IEmailService EmailService { get; }
}

The runtime implements this interface, and effect methods use it as a generic constraint (where RT : IHasEmailService) so they can resolve the dependency from the runtime.

Effect Methods

For each method on the target interface, the generator emits a static Eff<RT, A> method that resolves the service from the runtime and calls the underlying method:

public static class EmailEffects
{
    public static class EmailService
    {
        public static Eff<RT, Unit> SendAsync<RT>(string to, string subject, string body)
            where RT : IHasEmailService => ...

        public static Eff<RT, bool> ValidateAsync<RT>(string email)
            where RT : IHasEmailService => ...
    }
}

When Instrumented = true (the default), each method is wrapped with .WithActivity() for automatic OpenTelemetry tracing.

Naming Convention

The generated code follows a consistent naming pattern derived from your declarations:

You Write Generated Outer Class Generated Nested Class Capability Interface
[EffectsModule(typeof(IEmailService))] on EmailEffects EmailEffects EmailService (strips I) IHasEmailService (strips I, adds IHas)
[EffectsModule(typeof(IClock))] on ClockModule ClockModule Clock IHasClock
[EffectsModule(typeof(IPaymentGateway))] on PaymentEffects PaymentEffects PaymentGateway IHasPaymentGateway

Call pattern: OuterClass.NestedClass.Method<RT>()

// Full qualification
EmailEffects.EmailService.SendAsync<AppRuntime>(to, subject, body)

// With 'using static EmailEffects':
EmailService.SendAsync<AppRuntime>(to, subject, body)

Why the nested class?

The nested class groups all methods from one interface. An [EffectsModule] can wrap multiple interfaces (e.g., NotifyModule wraps both INotificationChannel and INotificationStore), so each gets its own nested class: NotifyModule.NotificationChannel.* and NotifyModule.NotificationStore.*.

Runtime and Bootstrapper

The runtime class, DI bootstrapper, OpenTelemetry setup, and RuntimeOptions are documented on the Runtime page.