Builder inheritance or generics to remove boilerplate #497
Replies: 2 comments 4 replies
-
I've been thinking about this too. I've not an easy one to solve really - F# doesn't support traits or mixins. The only solutions I could come up with are :
|
Beta Was this translation helpful? Give feedback.
-
Using Interfaces and Extension MethodsThis approach is almost like type classes and appears to "just work". I don't quite know how (!). Let's take the example of Tags. 1. Define an interfaceCreate an interface - lets call it type ITaggable<'TConfig> =
abstract member AddTags : state:'TConfig -> (string * string) list -> 'TConfig 2. Don't change builder recordFirst, keep your config type with the field on it: type MyConfig =
{ Tags : Map<string,string>
....
} 3. Remove builder methods for Tags.Remove all the attributed methods e.g. 4. Implement the interface on the buildertype MyBuilder() =
interface ITaggable<MyConfig> with
member _.AddTags state pairs =
{ state with Tags = pairs |> List.fold (fun map (key, value) -> Map.add key value map) state.Tags } Who provides / receives "state"? Who knows. F# does it. It's magic. 5. Provide ONE OFF extension methodsThese extension methods provide the keywords for tagging and delegate to the interface implementation: [<AutoOpen>]
module Extensions =
type ITaggable<'T> with
[<CustomOperation "add_tags">]
member this.Tags(state:'T, pairs) = this.AddTags state pairs
[<CustomOperation "add_tag">]
member this.Tag(state:'T, key, value) = this.AddTags state [ key, value ] That's it. Now every type that implements ITaggable will magically get these keywords. We should be able to apply this to things like Dependency and Name as well (and any other "reusable" set of keywords). I'm quite excited about this because it provides a way to abstract over a type whilst still allowing us to shape the data however we want at the builder level. What do you think, @ninjarobot? @cartermp Have I missed something here or have I stumbled on something that appears quite powerful here? |
Beta Was this translation helpful? Give feedback.
-
There is a lot of boilerplate between builders where we have to repeatedly create things like
name
,add_tags
, anddepends_on
. Could we use some inheritance or some sort of generic builder to make that consistent across builders?Beta Was this translation helpful? Give feedback.
All reactions