Fsharp interactive fu - reflection

I have a variable in fsharp interactive
val toto : obj = [["NKY INDEX"]]
(I got that value from a call to a regular dotnet library, whose prototype tells me it returns an obj )
I would like to access the value inside of it, but I don't know exactly the type.
So I try to reflect on it :
>toto.GetType();;
val it : Type =
System.Object[,]
{Assembly = mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;
AssemblyQualifiedName = "System.Object[,], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
Attributes = AutoLayout, AnsiClass, Class, Public, Sealed, Serializable;
BaseType = System.Array;
ContainsGenericParameters = false;
CustomAttributes = seq [[System.SerializableAttribute()]];
DeclaredConstructors = [|Void .ctor(Int32, Int32);
Void .ctor(Int32, Int32, Int32, Int32)|];
DeclaredEvents = [||];
DeclaredFields = [||];
DeclaredMembers = [|Void Set(Int32, Int32, System.Object);
System.Object& Address(Int32, Int32);
System.Object Get(Int32, Int32);
Void .ctor(Int32, Int32);
Void .ctor(Int32, Int32, Int32, Int32)|];
DeclaredMethods = [|Void Set(Int32, Int32, System.Object);
System.Object& Address(Int32, Int32);
System.Object Get(Int32, Int32)|];
DeclaredNestedTypes = seq [];
DeclaredProperties = [||];
It has a Get method, however, when I try to retrieve the element, I get an error.
>toto.Get(0,0);;
toto.Get(0,0);;
-----^^^
error FS0039: The field, constructor or member 'Get' is not defined
What is the correct way to retrieve the inside element ?
PS : casting it beforehand yields the same
>(toto :?> System.Object[,]).Get(0,0);;
(toto :?> System.Object[,]).Get(0,0);;
----------------------------^^^
error FS0039: The field, constructor or member 'Get' is not defined
same for .[0, 0]
> toto.[0, 0];;
toto.[0, 0];;
^^^^^^^^^^^
error FS0039: The field, constructor or member 'Item' is not defined

let toto = box (Array2D.init 1 1 (fun _ _ -> "NKY INDEX"))
(toto :?> string[,]).[0,0]

I imagine
let arr = toto :?> obj[,] // downcast to actual type
let item = arr.[0,0]
is what you want.

Related

Mono Bug: Error message when attempting to observe a newly assigned value after mutating an object member

I'm observing an error message on a data-tip when attempting to observe a newly assigned value after mutating an object member.
Viewmodel:
I'm trying to mutate the header member of a viewmodel object.
let mutable header : NavBarItem option = None
member x.Header with get() = header
and set(v) = header <- v
base.NotifyPropertyChanged(<# x.Header #>)
...
//----------------------------------
// THE FOLLOWING ERRORS
//----------------------------------
member x.LoadAsync(panelId:PanelId) =
let items = seq [NavBarItem() :> UITemplate]
let result = items |> Seq.map (fun v -> v :?> NavBarItem)
|> Seq.tryHead // Error recovering value
x.Header <- result
Error:
Here's the error after I hover my cursor over x.Header:
Incorrect number or types of arguments Parameter name: arguments
Here's a bug report that I observed after researching the error message.
UPDATE:
I attempted to serialize the sequence of objects that I did have access to so that I could deserialize the json and access an individual item.
That also failed:
let temp = seq [NavBarItem() :> UITemplate] |> filterToNavBarItems
|> Seq.cast<NavBarItem>
let json = JsonConvert.SerializeObject(temp)
let items = JsonConvert.DeserializeObject<NavBarItem seq>(json)
let item = items |> Seq.tryHead
x.Header <- item // Error recovering value
Json:
[{"MeasureId":"some_navbar_id","Header":"Dashboard","Subheader":"Trauma Alerting","EmblemLabel":"","IsEmblemAttached":false,"EmblemBGColor":"","EmblemFGColor":""}]
Appendix:
type UITemplate =
abstract member ToString : unit -> string
abstract member OrderIndex : int with get, set
type NavBarItem() =
inherit ViewModelBase()
let mutable header = ""
interface UITemplate with
member x.ToString() = "NavBarItem"
member val OrderIndex = -1 with get,set
member x.Header with get() = header
and set(v) = header <- v
base.NotifyPropertyChanged(<# x.Header #>)
type ViewModelBase () =
let propertyChanged = Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
let getPropertyName = function
| PropertyGet(_,pi,_) -> pi.Name
| _ -> invalidOp "Expecting property getter expression"
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
member this.NotifyPropertyChanged propertyName =
propertyChanged.Trigger(this,PropertyChangedEventArgs(propertyName))
member this.NotifyPropertyChanged quotation =
quotation |> getPropertyName |> this.NotifyPropertyChanged
It is hard to answer your question, because the code cannot really be compiled as-is. This makes it hard to see where the error is, because it is likely related to something that is not shown in your snippet.
I tried getting the code to compile by removing as much as possible. I ended up with the following, but this works fine:
type ViewModelBase() =
member x.NotifyPropertyChanged(a:Microsoft.FSharp.Quotations.Expr<'a>) = ()
type NavBarItem() =
inherit ViewModelBase()
let mutable header : NavBarItem option = None
member x.Header
with get() = header
and set(v) =
header <- v
base.NotifyPropertyChanged(<# x.Header #>)
member x.LoadAsync(panelId:int) = async {
let result = None
x.Header <- result }
If you can extend this minimal sample so that it exhibits the error, then I'm sure people will be able to help.

How to access a field of a type defined in an OCaml recursive module?

I am working on recursive modules in OCaml and I have some trouble accessing type fields.
If I try to do :
module A = struct type t = { name : string; } end
module A2 =
struct
include A
let getName (x:t) = x.name
end;;
Everything is alright. However, I need a more complex type, forcing me to define my type in a recursive module.
module rec B:Set.OrderedType =
struct
type t = {name: string; set : S.t}
let compare _ _ = 0
end
and S:Set.S = Set.Make (B);;
Everything still works perfectly. However, the following module is incorrect :
module B2 =
struct
include B
let get_name (x:t) = x.name
end;;
The returned error is "Unbound record field name". What is the problem ?
module rec B:Set.OrderedType =
Your recursive definition says that module B has the signature Set.OrderedType, which hides the definition of t and in this case, its projections. In Set.OrderedType, the type t is abstract, like this: type t;;.
If you want to show the definition of type t, it must be part of the signature. The first example works because you did not offer a signature for module A, so it was typed by default with a signature that exports everything.
The example below works for me with OCaml 4.02.1.
module rec B:
sig type t = { name:string ; set : S.t } val compare: t -> t -> int end
=
struct
type t = {name: string; set : S.t}
let compare _ _ = 0
end
and S:Set.S = Set.Make (B);;
The toplevel confirms the definition thus:
module rec B :
sig type t = { name : string; set : S.t; } val compare : t -> t -> int end
and S : Set.S

Cast MethodBase to RuntimeMethodInfo in F#

I want to cast MethodBase to RuntimeMethodInfo in order to retrieve the name and type of the arguments of reflected methods, and the returned type of those methods.
I can make a direct cast in Inmediate Window but have not found a way to make the cast with F#.
Why cast? You can call GetParameters() and all the other members you'd need on the MethodBase reference.
let methodInfo : MethodBase = //whatever
let firstParamName = methodInfo.GetParameters().[0].Name
EDIT (return types):
First, note that GetMethod returns MethodInfo, not MethodBase. You can't cast to RuntimeMethodInfo since, as others have noted, that is an internal type. But the ReturnType property is declared on MethodInfo, so all is well.
This therefore works, with the static type of methodInfo being MethodInfo:
let methodInfo = typeof<object>.GetMethod("ToString")
let returnTypeName = methodInfo.ReturnType.Name // "String"
Second, if you have a static reference to a MethodBase that you know is a MethodInfo, use the :?> operator. Example:
let toMethodInfo (mb : MethodBase) = mb :?> MethodInfo
On the other hand, if you're not sure about the object's actual type, you can use match:
let tryToMethodInfo (mb : MethodBase) =
match mb with
| :? MethodInfo as result -> Some result
| _ -> None
Finally, since you ask about "vice versa" in your comment: When you're going from a derived class to one of its base classes, which always succeeds, you don't need the question mark:
let toMethodBase (mi : MethodInfo) = mi :> MethodBase

Signature mismatch error in a complicated structure of modules and functors

I have built a complicated structure with modules, which has a recursion inside. The compilation gives me an error I can't solve (though I don't think it is really due to the recursion). Could anyone help?
First, an interface ZONE and a functor ZoneFunPrec are defined:
(* zone.ml *)
module type ZONE = sig
type prop
type info
type t
end
(* zoneFunPrec.ml *)
open Prop
open Zonesm
module ZoneFunPrec (Prop : PROP)(Prec: ZONESM with type prop = Prop.t) = struct
type prop = Prop.t
type info = { mark: int option; prec: Prec.t option }
type t = { prop: prop; info: info }
end
A functor ZonesFun and an interface ZONES whose element is a list of zones with same property:
(* zones.ml *)
open Prop
open Zone
module type ZONES = sig
type prop
type zone
type t
end
module ZonesFun (Prop: PROP) (Zone: ZONE with type prop = Prop.t) = struct
type prop = Prop.t
type zone = Zone.t
type t = | ZSbot | ZS of zone list
end
A functor ZonesmFun and an interface ZONESM whose element is a map from String into ZONES with same property:
(* zonesm.ml *)
open Prop
open Zone
open Zones
module SMap = Map.Make(String)
module type ZONESM = sig
type prop
type zones
type t
end
module ZonesmFun (Prop: PROP)
(Zone: ZONE with type prop = Prop.t)
(Zones: ZONES with type zone = Zone.t) = struct
type prop = Prop.t
type zones = Zones.t
type t = | Bot | ZSM of Zones.t SMap.t
end
And then, I try to build some modules from EEA whose interface is PROP:
(* modules.ml *)
open E_expression_abs
open Zone
open ZoneFunPrec
open Zones
open Zonesm
module EEA = E_expression_abs
module rec ZoneEEA : ZONE = ZoneFunPrec(EEA)(ZonesmEEA)
and ZonesEEA : ZONES = ZonesFun(EEA)(ZoneEEA)
and ZonesmEEA : ZONESM = ZonesmFun(EEA)(ZoneEEA)(ZonesEEA)
In my makefile, the order of compilation is same as the order I listed the files above. Then the compiler gives me an error in line module rec...:
File "domains/modules.ml", line 7, characters 45-54:
Error: Signature mismatch:
Modules do not match:
sig
type prop = ZonesmEEA.prop
type zones = ZonesmEEA.zones
type t = ZonesmEEA.t
end
is not included in
sig type prop = EEA.t type zones type t end
Type declarations do not match:
type prop = ZonesmEEA.prop
is not included in
type prop = EEA.t
So apparently, the compiler doesn't manage to know ZonesEEA.prop is actually EEA.t...
I am not good at recursive module typing but... I guess your example is simplified to the following
module type S = sig type t end
module rec R : S = (R : S with type t = int)
OCaml rejects this code due to signature mismatch. This is since R has incompatible types in the left and right hands of the equation. You must say:
module rec R : S with type t = int = (R : S with type t = int)
R must have the same module type in the both hands, since R is defined recursively.
If not recursive you can say:
module M = struct type t = int end
module N : S = (M : S with type t = int)
The module type of the left hand side of the equation can be more abstract than the right one.

Upcasting F# record created through reflection

I've been messing about with F# and it's Reflection, trying to create a Record type object dynamically from within F#, I got most of it working (as you can see below) but one thing - the record I create through reflection has type "obj" instead the one it should ("Person") and I can't seem to be able to upcast it in any way.
#light
type Person = {
Name:string;
Age:int;
}
let example = {Name = "Fredrik"; Age = 23;}
// example has type Person = {Name = "Fredrik"; Age = 23;}
let creator = Reflection.FSharpValue.PrecomputeRecordConstructor(example.GetType(),
System.Reflection.BindingFlags.Public)
let reflected = creator [| ("thr" :> obj); (23 :> obj) |]
// here reflected will have the type obj = {Name = "thr"; Age = 23;}
// Function that changes the name of a Person record
let changeName (x:Person) (name:string) =
{ x with Name = name }
// Works with "example" which is has type "Person"
changeName example "Johan"
// But not with "reflected" since it has type "obj"
changeName reflected "Jack" // Error "This expression has type obj but is here used with type Person. "
// But casting reflected to Person doesn't work either
(reflected :> Person) // Type constraint mismatch. The type obj is not compatible with
// type Person. The type 'obj' is not compatible with the type 'Person'.
// C:\Users\thr\Documents\Visual Studio 2008\Projects\
// Reflection\Reflection\Script.fsx 34 2 Reflection
Try using the other cast operator (as you're casting the other way this time)
So changeName (reflected :?> Person) "Jack"

Resources