-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Copy-and-update syntax for interfaces (decorator pattern) #524
Comments
I would love this, but would still prefer a mechanism to specify the return type (ie: in your example, should it be The ability to return an interface which delegates implementation to another object would be extremely useful, both in object expressions, but also in normal interface implementations, however, I think it'd need different syntax so the interface type was explicit. Perhaps something like { list :> IList<'a> with
member __.Add item =
if list.Count >= max then failwith "Too many items" else list.Add(item) } It seems like this could be easier to extend to normal interface definitions: type Foo<'T> () =
let internalList = ResizeArray<'T>()
interface internalList :> IList<'T> And/or: type Foo<'T> () =
let internalList = ResizeArray<'T>()
interface internalList :> IList<'T> with
member __.Add item =
() // "override" implementation here |
The first expression in the copy-and-update expression would determine the return type, same as record expressions. So, if you wanted to wrap an let withBounds x (list: IList<'a>) =
{ list with
(...members...) } If you wanted the returned type to be a different interface: let withBounds x (list: IList<'a>) =
{ list :> ICollection<'a> with (...) } With regard to the normal class definition, the decorator pattern doesn't make sense without passing in an existing instance of the interface, because then you run into the same single-inheritance/fragile-base-class problems that we want to avoid. I think it would look more like this: type BoundedList<'a> (list: IList<'a>) =
list with
member __.Add(item) = //etc ...and then |
One addition: It would be even more useful if there is a way to make the underlying field mutable, for example if we could use a But even without that it feels like a logical addition on the first look. |
Could you explain this a bit more please? |
@dsyme Sure. (Sorry for the delay). Something like (I have no idea how a syntax would look like): let withBound max (list: System.Collections.Generic.IList<'a>) =
{ mutable list with // I think this should be "marked" somehow, maybe allow a ref cell here?
member this.Add(item) =
if list.Count >= max then failwith "Too many items" else list.Add(item) }
let o1 : System.Collections.Generic.IList<'a>= ...
let o2 : System.Collections.Generic.IList<'a>= ...
let wrapper = withBound 3 o1
wrapper.list <- o2 // This Basically a way to "replace" the wrapped object. Otherwise I need to wrap again and then need to implement all members again :). Usually I don't want to replace my code to understand With a ref cell: let withBound max (list: System.Collections.Generic.IList<'a>) =
let l = ref list
{ l with // maybe a bit invisible?
member this.Add(item) =
if list.Count >= max then failwith "Too many items" else list.Add(item) }, l
let o1 : System.Collections.Generic.IList<'a>= ...
let o2 : System.Collections.Generic.IList<'a>= ...
let wrapper, cell = withBound 3 o1
cell := o2 // This Does that make it clear? |
Maybe type Foo<'T> () =
let mutable internalList = ResizeArray<'T>() // Note the mutable here
interface internalList :> IList<'T> Would be enough for such situations, more explicit and less special syntax... |
Related: dotnet/csharplang#477 |
Considering #132 #195 and #555 I think for object expressions the same syntax should be used. let withBound max (list: System.Collections.Generic.IList<'a>) =
{ new System.Collections.Generic.IList<'a> by list with
member this.Add(item) =
if list.Count >= max then failwith "Too many items" else list.Add(item) } With the same semantics as in #132 (comment) |
Note that regarding this comment I feel like we should support any expression after let withBound max (list: System.Collections.Generic.IList<'a>) =
let l = ref list
{ new System.Collections.Generic.IList<'a> by !l with // maybe a bit invisible?
member this.Add(item) =
if list.Count >= max then failwith "Too many items" else list.Add(item) }, l
let o1 : System.Collections.Generic.IList<'a>= ...
let o2 : System.Collections.Generic.IList<'a>= ...
let wrapper, cell = withBound 3 o1
cell := o2 // This |
Closing this as a duplicate of #164 , it should all be considered as part of one thing |
@dsyme I have a working implementation for the object expression case like this one. The exact code works, only changing the |
I propose we add syntax to interfaces similar to the copy and update record expression syntax.
Say I want to implement an IList<_> that constrains an existing IList implementation to a maximum item count. Currently I would can do:
With the proposed syntax, I could do:
This would make the decorator pattern very easy in F#, e.g.:
Pros and Cons
The advantages of making this adjustment to F# are ...
The disadvantages of making this adjustment to F# are ...
Related Suggestions
Affadavit (must be submitted)
Please tick this by placing a cross in the box:
The text was updated successfully, but these errors were encountered: