It would definitely be helpful to have better error messages (we'll work on this for a future release).

Even for simple examples, the compiler is doing many (often many, many) steps, and so I think 'showing the steps' is likely to be even less comprehensible than some of the inscrutable error messages. Apart from the low-hanging fruit of improving the English text of some typechecking error messages, I think that a more helpful type-inference-diagnostic-system would take many man-years of effort to create. It is not a simple problem, and it is not a new problem, and the research on this front does not look too promising to me.

Some of the messages you mention are due to bad parsing or indentation-misunderstandings. Those are easier for us to fix/improve in the compiler, and I have somewhat realistic hopes that those may improve markedly by the time F# ships in VS 2010.

In terms of pragmatic advice today, your best bets are

  • For type-inference errors, try to localize the problem by adding type annotations to nearby identifiers/expressions (and use the hover-tooltips to see what types are being inferred). A common cycle is "get an error", "hover-inspect", "add a few annotations (e.g. change 'x' to '(x:int)')", "discover the real problem", "fix the problem", "(optionally) remove the redundant just-added annotations". Also, when about to author a big function (especially when recursive) that you're not quite sure how to implement yet until you start typing, if you know the type, it can be helpful to specify it up front (e.g. "let rec F (x:Foo) (y:Bar) : ResultType = ...") to guide the typechecking along the way as you write the body, and then once you've got the code working, optionally remove the annotations.
  • For parse errors (often "unexpected Blah..." or "unmatched Blah...") try adding parentheses or 'begin'/'end' pairs around expressions to disambiguate things.
  • Be wary of overreacting to real-time squiggles as you are writing code. If you are in the midst of writing a function/expression but have not finished, weird things may happen due to the incomplete code. It is sometimes better to finish typing the block/function/expression you're typing and then go back and check the errors.

and of course, when all else fails

  • ask a question on the forum :)
By on 2/1/2009 12:08 PM ()

Brian,Good tips. I'd like to add:Try to separate subfunctions in local let bindings. Check that these local functions have the type you expect. Iterate for every subfunction. Optionally remove the local lets. (Usually I don't cause they also improve the readability, especially with arguments to map, fold and friends. I'm in the habit now of using anonymous functions only for the simplest).Kurt

By on 2/3/2009 5:33 AM ()

Sounds like all of the things I've been trying whenever problems arise :) It usually works pretty well, but sometimes I still scratch my head over these problems. Anyway, mostly I just wanted to throw this out there, it's highly unlikely I'll come across anything groundbreaking that someone on the team hasn't already thought of, but never hurts :P

On that note though, I actually have two more suggestions. First is to display variable names on hover tooltips of function invocations. E.g. if I say

let rec f x : int =
f 7

And I hover over either of the f's, Instead of just saying "f : int -> int" it would be nice if it said "f : (x:int) -> int". Currying and anonymous functions probably present some difficulties here, but it seems like it would be possible to get it to work in the simple case.

The second suggestion is that sometimes output in the FSI window seems to be out of order. I'm not sure what's going on here, but I notice it most often when an exception occurs. I can have a function invocation sequence with a bunch of printfs, somewhere an exception is thrown, and the location that the exception message is printed to the FSI window relative to the printf statements does not seem to be in sequence with where I know the exception occured. If needed I can try to produce a sample to illustrate this.

I suspect it might be due to the fact that there is some automatic parallelization occuring, and so the code does not actually always execute in the order it's written in the code. It makes debugging exceptions sometimes difficult though, especially if you've added printfs specifically to try to diagnose when / and with what variable states the exception occurs in

By on 2/1/2009 6:36 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper