how to implement interface with abstract members that accept option word? - f#

the interface code as follows
type [<AllowNullLiteral>] QueryInfo =
abstract status: QueryInfoStatus option with get, set
abstract lastFocusedWindow: bool option with get, set
abstract windowId: float option with get, set
abstract windowType: QueryInfoWindowType option with get, set
abstract active: bool option with get, set
abstract index: float option with get, set
abstract title: string option with get, set
abstract url: U2<string, ResizeArray<string>> option with get, set abstract currentWindow: bool option with get, set
abstract highlighted: bool option with get, set
abstract discarded: bool option with get, set
abstract autoDiscardable: bool option with get, set
abstract pinned: bool option with get, set
abstract audible: bool option with get, set
abstract muted: bool option with get, set
abstract groupId: float option with get, set
I want to pass a parameter to the function that accept argument type QueryInfo
abstract query: queryInfo: QueryInfo -> unit
so how do I use the interface to pass a valueactive=true,currentWindow=true that satisfies the interface?
in fact I tried the code, but failed.
type Query(active:bool option,currentWindow:bool option) =
interface Chrome.Tabs.QueryInfo with
member _.active = active
member _.currentWindow = currentWindow
query(Query(true,true))
the IDE told me that
This expression was expected to have type 'bool option' but here has type 'bool'
if I add some type, I get this:

I assume this is a question about interop with JavaScript libraries from Fable. This means that you are compiling to JavaScript and can use extra tricks that Fable provides for accessing JavaScript libraries. The tricks are documented in the Fable JS interop documentation and there are a few options listed there.
In your case, it seems that a nice thing to do would be to use the !! oeprator. This is a Fable-specific trick (that the Fable compiler understands) that lets you create interface values like this. I think the following should do the trick:
let x: Chrome.Tabs.QueryInfo = !!{| active=Some true; currentWindow=Some true |}
Chrome.Tabs.query(x)
In fact, you may be even able to call the query function directly:
Chrome.Tabs.query(!!{| active=Some true; currentWindow=Some true |})
I have not actually tried compiling and running this, but based on your example and the Fable docs, something along those lines should work.

Related

Check if a type implements an interface [duplicate]

I've recently found myself in a situation where I wanted to check if a Type is a subtype of another Type this is what I've tried
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord is Record); // return false but why ??
}
The only time it makes sense to check if one type is a subtype of another type is when at least one of the types is a type variable. (Otherwise, you can just look at the source and write a constant true or false into the code).
There is a way to check whether one type is a subtype of another, and it does use the is operator, but you need to have an instance as the first operand and a type as the second. You can't just create an instance of an unknown type, so we instead rely in Dart's covariant generics:
bool isSubtype<S, T>() => <S>[] is List<T>;
(You can use any generic class, or even create your own, instead of using List. All it needs is a way to create the object.)
Then you can write:
print(isSubtype<TimeRecord, Record>()); // true!
The is keyword is used to check if an object instance is an object of type T, and not if a type is another type:
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord() is Record); // returns true!
}
Just to add up to #lrn answer.
You could also do something like:
extension NullableObjectsExtensions<T> on T {
bool isSubtypeOf<S>() => <T>[] is List<S>;
bool isSupertypeOf<S>() => <S>[] is List<T>;
}
So this way you can test any variable anywhere.

Overriding static properties in F# with extension methods

F# extension methods can be defined on types with the same name and type signature as existing instance and static methods to effectively override the default implementation of these methods, however I can't get this to work on static properties.
In particular, I'm trying to create an extension method for DateTime that returns a more precise time as follows:
#nowarn "51"
open System
module DateTimeExtensions =
open System.Runtime.InteropServices
[<DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)>]
extern void private GetSystemTimePreciseAsFileTime(int64*)
type System.DateTime with
// example showing that static methods can be overridden
static member IsLeapYear(_: DateTime) =
printfn "Using overridden IsLeapYear!"
true
// more accurate UtcNow method (note: not supported by older OS versions)
static member UtcNow =
printfn "Using overridden UtcNow!"
let mutable fileTime = 0L
GetSystemTimePreciseAsFileTime(&&fileTime)
DateTime.FromFileTimeUtc(fileTime)
However, the output when executing
open DateTimeExtensions
let _ = DateTime.IsLeapYear(DateTime.UtcNow)
is just
Using overridden IsLeapYear!
which shows that the static method 'override' is working, but not the static property.
(Note: I'm using F# 4.0)
This statement seems to be incorrect:
F# extension methods can be defined on types with the same name and
type signature as existing instance and static methods to effectively
override the default implementation of these methods, however I can't
get this to work on static properties.
No, they don't override.
You might be confused because in fact your signature of IsLeapYear is wrong, it should take an integer, that's why it works I mean you are not overriding anything, just adding a new (extension) method.
If you try it with the original signature you'll see that it doesn't work either:
type System.DateTime with
// example showing that static methods can NOT be overridden
static member IsLeapYear(_: int) =
printfn "Using overridden IsLeapYear!"
false
> DateTime.IsLeapYear(2000);;
val it : bool = true
Which is consistent with the behavior of the static property extension.
Anyway I'm not sure why it was decided not to override, if there was such decision at all when designing the language. I think it would be an interesting feature and if there is a good reason not to implement it at least it should emit a warning saying that since the method already exists it will never be called.
Maybe I will open an issue or a suggestion for the F# compiler.

What would be the inferred type of my function here?

I am wondering why F# compiler allows the following
type MyMath() =
member this.Add a b = a + b
What would be the type of Add method and its arguments ? If I compiled this into the Library and try to use it in C# what types of arguments it is going to expect ?
Shouldn't the F# require you to explicitly specify types when it comes to Methods of classes ?
You can enter the code in F# interactive and see the inferred type yourself:
> type MyMath() =
member this.Add a b = a + b;;
type MyMath =
class
new : unit -> MyMath
member Add : a:int -> b:int -> int
end
Here, the compiler uses default type for the + operator which is int. The operator can be used with other types, but the inference uses int as the default. You can use type annotations, but you are not required to do that if you are happy with the inferred type.
In general, you can use type annotations in F# to specify types if you want to, but in many cases, the inferred type will be exactly what you want, so you do not have to make the code more verbose, if the inference behaves as expected.
Of course, if you were writing some library and wanted to be super careful about changing the API, then you might want to use type annotations (or you can add F# Interface file .fsi)
F# Interactive is your friend:
type MyMath =
class
new : unit -> MyMath
member Add : a:int -> b:int -> int
end

Is there a way to inject support for the F# Option type into ServiceStack?

Updated below...
I recently started experimenting with ServiceStack in F#, so naturally I started with porting the Hello World sample:
open ServiceStack.ServiceHost
open ServiceStack.ServiceInterface
open ServiceStack.WebHost.Endpoints
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string }
[<CLIMutable>]
type HelloResponse = { Result : string }
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result = sprintf "Hello, %s!" req.Name }
type HelloAppHost() =
inherit AppHostBase("Hello Web Services", typeof<HelloService>.Assembly)
override x.Configure container = ()
type Global() =
inherit System.Web.HttpApplication()
member x.Application_Start() =
let appHost = new HelloAppHost()
appHost.Init()
That works great. It's very concise, easy to work with, I love it. However, I noticed that the routes defined in the sample allow for the Name parameter to not be included. Of course, Hello, ! looks kind of lame as output. I could use String.IsNullOrEmpty, but it is idiomatic in F# to be explicit about things that are optional by using the Option type. So I modified my Hello type accordingly to see what would happen:
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string option }
As soon as I did this, the F# type system forced me to deal with the fact that Name might not have a value, so I changed HelloService to this to get everything to compile:
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result =
match req.Name with
| Some name -> sprintf "Hello, %s!" name
| None -> "Hello!" }
This compiles, and runs perfectly when I don't supply a Name parameter. However, when I do supply a name...
KeyValueDataContractDeserializer: Error converting to type: Type
definitions should start with a '{', expecting serialized type
'FSharpOption`1', got string starting with: World
This wasn't a complete surprise of course, but it brings me to my question:
It would be trivial for me to write a function that can wrap an instance of type T into an instance of type FSharpOption<T>. Are there any hooks in ServiceStack that would let me provide such a function for use during deserialization? I looked, but I couldn't find any, and I'm hoping I was just looking in the wrong place.
This is more important for F# use than it might seem at first, because classes defined in F# are by default not allowed to be null. So the only (satisfying, non-hacky) way of having one class as an optional property of another class is with, you guessed it, the Option type.
Update:
I was able to sort-of get this working by making the following changes:
In the ServiceStack source, I made this type public:
ServiceStack.Text.Common.ParseFactoryDelegate
...and I also made this field public:
ServiceStack.Text.Jsv.JsvReader.ParseFnCache
With those two things public, I was able to write this code in F# to modify the ParseFnCache dictionary. I had to run this code prior to creating an instance of my AppHost - it didn't work if I ran it inside the AppHost's Configure method.
JsvReader.ParseFnCache.[typeof<Option<string>>] <-
ParseFactoryDelegate(fun () ->
ParseStringDelegate(fun s -> (if String.IsNullOrEmpty s then None else Some s) |> box))
This works for my original test case, but aside from the fact that I had to make brittle changes to the internals of ServiceStack, it sucks because I have to do it once for each type I want to be able to wrap in an Option<T>.
What would be better is if I could do this in a generic way. In C# terms, it would be awesome if I could provide to ServiceStack a Func<T, Option<T>> and ServiceStack would, when deserializing a property whose generic type definition matches that of the return type of my function, deserialize T and then pass the result into my function.
Something like that would be amazingly convenient, but I could live with the once-per-wrapped-type approach if it were actually part of ServiceStack and not my ugly hack that probably breaks something somewhere else.
So there are a couple of extensibility points in ServiceStack, on the framework level you can add your own Custom Request Binder this allows you to provide your own model binder that's used, e.g:
base.RequestBinders.Add(typeof(Hello), httpReq => {
var requestDto = ...;
return requestDto;
});
But then you would need to handle the model binding for the different Content-Types yourself, see CreateContentTypeRequest for how ServiceStack does it.
Then there are hooks at the JSON Serializer level, e.g:
JsConfig<Hello>.OnDeserializedFn = dto => newDto;
This lets you modify the instance of the type returned, but it still needs to be the same type but it looks like the F# option modifier changes the structural definition of the type?
But I'm open to adding any hooks that would make ServiceStack more palatable for F#.
What does the code look like to generically convert a normal Hello type to an F# Hello type with option?
The only thing I can think of is to replace the option type with your own type, one that has an implicit conversion from string to myOption, and anything else you need.
Not all that nice, but workable. Your type would probably also need to be serializable.
type myOption =
| None
| Some of string
static member public op_Implicit (s:string) = if s <> null then Some s else None
member public this.Value = match this with
| Some s -> s
| _ -> null
member this.Opt = match this with
| Some s -> Option.Some s
| None -> Option.None
Your record type would then be
[<CLIMutable>]
type Hello =
{ Name : myOption }
On the other hand, ServiceStack is open source, so maybe something could be done there.

why is the implementation of my abstract member not public

I've been struggling to get this to compile for about an hour. It must be something stupid. Can you spot it?
in my lib project:
namespace TravelerStuff
open System
type Traveler =
abstract GetData : unit -> unit
type public DeltaTraveler() =
interface Traveler with
member v.GetData () =
printf "hello"
and in my console test app:
[<EntryPoint>] let main _ =
let traveler = new TravelerStuff.DeltaTraveler()
traveler.GetData // this line won't compile: (The field, constructor or member 'GetData' is not defined)
As gradbot says, F# doesn't currently implicitly convert values to interfaces when searching for members. Also, F# only uses explicit interface implementation (as known from C#) and not implicit implementation where members are not only compiled as implementation of an interface, but also as ordinary (directly visible) members of the type.
Aside from casting, you can duplicate the member in the type definition:
type DeltaTraveler() =
member v.GetData () = printf "hello"
interface Traveler with
member v.GetData () = v.GetData()
Also, if you just want to implement an interface, but don't need to add any members, you can use F# object expressions (which are more lightweight):
let deltaTraveler() =
{ new Traveler with
member v.GetData () = printf "hello" }
// The function directly returns value of type 'Traveler'
let t = deltaTraveler()
t.GetData()
You need to upcast. F# currently won't do it for you in this situation.
(traveler :> TravelerStuff.Traveler).GetData()
// open the namespace to reduce typing.
open TravelerStuff
(traveler :> Traveler).GetData()
Snip from F# docs.
In many object-oriented languages,
upcasting is implicit; in F#, the
rules are slightly different.
Upcasting is applied automatically
when you pass arguments to methods on
an object type. However, for let-bound
functions in a module, upcasting is
not automatic, unless the parameter
type is declared as a flexible type.
For more information, see Flexible Types (F#).

Resources