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

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.

Related

Custom attribute on record fields F#

I am trying to declare a custom attribute in a record and trying to read it. It seems to be not working. Please advise.
// Custom Attribute for record fields
[<AttributeUsage(AttributeTargets.Field)>]
type Name(x: string) =
inherit Attribute()
member _.value = x
// Record type
type User =
{ [<Name("id")>]
Id: int
[<Name("email")>]
Email: string
[<Name("organization_id")>]
OrganizationId: option<string> }
// Trying to read the attribute. This is not working. I am getting <null> here.
let parse () =
FSharpType.GetRecordFields(typeof<User>)
|> Array.map (fun p -> p.Name, p.GetCustomAttribute(typeof<Name>, false))
|> Array.iter (fun (t, a) -> printfn "%s : %A" t a)
The below code fixes the problem. For more detailed answer, refer this link.
// Changing to property instead of field
[<AttributeUsage(AttributeTargets.Property)>]
type Name(x: string) =
inherit Attribute()
member _.value = x

How do I check 'T for types not being allowed to be null?

given
let inline deserialize<'t> x :'t option =
printfn "Attempting to deserialize %A" typeof<'t>.Name
try
JsonConvert.DeserializeObject<'t>(x)
|> Some
with ex ->
System.Diagnostics.Trace.WriteLine(sprintf "Error deserialization failed:%s" ex.Message)
None
is returning for example an obj list as null. FSharpList<_> is not allowed to be null. How can I, without knowing what 't is ask F# if the type I'm about to return supports null so that I can halt/throw/act accordingly? Is there a reflection flag or Microsoft.FSharp.Reflection... method for this?
The full answer involves checking if the type is a record (in which case null is never allowed), or if it's a union (in which case null is allowed if the type has a CompilationRepresentation CustomAttribute whose flags contain the UseNullAsTrueValue member (https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/core.compilationrepresentationflags-enumeration-%5Bfsharp%5D for more details)).
To answer the first question you can use the IsRecord function in the FSharpType module (https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/reflection.fsharptype-class-%5Bfsharp%5D) and to answer the second you can use a combination of the IsUnion function on that same module and CustomAttribute hunting.
In case the type is a union with UseNullAsTrueValue set, you should be good to go, just send the value along.
Best I can think of is to box the result (in case you are deserializing structs) and pattern match it with null:
let inline deserialize<'t> x :'t option =
printfn "Attempting to deserialize %A" typeof<'t>.Name
try
let obj = Newtonsoft.Json.JsonConvert.DeserializeObject<'t>(x)
match box obj with
| null -> None
| _ -> Some obj
with ex ->
System.Diagnostics.Trace.WriteLine(sprintf "Error deserialization failed:%s" ex.Message)
None
let r1 = deserialize<obj list> ("[1,2,3]") //val r1 : obj list option = Some [1L; 2L; 3L]
let r2 = deserialize<obj list> ("null") //val r2 : obj list option = None

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

Assign value to optional dictionary in Swift

I'm finding some surprising behavior with optional dictionaries in Swift.
var foo:Dictionary<String, String>?
if (foo == nil) {
foo = ["bar": "baz"]
}
else {
// Following line errors with "'Dictionary<String, String>?' does
// not have a member named 'subscript'"
foo["qux"] = "quux"
}
I've played with this a lot, trying to figure out what I might be missing, but nothing seems to make this code work as expected short of making the dictionary not optional. What am I missing?
The closest I can get is the following, but of course it's ridiculous.
var foo:Dictionary<String, String>?
if (foo == nil) {
foo = ["bar": "baz"]
}
else if var foofoo = foo {
foofoo["qux"] = "quux"
foo = foofoo
}
The lightbulb moment is when you realize that an Optional dictionary is not a Dictionary. An Optional anything is not that thing! It is an Optional!! And that's all it is. Optional is itself a type. An Optional is just an enum, wrapping the possible cases nil and some value. The wrapped value is a completely different object, stored inside.
So an Optional anything does not act like the type of that thing. It is not that thing! It is just an Optional. The only way to get at the thing is to unwrap it.
The same is true of an implicitly unwrapped Optional; the difference is just that the implicitly unwrapped Optional is willing to produce (expose) the wrapped value "automatically". But it is still, in fact, wrapped. And, as Bryan Chen has observed, it is wrapped immutably; the Optional is just holding it for you - it is not giving you a place to play with it.
you can use this code
if var foofoo = foo {
foofoo["qux"] = "quux"
foo = foofoo
} else {
foo = ["bar": "baz"]
}
with this code
var foo:Dictionary<String, String>? = Dictionary()
foo[""]=""
error: 'Dictionary<String, String>?' does not have a member named 'subscript'
foo[""]=""
^
the error message makes sense to me that Dictionary<String, String>? does not implement subscript method, so you need to unwrap it before able to use subscript.
one way to call method on optional is use ! i.e. foo![""], but...
var foo:Dictionary<String, String>? = Dictionary()
foo![""]=""
error: could not find member 'subscript'
foo![""]=""
~~~~~~~~^~~
whereas
var foo:Dictionary<String, String>? = Dictionary()
foo![""]
works
it is interesting these code failed to compile
var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo[""]=""
error: could not find an overload for 'subscript' that accepts the supplied arguments
foo[""]=""
~~~~~~~^~~
var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo.updateValue("", forKey: "")
immutable value of type 'Dictionary<String, String>' only has mutating members named 'updateValue'
foo.updateValue("", forKey: "")
^ ~~~~~~~~~~~
the last error message is most interesting, it is saying the Dictionary is immutable, so updateValue(forKey:) (mutating method) can't be called on it
so what happened is probably that the Optional<> store the Dictionary as immutable object (with let). So even Optional<> it is mutable, you can't modify the underlying Dictionary object directly (without reassign the Optional object)
and this code works
class MyDict
{
var dict:Dictionary<String, String> = [:]
subscript(s: String) -> String? {
get {
return dict[s]
}
set {
dict[s] = newValue
}
}
}
var foo:MyDict? = MyDict()
foo!["a"] = "b" // this is how to call subscript of optional object
and this lead me to another question, why Array and Dictionary are value type (struct)? opposite to NSArray and NSDictionary which are reference type (class)
This is because your Dictionary is optional. If it's nil, you won't add an entry to it.
You can do this way:
var dict: [String : String]?
if let dict = dict {
dict["key"] = "value" // add a value to an existing dictionary
} else {
dict = ["key" : "value"] // create a dictionary with this value in it
}
Or, if you are given an optional dictionary, for example HTTPHeaders - which in AlamoFire is a [String : String] dictionary - and you want to either add a value if it's non-nil, or create it with this value if it's nil, you could do like so:
let headers: HTTPHeaders? // this is an input parameter in a function for example
var customHeaders: HTTPHeaders = headers ?? [:] // nil coalescing
customHeaders["key"] = "value"
I tried this for Swift 3.1 and it worked:
if (myDict?[key] = value) == nil {
myDict = [key: value]
}

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