Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

104
Views
Implementing an interface with a generic parameter on a F# record

I'm trying to implement the an Microsoft.Extensions.Logging.ILogger (copied below for brevity) on a F# Record

using System;

namespace Microsoft.Extensions.Logging
{
    public interface ILogger
    {
        void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter);
        bool IsEnabled(LogLevel logLevel);
        IDisposable BeginScope<TState>(TState state);
    }
}

This is the record implementation.

  type ILoggerRcd<'TState> = 
    {
      BeginScope : 'TState -> IDisposable
      IsEnabled : LogLevel -> bool
      Log : LogLevel * EventId * 'TState * exn * Func<'TState,exn,string> -> unit
    }
    interface ILogger with
          override this.BeginScope(state : 'TState): IDisposable = 
              this.BeginScope (state)
          override this.IsEnabled(logLevel: LogLevel): bool = 
              this.IsEnabled logLevel
          override this.Log(logLevel: LogLevel, eventId: EventId, state : 'TState, ``exception``: exn, formatter: Func<'TState,exn,string>): unit = 
              this.Log(logLevel, eventId, state, ``exception``, formatter)

However, I'm getting this error on BeginScope: One or more of the explicit class or function type variables for this binding could not be generalized, because they were constrained to other types.

And this error on Log: The generic member 'Log' has been used at a non-uniform instantiation prior to this program point. Consider reordering the members so this member occurs first. Alternatively, specify the full type of the member explicitly, including argument types, return type and any additional generic parameters and constraints.

I've read through a few issues on fsharp compiler itself but nothing seems to be exactly this case I'm hitting. Is this something that can be done?

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

The ILogger interface requires that you can log objects of any type, but you're trying to log only those of type 'TState.

Take the signature of BeginScope:

IDisposable BeginScope<TState>(TState state);

See that <TState> bit there? That's a generic parameter. This signature means that every time anybody calls this method, they get to choose a type TState to use with that call.

Again: the caller chooses the generic type, not the implementer.

For example:

let l : ILogger = ...
l.BeginScope 42   // TState = int
l.BeginScope true // TState = bool

This means that your implementation of BeginScope has to be able to work with any type, not just the type with which your ILoggerRcd record was created.

over 4 years ago · Santiago Trujillo Report

0

The problem here is that you are trying to constrain ILogger's 'TState to match the ILoggerRcd's 'TState, but it's not your choice to do that.

To see this, note that a caller of ILogger.BeginScope can pass an int state on one call, and then a string state on another call to the same ILogger instance. Your implementation attempts to prevent this, hence the compiler errors.

The only way I can see around this is to use generic methods in your type instead of a record of functions. I don't think there's any way to do what you want using vanilla F# records.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!