BinderScriptNotebook

DynamicObj

F# library supporting Dynamic Objects including inheritance in functional style.

Table of contents

DynamicObj (mutable)

DynamicObj builds on ´System.Dynamic´ but adds object inheritance.

One main use case of this library is the dynamic generation of JSON objects - especially nested objects with optional properties - aimed to be used from javascript wuith the init/style pattern:

Use it for your custom types via inheritance:

Simple inheritance pattern for DynamicObj

#r "nuget: Newtonsoft.JSON, 13.0.1"
open Newtonsoft.Json
open DynamicObj

type A() = 
    inherit DynamicObj()

    static member init
        (
            ?SomeProp: int
        ) =
            A()
            |> A.style
                (
                    ?SomeProp  = SomeProp
                )

    static member style
        (
            ?SomeProp: int
        ) =
            fun (a:A) ->

                SomeProp |> DynObj.setValueOpt a "some_prop"

                a

You can use the DynObj.print function to look at the dynamic members of the object:

let aformat = A.init(42) |> DynObj.format
"?some_prop: 42"

And this is how the serialized JSON looks like:

let aSerialized =
    A.init(42)
    |> JsonConvert.SerializeObject
"{"some_prop":42}"

Nesting DynamicObjs

type MyComplexJSONType() =
    inherit DynamicObj()

    static member init
        (
            ?PropA: int [],
            ?PropB: A
        ) =
            MyComplexJSONType()
            |> MyComplexJSONType.style
                (
                    ?PropA  = PropA,
                    ?PropB  = PropB
                )

    static member style
        (
            ?PropA: int [],
            ?PropB: A
        ) =
            fun (t:MyComplexJSONType) ->

                PropA |> DynObj.setValueOpt t "prop_a"
                PropB |> DynObj.setValueOpt t "prop_b"

                t

let complex =
    MyComplexJSONType.init(
        PropA = [|42;1337|],
        PropB = A.init(68) // nested dynamic objects
    )

let complexSerialized = 
    complex
    |> JsonConvert.SerializeObject

You can use the DynObj.print function to look at the dynamic members of the object:

complex |> DynObj.print
?prop_a: System.Int32[]
?prop_b:
    ?some_prop: 68

And this is how the serialized JSON looks like:

"{"prop_a":[42,1337],"prop_b":{"some_prop":68}}"

Simple inheritance pattern for ImmutableDynamicObj

#r "nuget: Newtonsoft.JSON, 12.0.3"
open Newtonsoft.Json
open DynamicObj

type ImmutableA() = 
    inherit ImmutableDynamicObj()

    static member init
        (
            ?SomeProp: int
        ) =
            ImmutableA()
            |> ImmutableA.style
                (
                    ?SomeProp  = SomeProp
                )

    static member style
        (
            ?SomeProp: int
        ) =
            fun (a:ImmutableA) ->
                a 
                |> ImmutableDynamicObj.addOpt "some_prop" SomeProp

You can use the ImmutableDynamicObj.print function to look at the dynamic members of the object:

ImmutableA.init(42) |> ImmutableDynamicObj.print
?some_prop: 42

And this is how the serialized JSON looks like:

let immutableASerialized =
    ImmutableA.init(42)
    |> JsonConvert.SerializeObject
"{"some_prop":42}"

Nesting DynamicObjs

DynamicObj.Operators adds usefull operators for adding properties:

open DynamicObj.Operators

type ImmutableMyComplexJSONType() =
    inherit ImmutableDynamicObj()

    static member init
        (
            ?PropA: int [],
            ?PropB: A
        ) =
            ImmutableMyComplexJSONType()
            |> ImmutableMyComplexJSONType.style
                (
                    ?PropA  = PropA,
                    ?PropB  = PropB
                )

    static member style
        (
            ?PropA: int [],
            ?PropB: A
        ) =
            fun (t:ImmutableMyComplexJSONType) ->
                t
                ++? ("prop_a", PropA)
                ++? ("prop_b", PropB)

let immutableComplex =
    ImmutableMyComplexJSONType.init(
        PropA = [|42;1337|],
        PropB = A.init(68) // nested dynamic objects
    )

let immutableComplexSerialized = 
    immutableComplex
    |> JsonConvert.SerializeObject

You can use the DynObj.print function to look at the dynamic members of the object:

complex |> DynObj.print
?prop_a: System.Int32[]
?prop_b:
    ?some_prop: 68

And this is how the serialized JSON looks like:

"{"prop_a":[42,1337],"prop_b":{"some_prop":68}}"
namespace Newtonsoft
namespace Newtonsoft.Json
namespace DynamicObj
type A = inherit DynamicObj new: unit -> A static member init: ?SomeProp: int -> A static member style: ?SomeProp: int -> (A -> A)
Multiple items
namespace DynamicObj

--------------------
type DynamicObj = inherit DynamicObject new: unit -> DynamicObj member CopyDynamicProperties: unit -> DynamicObj member CopyDynamicPropertiesTo: target: DynamicObj -> unit override Equals: o: obj -> bool override GetDynamicMemberNames: unit -> IEnumerable<string> override GetHashCode: unit -> int member GetProperties: includeInstanceProperties: bool -> seq<KeyValuePair<string,obj>> member Remove: name: string -> bool + 1 overload member SetValue: name: string * value: 'a -> unit ...

--------------------
new: unit -> DynamicObj
val SomeProp: int option
Multiple items
val int: value: 'T -> int (requires member op_Explicit)
<summary>Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Int32.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted int</returns>
<example id="int-example"><code lang="fsharp"></code></example>


--------------------
[<Struct>] type int = int32
<summary>An abbreviation for the CLI type <see cref="T:System.Int32" />.</summary>
<category>Basic Types</category>


--------------------
type int<'Measure> = int
<summary>The type of 32-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Int32" />.</summary>
<category>Basic Types with Units of Measure</category>
new: unit -> A
static member A.style: ?SomeProp: int -> (A -> A)
val a: A
module DynObj from DynamicObj
val setValueOpt: dyn: DynamicObj -> propName: string -> _arg1: 'a option -> unit
val aformat: string
static member A.init: ?SomeProp: int -> A
val format: d: DynamicObj -> string
val aSerialized: string
type JsonConvert = static member DeserializeAnonymousType<'T> : value: string * anonymousTypeObject: 'T -> 'T + 1 overload static member DeserializeObject: value: string -> obj + 7 overloads static member DeserializeXNode: value: string -> XDocument + 3 overloads static member DeserializeXmlNode: value: string -> XmlDocument + 3 overloads static member PopulateObject: value: string * target: obj -> unit + 1 overload static member SerializeObject: value: obj -> string + 7 overloads static member SerializeXNode: node: XObject -> string + 2 overloads static member SerializeXmlNode: node: XmlNode -> string + 2 overloads static member ToString: value: DateTime -> string + 24 overloads static val False: string ...
<summary> Provides methods for converting between .NET types and JSON types. </summary>
<example><code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\SerializationTests.cs" region="SerializeObject" title="Serializing and Deserializing JSON with JsonConvert" /></example>
JsonConvert.SerializeObject(value: obj) : string
JsonConvert.SerializeObject(value: obj, settings: JsonSerializerSettings) : string
JsonConvert.SerializeObject(value: obj, [<System.ParamArray>] converters: JsonConverter[]) : string
JsonConvert.SerializeObject(value: obj, formatting: Formatting) : string
JsonConvert.SerializeObject(value: obj, formatting: Formatting, settings: JsonSerializerSettings) : string
JsonConvert.SerializeObject(value: obj, ``type`` : System.Type, settings: JsonSerializerSettings) : string
JsonConvert.SerializeObject(value: obj, formatting: Formatting, [<System.ParamArray>] converters: JsonConverter[]) : string
JsonConvert.SerializeObject(value: obj, ``type`` : System.Type, formatting: Formatting, settings: JsonSerializerSettings) : string
Multiple items
type MyComplexJSONType = inherit DynamicObj new: unit -> MyComplexJSONType static member init: ?PropA: int[] * ?PropB: A -> MyComplexJSONType static member style: ?PropA: int[] * ?PropB: A -> (MyComplexJSONType -> MyComplexJSONType)

--------------------
new: unit -> MyComplexJSONType
val PropA: int[] option
val PropB: A option
static member MyComplexJSONType.style: ?PropA: int[] * ?PropB: A -> (MyComplexJSONType -> MyComplexJSONType)
val t: MyComplexJSONType
val complex: MyComplexJSONType
static member MyComplexJSONType.init: ?PropA: int[] * ?PropB: A -> MyComplexJSONType
val complexSerialized: string
val print: d: DynamicObj -> unit
Multiple items
type ImmutableA = inherit ImmutableDynamicObj new: unit -> ImmutableA static member init: ?SomeProp: int -> ImmutableA static member style: ?SomeProp: int -> (ImmutableA -> ImmutableA)

--------------------
new: unit -> ImmutableA
Multiple items
type ImmutableDynamicObj = new: unit -> ImmutableDynamicObj override Equals: o: obj -> bool override GetHashCode: unit -> int member TryGetTypedValue: name: string -> 'a option member TryGetValue: name: string -> obj option static member add: name: string -> newValue: obj -> object: 'c -> 'c (requires 'c :> ImmutableDynamicObj and default constructor) static member addOpt: name: string -> newValue: 'c option -> object: 'd -> 'd (requires 'd :> ImmutableDynamicObj and default constructor) static member addOptBy: name: string -> newValue: 'd option -> f: ('d -> 'e) -> object: 'f -> 'f (requires 'f :> ImmutableDynamicObj and default constructor) static member combineWith: sourceObject: #ImmutableDynamicObj -> targetObject: 'a1 -> 'a1 (requires 'a1 :> ImmutableDynamicObj and default constructor) static member format: object: #ImmutableDynamicObj -> string ...
<summary> Represents an DynamicObj's counterpart with immutability enabled only. </summary>

--------------------
new: unit -> ImmutableDynamicObj
static member ImmutableA.style: ?SomeProp: int -> (ImmutableA -> ImmutableA)
val a: ImmutableA
static member ImmutableDynamicObj.addOpt: name: string -> newValue: 'c option -> object: 'd -> 'd (requires 'd :> ImmutableDynamicObj and default constructor)
static member ImmutableA.init: ?SomeProp: int -> ImmutableA
static member ImmutableDynamicObj.print: object: #ImmutableDynamicObj -> unit
val immutableASerialized: string
module Operators from DynamicObj
Multiple items
type ImmutableMyComplexJSONType = inherit ImmutableDynamicObj new: unit -> ImmutableMyComplexJSONType static member init: ?PropA: int[] * ?PropB: A -> ImmutableMyComplexJSONType static member style: ?PropA: int[] * ?PropB: A -> (ImmutableMyComplexJSONType -> ImmutableMyComplexJSONType)

--------------------
new: unit -> ImmutableMyComplexJSONType
static member ImmutableMyComplexJSONType.style: ?PropA: int[] * ?PropB: A -> (ImmutableMyComplexJSONType -> ImmutableMyComplexJSONType)
val t: ImmutableMyComplexJSONType
val immutableComplex: ImmutableMyComplexJSONType
static member ImmutableMyComplexJSONType.init: ?PropA: int[] * ?PropB: A -> ImmutableMyComplexJSONType
val immutableComplexSerialized: string