Improve Error Reporting: Make FS0072 less intimidating.
What
The following code leads to the following error:
let bar foo =
let age = foo.Bar + 99
age * 2
Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
Why
The message is overly verbose and complicated, using words like "indeterminate" and so on. In reality, all we're trying to say is: "I couldn't infer what this type is! Please add an annotation to tell me directly.". We could also provide some guidance to explain that the compiler cannot generally infer types from C#.
How
How about:
Unable to infer the type of
foo. Please add a type annotation wherefoois declared e.g. (foo:string).
or
It is unclear what type
foois. Please add a type annotation wherefoois declared e.g. (foo:string).
We could also add some "background" information as well:
Unable to infer the type of
foo. Please add a type annotation wherefoois declared e.g. (foo:string). F# can only directly infer from member usage types that are defined in F#; if the type offoois defined in a C# library (including anything from the Base Class Library e.g. string), F# will not be able to infer it based on a member access.
Yes. I love type inferencing but I also love the intellisense you get with member access and I want to define types that support both. Now if I can't have both, the least the compiler can do is say so plainly so that I don't become confused and frustrated by the endless pursuit of a pipe dream.
@isaacabraham I agreed with you completely previously, but now I've changed my mind somewhat. The example code below seems it was misleading for you to suggest:
"F# can only directly infer from member usage types that are defined in F#; if the type of foo is defined in a C# library (including anything from the Base Class Library e.g. string), F# will not be able to infer it based on a member access."
ie. All the code below is in F# and still the type inferencing doesn’t work. Of course, your experience is much greater than mine and you may have other examples that invalidate my assessment.
I think the key to getting this error message right is prompting devs to stop wasting time pursuing the illusory goal of universal type inferencing.
How about:
“Due to limitations in F#’s type inferencing, especially when using member access, a type annotation may be needed prior to this point in the program.” ?
type Database = { Conn: SqliteConnection } with
static member Init =
let ret = { Conn = new SqliteConnection("Data Source=:memory:") }
ret.Conn.Open()
ret.Action "create table obs(ID int);"
ret
member this.Get sql =
let cmd = this.Conn.CreateCommand()
cmd.CommandText <- sql
cmd.ExecuteScalar()
member this.Action sql =
let cmd = this.Conn.CreateCommand()
cmd.CommandText <- sql
let x = cmd.ExecuteNonQuery()
()
let SqlGet db sql =
let cmd = db.Conn.CreateCommand()
cmd.CommandText <- sql
cmd.ExecuteScalar()
let SqlAction db sql =
let cmd = db.Conn.CreateCommand()
cmd.CommandText <- sql
cmd.ExecuteNonQuery() |> ignore
let db = Database.Init
let TestDb db =
//db.Action "insert into obs values(1)" !!! only compiles with db parameter having type annotation (db:Database)
//db.Get "select count(*) from obs"
SqlAction db "insert into obs values(1)" // Works just fine
SqlGet db "insert into obs values(1)"
printfn "result: %A" (TestDb db)