-
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
Support operators in type extensions, and also operators on internal types [RFC FS-1043] #230
Comments
#29 Allow Type Extensions and Extension Methods to Satisfy Constraints was closed in favor of this suggestion, and while being able to define extension operators would be great, especially since it would make it a lot easier to define global operators that only work with types that implement an operator of the same form, it's the other aspects of SRTP that I think would be more useful. Currently we can use SRTP constraints to define extension methods that will only appear on types that satisfy the constraint open System.Collections.Generic
let inline getOption key this =
let mutable v = Unchecked.defaultof<'v>
let scc = ( ^a : (member TryGetValue : 'k * ('v byref) -> bool) this, key, &v)
if scc then Some v else None
let inline getOrDefault key defaultValue this =
let mutable v = Unchecked.defaultof<'v>
let scc = ( ^a : (member TryGetValue : 'k * ('v byref) -> bool) this, key, &v)
if scc then v else defaultValue
let inline bind key f this =
let mutable v = Unchecked.defaultof<'v>
let scc = ( ^a : (member TryGetValue : 'k * ('v byref) -> bool) this, key, &v)
if scc then f v else None
let inline return'< ^a,'k,'v when 'a : (member TryGetValue : 'k * ('v byref) -> bool)>(v : 'v) ( _ : ^a) = Some v
open System.Runtime.CompilerServices
[<Extension>]
type ExtensionMethods() =
[<Extension>] static member inline GetOption (this, key) = getOption key this
[<Extension>] static member inline GetOrDefault (this, key,dval) = getOrDefault key dval this
[<Extension>] static member inline Bind (this, key, f) = bind key f this
[<Extension>] static member inline Return (this,v) = return' v this
// EXTENSION CONSTRAINTS
[<System.Runtime.CompilerServices.Extension>]
type ExtensionMethods2() =
[<System.Runtime.CompilerServices.Extension>]
static member inline GetOption< ^a,'k,'v when 'a : (member TryGetValue : 'k * ('v byref) -> bool)>(this : ^a, key : 'k) =
getOption key this
[<System.Runtime.CompilerServices.Extension>]
static member inline GetOrDefault< ^a,'k,'v when 'a : (member TryGetValue : 'k * ('v byref) -> bool)>(this : ^a, key : 'k, defaultValue : 'v) =
let mutable v = Unchecked.defaultof<'v>
let scc = ( ^a : (member TryGetValue : 'k * ('v byref) -> bool) this, key, &v)
if scc then v
else defaultValue
[<System.Runtime.CompilerServices.Extension>]
static member inline Bind< ^a,'k,'v when 'a : (member TryGetValue : 'k * ('v byref) -> bool)>(this : ^a, key : 'k, f : 'v -> 'v option) =
let mutable v = Unchecked.defaultof<'v>
let scc = ( ^a : (member TryGetValue : 'k * ('v byref) -> bool) this, key, &v)
if scc then f v
else None
[<System.Runtime.CompilerServices.Extension>]
static member inline Return< ^a,'k,'v when 'a : (member TryGetValue : 'k * ('v byref) -> bool)>(this : ^a, v : 'v) = Some v But if type extensions/extension methods themselves could also be used to satisfy constraints it would open up a whole new world of flexibility for this kind of technique. It could be a decent way to make provided types more expressive, especially if structural aspects of the provided types are used as the constraints to tailor and extend its API |
@cloudRoutine contraints on Extension Methods. That would be cool. I have another feature request (me thinks its more of a bug but ...) and as I am not sure if I should create a new issue I will put it here What is really annoying is the follwing behaviour using extension methods and static type constraints type System.String with
member this.Foo (x: string) = this + x
type Bar = Bar of String
with
member this.Foo (x: string) =
match this with
| Bar y -> y + x
let z = "Bar".Foo("foo")
let z0 = (Bar "Bar").Foo("foo") All of this works as expected. Now I define an inline method using static type constraints let inline foo (x: ^T) (y:^R) : ^R = (^T : (member Foo: ^R -> ^R) (x, y)) And call it on a in-type-defined method let z1 = foo (Bar "Foo") "Bar" Which works as expected but calling the optional extension method gives me an error let z2 = foo "foo" "bar"
^^^^---- Type String does not support operator "Foo" This is confusing and unexpected. I know there are workarounds for that like the ones used in FsharpPlus https://github.com/gusty/FSharpPlus/blob/master/src/FSharpPlus/Functor.fs#L217-L222 but that is really something very hard to understand |
Here is another one that maybe a bug or a feature request. Static Type Constraits break down in the face of overloaded function with generic paramters. This is very anoying type Extendor () =
static member Foo(x:Option<int>) = 1
static member Foo(x:Option<string>) = "Its a Option of String"
let z = Extendor.Foo (Some 1)
let z1 = Extendor.Foo (Some "1") Using the functions as static members works fine. So does wrapping them in an inline function using type constraints let inline foo (e:^R, x:^T) : ^S = (^R : (static member Foo: ^T -> ^S) x)
let z3 = foo (Unchecked.defaultof<Extendor>, Some "1")
let z4 = foo (Unchecked.defaultof<Extendor>, Some 1) To a degree - If I Try the follwing let inline foo' (x:^T) : ^S = foo (Unchecked.defaultof<Extendor>, x) The compiler spits out this error A unique overload for method 'Foo' could not be determined based on type information prior to this
program point.
A type annotation may be needed. Candidates:
static member Extendor.Foo : x:Option<int> -> int,
static member Extendor.Foo : x:Option<string> -> string This behavior is very surprising and therefore confusing |
See trial implementation at dotnet/fsharp#3582 |
Submitted by Gustavo Guerra on 3/28/2014 12:00:00 AM
80 votes on UserVoice prior to migration
This is currently not allowed:
Original UserVoice Submission
Archived Uservoice Comments
The text was updated successfully, but these errors were encountered: