Records satisfying implicit interface w/o re-implementing
Asked Answered
T

1

5

Seeing a record already has a public Getter/(Setter) for its fields, is it possible to specify that a record satisfies a matching interface without re-implementing it?

For example:

type IText = 
    abstract text : string with get,set

type TextRec = 
{ 
mutable text : string
}

Now seeing the Record already implements this interface implicitly, I'd like to put an "inherit IText" or "interface IText" (with no body) on the record, but it appears I can't do that. As it is, I believe I have to re-implement the interface by adding this to the record:

interface IText with
    member this.text
        with get()  = this.text
        and set(v)  = this.text <- v

thanks

Tyson answered 10/9, 2014 at 16:20 Comment(5)
That's correct. There is no implicit interface implementation in F#.Holography
I'm not asking about implicit implementation of interfaces, which (at least as its talked about as not in F#) is about whether you need to name the interface at the call-site. I'm asking about explicitly marking the compiler-provided protocol as implementing an interface without re-implementing it, which is different. I understand even if I could do what I'm asking, I would still need to check the type and use a downcast.Tyson
I think what @Holography meant is that there is no automatic interface implementation in F# like in your question. I think I saw a proposal for this feature once though...Lawler
To be clear, there is already an implementation of this particular interface here, by virtue of it's being a Record with a mutable field - I just wanted to tell the compiler that that the existing implementation is compatible with my interface. Although, for example, an "interface IText" with no member body would make sense, I was pretty sure I couldn't do this - just making sure I wasn't missing edge-case syntax somewhere. Thanks...Tyson
There's no such thing as implicit or explicit interface implementation in c#. The proper terms are implicit or explicit interface member implementation. In c#, a type cannot implement an interface unless explicitly declared, though any number of the interface's members may be implemented implicitly. In f#, as others have noted, implicit interface member implementation is not supported.Yearround
M
8

F# currently does not support implicit interface implementations (not even for classes), but it is one of the frequently requested features, so it might happen in the future. I certainly see why this would be useful.

I don't think there is any good workaround for this - the best option is probably to write the additional piece of code needed to implement the interface.

If you wanted to be adventurous, you could try writing a "wrapping" function that creates an interface implementation from a value that provides the required members. Using static member constraints, you can require the members to be there (without actually implementing the interface):

type IText = 
  abstract Text : string with get, set

let inline wrap (a:^T) =
  { new IText with
      member x.Text 
        with get() = (^T : (member Text : string) (a)) 
        and set(v) = (^T : (member set_Text : string -> unit) (a, v)) }

Static member constraints (used in the implementation of wrap) are mainly useful for generic numerical computations, so this is a bit of a stretch (and certainly an advanced F# feature), but it does the trick:

type Rect = { mutable Text : string }
let i = wrap { Text = "Hi" }
i.Text <- i.Text + " there!"
Monastic answered 10/9, 2014 at 20:46 Comment(3)
Thanks for the reply, Tomas. I haven't been lurking here for a while and I'm happy to see that you're still answering questions... I'd already gone down the static duck typing route as an option, but thought maybe I'd missed something, so I was just checking.Tyson
[Arg - keep hitting Enter and posting early...] I wonder if it's worth using a thread-local singleton for these wrappers so that they don't create garbage on every wrapping. (I guess in this simple case it can be a global, shared wrapper.) Of course, what I really want is F#-in-F# meta-programming calling the optimizing compiler rather than Eval with nice syntactic macros so we can add whatever features we want :)Tyson
Sorry - my last comment conflating your wrapper and my inline helper version that didn't hold a reference - obviously you need to hold on to your target for the duration. Need coffee - sadly too late for that...Tyson

© 2022 - 2024 — McMap. All rights reserved.