extending an object with an interface through an object expression - f#

Is it possible to decorate an object in F# with an interface using an object expression. E.g.:
type IFoo = abstract member foo : string
type IBar = abstract member bar : string
let a = { new IFoo with member x.foo = "foo" }
/// Looking for a variation on the below that does compile, the below doesn't
let b = { a with
interface IBar with
member x.Bar = "bar" }

You can't extend an object with an interface at run-time, but you could wrap it with another object:
let makeB (a: IFoo) =
{
new IFoo with
member x.foo = a.foo
interface IBar with
member x.bar = "bar"
}
let a = { new IFoo with member x.foo = "foo" }
let b = makeB a

Related

F# multiple interface implementations with object expressions

According to docs you can implement multiple interfaces with object expressions. But if you see below code :
// Define two interfaces
type IFirst =
abstract F : unit -> unit
abstract G : unit -> unit
type ISecond =
abstract H : unit -> unit
abstract J : unit -> unit
// This object expression implements both interfaces.
let implementer : IFirst =
{ new ISecond with
member this.H() = ()
member this.J() = ()
interface IFirst with
member this.F() = ()
member this.G() = () }
So casting to IFirst causes a compiler error. Why is that so?
F# does not perform implicit conversions.
When type annotating in a let binding, the type must strictly match the expression.
For example,
let value : obj = new System.Collections.Generic.List<int>()
will fail to compile, even though a List is very obviously an object.
When you write:
let implementer : IFirst = expr
The type of expr must absolutely be IFirst. There's no implicit casting like in C#.
An object expression will have its type as the abstract type implemented, so:
{ new ISecond with ... }
will be inferred to have a type of ISecond. Combine it with no-implicit casts rule, and you have a compile error.
Because IFirst and ISecond are unrelated, you could (runtime) downcast to IFirst:
let firstImplementer = implementer :?> IFirst
Another option is to make a combined interface:
type IBoth = inherit IFirst inherit ISecond
and do:
let implementer =
{
new IBoth with ...
That way you can freely (static) upcast to IFirst or ISecond.
let firstImplementer = implementer :> IFirst
let secndImplementer = implementer :> ISecond

Interface properties not getting serialized

If I defined a record that implements an interface with an additional property the interface properties are not serialized by json.net. How do I get json.net to serialize those interface properties. Here is an example
open Newtonsoft.Json
type IRecord =
abstract member id : string
type ARec = {
Name : string
} with
interface IRecord with
member this.id = this.Name
let aRec = {Name = "John"}
Both JsonConvert.SerializeObject aRec and JsonConvert.SerializeObject (aRec :> IRecord) result in {"Name":"John"} but I expected {"Name":"John"; "id":"John"}
I tried adding ShouldSerializeid to the interface but that made no difference.

Public Mutable Field in Object

Is it possible to create a simple public mutable field in F#? I'm creating a library that I will be accessing from a C# program and I need to be able to set a field from C#.
//C# Equivalent
public class MyObj
{
public int myVariable;
}
//F#
type MyObj =
//my variable here
member SomeMethod() =
myVariable <- 10
//C# Usage
MyObj obj = new MyObj();
obj.myVariable = 5;
obj.SomeMethod()
type MyObj() =
[<DefaultValue>]
val mutable myVariable : int
member this.SomeMethod() =
this.myVariable <- 10
You can leave off [<DefaultValue>] if there's no primary constructor, but this handles the more common case.
How about:
[<CLIMutable>]
type MyObj =
{ mutable myVariable : int }
member x.SomeMethod() =
x.myVariable <- x.myVariable + 10
Then you can do:
var obj = new MyObj();
obj.myVariable = 5;
obj.SomeMethod();
or
var obj = new MyObj(5);
obj.SomeMethod();

Overloading constructor without initialization

I'm writing a generic class that has two constructors: the first one initializes every field, the second (parameter-less) should not initialize anything.
The only way I found to achieve this is calling the main constructor with "empty" arguments, i.e. Guid.Empty and null. Besides not looking good functional style to my untrained eyes, this means that I have to put a a' : null constraint on the second parameter, which I don't want:
type Container<'a when 'a : null>(id : Guid, content : 'a) =
let mutable _id = id
let mutable _content = content
new() = Container<'a>(Guid.Empty, null)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
I see two ways to solve this:
use something like the default c# keyword instead of null (does such a thing exist in F#?)
use a different syntax to specify constructors and private fields (how?)
What is the best way to implement this class?
The F# analog to default is Unchecked.default<_>. It is also possible to use explicit fields which you don't initialize:
type Container<'a>() =
[<DefaultValue>]
val mutable _id : Guid
[<DefaultValue>]
val mutable _content : 'a
new (id, content) as this =
new Container<'a>() then
this._id <- id
this._content <- content
However, in general, your overall approach is somewhat unidiomatic for F#. Typically you'd use a simple record type (perhaps with a static method to create uninitialized containers, although this seems to have questionable benefit):
type 'a Container = { mutable id : Guid; mutable content : 'a } with
static member CreateEmpty() = { id = Guid.Empty; content = Unchecked.defaultof<_> }
In many situations, you could even use an immutable record type, and then use record update statements to generate new records with updated values:
type 'a Container = { id : Guid; content : 'a }
[<GeneralizableValue>]
let emptyContainer<'a> : 'a Container =
{ id = Guid.Empty;
content = Unchecked.defaultof<_> }
let someOtherContainer = { emptyContainer with content = 12 }
If the type will be used from languages other than F#, the following provides a natural interface in F#, and C#, for example.
type Container<'a>(?id : Guid, ?content : 'a) =
let orDefault value = defaultArg value Unchecked.defaultof<_>
let mutable _id = id |> orDefault
let mutable _content = content |> orDefault
new() = Container(?id = None, ?content = None)
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
If it will only be used from F#, you can omit the following constructor overloads
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
new() = Container()
because the overload accepting optional args handles both these cases equally well in F#.

F# function with polymorphic (in the OO sense) return type

Is it possible to have a function return multiple types as long as they share a common base class, without casting each return value?
For example:
[<AbstractClass>]
type A() =
abstract Do : unit -> unit
type B() =
inherit A()
override x.Do() = ()
type C() =
inherit A()
override x.Do() = ()
let getA i : A =
if i = 0 then new B() else new C() //Error: This expression was expected to have type A but here has type B
No, you have to cast:
let getA i : A =
if i = 0 then upcast new B() else upcast new C()
I believed you could use generics with constraints to define a return type of 'a when a :> SomeType but I've now got to fire up VS to check.
Edit: nope.. curses... you'll have to cast.

Resources