Compiler bug in F# 4? - f#

I have some F# 4.0 source that compiles fine in Debug, but not in Release.
There are no conditional defines, no changes in the inferred types, and nothing else I can think of, that can explain this difference to me.
Did I really stumble on a compiler bug?
This is a snippet with the problematic code.
let oldItems = userDisplayItems |> Seq.toList
for newItem in newItems do
match List.tryFind (fun (itemOfOld: UserDisplay.UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
| Some oldItem ->
The error message refers to the last use of "oldItems", before the "with" keyword at the end of the long line. The error message is:
Undefined value 'oldItems : UserDisplayItem list'
What!? oldItems is in plain sight a few lines above, and this compiles in Debug, so why not in Release? What does that error message actually mean?
UserDisplayItem is a simple class.
newItems is a ResizeArray of UserDisplayItem
I looked into the build history, and it compiled fine in Release when UserDisplayItem was an F# immutable record, and not a class.
Visual Studio 2015, F# 4.0, Any CPU, Release, .NET 4.5.2 targeted.
UPDATE:
The following is a complete example. You can create an F# console application, and paste this into Program.fs. I expect it will compile in Debug, but not Release.
open System.Collections.ObjectModel
type User = { Id: int }
[<AllowNullLiteral>]
type UserDisplayItem(id: int) =
let mutable id = id
member x.Id with get() = id and set(v) = id <- v
let userDisplayItems = new ObservableCollection<UserDisplayItem>()
let refreshList () =
let newItems = userDisplayItems
let oldItems = userDisplayItems |> Seq.toList
for newItem in newItems do
match List.tryFind (fun (itemOfOld: UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
| Some oldItem -> ()
| None -> ()
UPDATE 2 :
An even shorter sample.
type UserDisplayItem = { Id: int }
let refreshList () =
let newItems = new ResizeArray<UserDisplayItem>()
let oldItems = new ResizeArray<UserDisplayItem>() |> Seq.toList
for newItem in newItems do
match List.tryFind (fun (itemOfOld: UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
| Some oldItem -> ()
| None -> ()

Seems to be compiler bug (maybe related to 1020).
Could reproduce it with your code and F# version 14.0.23413.0
Now installed current preview which is F# version 14.0.23618.0 and it works.

Until you have the fix for this issue (see DAXaholic's answer for final fix), you can use this workaround, as explained by dsyme here:
https://github.com/Microsoft/visualfsharp/issues/759#issuecomment-162243299
The fix applied to the last sample in the question. First add this.
// do something that doesn't get optimized away
let workaround() = null |> ignore
and then only add a call to the function workaround in the right place(s), which is right before any loop where you get this error.
let oldItems = new ResizeArray<UserDisplayItem>() |> Seq.toList
workaround()
for newItem in newItems do
match List.tryFind (fun (itemOfOld: UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with

Related

TypeProvider giving unexpected dev-time behavior

I'm messing with my new statically parameterized type provider that provides a type with statically parameterized static methods. I haven't found documentation about this not being allowed. I'm getting some strange type provider behavior:
This type-provider-consuming code runs correctly but the intellisense gives crappy info. Members just keep getting added but never removed. The OpDef method shouldn't be available without the type parameters but intellisense kinda shows that as an option but still gives an error about a missing invoker if I actually refer to it. The required arguments to the provided OpDef method are not shown - always shows OpDef() -> unit instead of OpDef(suffix : string * id : string) -> unit that I currently expect to see (from this draft of the type provider). But as I've given all the arguments it really needs then it stops complaining.
Am I doing something that isn't supported or correct? Or, doubtfully, is there a bug in the f# stuff (and can you isolate where the bug is apparent)?
Here is the full implementation which uses the starter-pack files.
namespace OfflineSql
open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open System.Text.RegularExpressions
#nowarn "0025"
[<TypeProvider>]
type OfflineSqlProvider (config : TypeProviderConfig) as this =
inherit TypeProviderForNamespaces ()
let ns = "OfflineSql"
let asm = System.Reflection.Assembly.GetExecutingAssembly()
let buildDomainProvider nm schema invariants =
let parameterizedType = ProvidedTypeDefinition(asm, ns, nm, None)
let m = ProvidedMethod("OpDef", list.Empty, typeof<unit>, IsStaticMethod = true)
m.DefineStaticParameters(
[
ProvidedStaticParameter("script", typeof<string>)
],
fun nm [| :? string as operation |] ->
let results =
Regex.Matches(operation, "#([a-zA-Z_][a-zA-Z0-9_]*)") |> Seq.cast
|> Seq.map (fun (regmatch: Match) -> regmatch.Groups.[1].Captures.[0].ToString())
let ps = [ for a in results -> ProvidedParameter(a, typeof<string>) ] |> List.distinct
let opDef = ProvidedMethod(nm, ps, typeof<unit>, IsStaticMethod = true, InvokeCode = (fun _ -> <## () ##>))
opDef.AddXmlDoc("Constructs a guarded method for the operation's script")
parameterizedType.AddMember(opDef)
opDef)
let schemaProp =
ProvidedProperty("Schema", typeof<string>, IsStatic = true,
GetterCode = (fun _ -> <## schema ##>))
let invariantsProp =
ProvidedProperty("Invariants", typeof<string>, IsStatic = true,
GetterCode = (fun _ -> <## invariants ##>))
parameterizedType.AddMember(m)
parameterizedType.AddMember(schemaProp)
parameterizedType.AddMember(invariantsProp)
parameterizedType
do
let root = ProvidedTypeDefinition(asm, ns, "Domain", None)
root.DefineStaticParameters(
[
ProvidedStaticParameter("schema", typeof<string>)
ProvidedStaticParameter("invariants", typeof<string>, "")
],
fun nm [| :? string as schema ; :? string as invariants |] ->
buildDomainProvider nm schema invariants)
this.AddNamespace(ns, [ root ])
[<assembly:TypeProviderAssembly>]
do ()
This is directly related to known bugs with a fix:
https://github.com/Microsoft/visualfsharp/issues/642
https://github.com/Microsoft/visualfsharp/issues/640
https://github.com/Microsoft/visualfsharp/pull/705
Thanks to #gauthier on functionalprogramming.slack.com/fsharp for this find.

F# how to list functions with custom attribute?

I'm trying to create some kind of interface, but i cannot find how to use custom attributes in F# as MSDN only shows usage of CLR attributes. This is what i want to achieve:
open System
type Command (name : string) =
inherit Attribute()
member this.Name = name
[<Command("something")>]
let doSomething () =
Console.Write("I'm doing something")
[<Command("somethingElse")>]
let doSomethingElse () =
Console.Write("I'm doing something else")
[<EntryPoint>]
let main args =
let command = Console.ReadLine()
// find function where Command.Name = command and call it
Console.Read()
0
To extend on your answer, a more generic approach would be to get all the types and then filter the functions that have the attribute you're looking for (as your approach would break down once your application grows and no longer has everything "packed" into the Program class):
let getCommands () =
let types = Assembly.GetExecutingAssembly().GetTypes()
let commands =
types
|> Array.collect (fun typ -> typ.GetMethods())
|> Array.choose (fun mi ->
mi.CustomAttributes
|> Seq.tryFind (fun attr -> attr.AttributeType = typeof<Command>)
|> Option.map (fun attr -> attr, mi))
let commandsMap =
commands
|> Seq.map (fun (attr, mi) ->
let name =
let arg = attr.ConstructorArguments.[0]
unbox<string> arg.Value
name, mi)
|> Map.ofSeq
commandsMap
This gets all the functions from all the types in the executing assembly, then filters out everything that doesn't have command attribute. Then it builds a map where the key is the attribute argument and the value is the MethodInfo of the function.
Ok, found it.
Reflection.Assembly.GetExecutingAssembly().GetType("Program").GetMethods()
Program typename is not viable in code so it cannot be used in typeof<Program>, but this type exists and can be taken from assembly.

FSharp and upcasting to Interfaces seems redundant

I have the following code snippet using the reactive extensions:
let value : 't = ...
Observable.Create<'t>(fun observer ->
let subject = new BehaviorSubject<'t>(value)
let d0 = subject.Subscribe(observer)
let d1 = observable.Subscribe(subject)
new CompositeDisposable(d0, d1) :> IDisposable
)
This works. However if I drop the upcast to IDisposable then the code fails
to compile, citing ambiguous overloads. However CompositeDisposable is an
IDisposable. Why is the type inference engine failing to resolve this? Note I use this pattern almost all the time in C# returning CompositeDisposable from Observable.Create without having to upcast.
As #kvb said, functions don't support variance so upcast is required for interfaces and subclasses.
Here is a small example demonstrating the behavior with subclasses:
type A() =
member x.A = "A"
type B() =
inherit A()
member x.B = "B"
let f (g: _ -> A) = g()
let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // fails
If function f is written by you, adding type constraints could help:
// This works for interface as well
let f (g: _ -> #A) = g()
let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // works
Otherwise, you have to do a litle upcast as your example described.
EDIT: Since F# 6.0, auto-upcasting of interfaces and subclasses is now supported by default.

F# interactive window problem

i am getting this error in the interactive window on http://www.tryfsharp.org. It works fine in visual studio and im not sure how to tackle it.Any help would be appreciated
let randomNumberGenerator count =
let rnd = System.Random()
List.init count (fun numList -> rnd.Next(0, 100))
let rec sortFunction = function
| [] -> []
| l -> let minNum = List.min l in
let rest = List.filter (fun i -> i <> minNum) l in
let sortedList = sortFunction rest in
minNum :: sortedList
let List = randomNumberGenerator 10
let sortList = sortFunction List
printfn "Randomly Generated numbers in a NON-SORTED LIST\n"
printfn "%A" List
printfn "\nSORTED LIST \n"
printfn "%A \n" sortList
error FS0039: The field, constructor or member 'init' is not defined
Aprreciate your help
You should be getting the error only when you run the code for the second time and it shoul behave the same in the TryF# console as well as locally in Visual Studio.
The problem is that you're declaring a value named List:
let List = randomNumberGenerator 10
which hides the standard module List. After you declare the value List.init tries to access a member of this List value instead of accessing a function in the standard List module.
There is a good reason for naming conventions, such as using lowercase for local variable names :-)

Observable from Sequence in F#

Is there a way to creating an observable from a sequence in F#?
The required behaviour is that an observer subscribing to the resulting observable receives all the values of the sequence one at a time.
Edit: The question can be framed as: Is there an equivalent to Rx.Observable.FromArray([1,2,3]) as shown here in F#?
Edit 2: Thanks everyone. It took me some time to find the answer, only to find that desco has answered already. For the sake of completeness, here is how it works:
//Using the Reactive Framework.
//References to System.CoreEx.dll and System.Reactive.dll are needed.
open System.Linq
let observable = Observable.ToObservable [1..10]
let odds = observable |> Observable.filter (fun i -> i%2=1)
let disp = odds.Subscribe (fun i -> printfn "%d" i)
disp.Dispose ()
Just in case you wanted to avoid the additional dependency, it is actually quite easy to implement the behavior using F# events and Observable.guard function that I already used in another answer here at StackOverflow.
Here is the implementation together with a brief example:
module Observable =
let ofSeq s =
let evt = new Event<_>()
evt.Publish |> Observable.guard (fun o ->
for n in s do evt.Trigger(n))
[ 1 .. 10 ] |> Observable.ofSeq
|> Observable.filter (fun n -> n%2 = 0)
|> Observable.add (printfn "%d")
And for completeness, the implementation of Observable.guard looks like this:
/// Creates an observable that calls the specified function after someone
/// subscribes to it (useful for waiting using 'let!' when we need to start
/// operation after 'let!' attaches handler)
let guard f (e:IObservable<'Args>) =
{ new IObservable<'Args> with
member x.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
Is System.Reactive.Linq.Observable.ToObservable(this IEnumerable source) located in System.Reactive.dll the thing your wanted?
Yoou can try Reactive Extensions. Please refer to the following blog entry which might help you a lot.
http://www.navision-blog.de/2009/10/20/iobservableiobserver-using-the-reactive-framework-with-f/

Resources