The blog of the F# team at Microsoft
IntelliSense is the identifier auto-completion facility in Visual Studio. As a developer, IntelliSense is critical to my productivity, as it allows me to easily work with thousands of functions from different namespaces and classes without having to constantly leave the editor to consult API documentation. In this blog post, I’ll show how the improvements to F# IntelliSense in Visual Studio 11 Beta will make day-to-day programming with F# easier and more enjoyable, and how F# IntelliSense, coupled with the new language feature of Type Providers, shapes the future of the experience developers have with all the world’s data.
When you think of IntelliSense, you may just think of an example like:
You can bring up a completion list explicitly by pressing the keyboard shortcut Ctrl-Space, or a completion list will appear automatically just by “dotting into” an object. The list of members appears, and the highlighted member shows more detail about that member. If you’re a developer, that is all familiar.
We’ve made a number of refinements to the F# IntelliSense experience in Visual Studio 11 that will really impact your productivity. First, the completion list now does “smart” choosing and filtering when you type a mixed-case partial identifier. For example, if I want “Console.WriteLine,” rather than arrow down through all the completions on “Console”:
or type a fully unique prefix like “Console.WriteL”:
I can now type “Console.WL”:
and quickly select WriteLine from the filtered list that contains only those identifiers with a capital “W” and a capital “L.”
This “smart filtering” feature can have a huge impact when working with certain APIs. What was that Form color change event I wanted again?
There are about 300 entries in that completion list; good luck scrolling through all those to find what you want. But if I know it was some kind of “changed” event, then I can type two more characters “Ch”:
…and now the filtering shows only methods with “Ch” in them, which is mostly the “XXXChanged” events.
And if instead I type “CoCh”:
Oh, right, it was “ForeColorChanged” I was looking for. “Smart-filtering” the completion list makes it dramatically easier to find the API you’re looking for.
F# now supports parameter help while you type. You can explicitly bring it up by pressing Ctrl-Shift-Space. For example, if I don’t recall what one particular exotic overload of String.Compare does, I can bring up the parameter help:
to learn about all the parameters for that overload. Note that my cursor was before the “1," the fourth parameter, and so the 4th parameter is bolded in the list. Parameter help automatically pops up when you type the open parenthesis:
and tracks parameters and selects overloads as you type more parameters:
In F# you can even use Ctrl-Shift-Space to get parameter help for one-argument functions that have no parentheses:
Parameter help makes it easy to select the right overload API and understand arguments without breaking the flow of typing code in the editor.
F# IntelliSense now has some contextual filtering based on the language construct you are using. For example, there are tons of completions under “System”:
but if I am opening a namespace in an “open” declaration:
F# will automatically filter the list down to just the namespaces and modules, since those are the only things that make sense in this context. Or if I’m updating a record, and bring up identifier completion suggestions with Ctrl-Space:
the list only contains the record field names that are valid at that location. There is still much more that can be done here, but F# continues to improve its ability to automatically filter completion lists based on context.
Though the aforementioned improvements to F# IntelliSense impact nearly every line of code you write, perhaps the most compelling thing is how IntelliSense interacts with the new F# language feature of Type Providers. Type Providers are assemblies you can reference that read an external schematized data source (like a database or web service) and surface it as though it were normal types in your F# program.
After watching “Attack of the Killer Tomatoes,” a friend made the offhand remark that no movie with “tomato” in its title is ever any good. Let’s try to verify that assertion programmatically!
I don’t know anything about web APIs for movies, but I do know that F# has an OData Type Provider, and that OData is a popular format for publishing lots of data on the web. If I Bing for “Netflix OData”, the first result contains the text:
Our OData service is located at odata.netflix.com/Catalog/
and now I am off and running. In less than five minutes, I have written:
open Microsoft.FSharp.Linq.NullableOperators
open Microsoft.FSharp.Data.TypeProviders
type Netflix = ODataService<"http://odata.netflix.com/catalog">
let ctxt = Netflix.GetDataContext()
let q = query {
for t in ctxt.Titles do
sortByNullableDescending(t.AverageRating)
where(t.Name.Contains("Tomato"))
}
for tomatoMovie in q do
printfn "%A %s" tomatoMovie.AverageRating tomatoMovie.Name
which produces the output:
3.9 Fried Green Tomatoes 3.1 Daft Punk: D.A.F.T.: A Story About Dogs, Androids, Firemen and Tomatoes 2.3 Automaton Transfusion<null> Tomato: Disc 4<null> Tomato: Disc 1
…demonstrating that good tomato movies do exist; “Fried Green Tomatoes” averages nearly four stars! (I’ve seen different subsets of results when running this query on different days; I’m unclear if the public Netflix endpoint gives full access to the entire catalog.) Let’s break down how F# IntelliSense helped me write code in an unfamiliar domain at every step of the way.
First off, type providers have “static parameters” that describe how they fetch their schematized data. F# gives parameter help for these static parameters, just like with method calls:
There are a number of optional parameters (which have argument identifiers starting with “?”, just as with optional parameters to methods), so I can just supply the URI of the Netflix OData service that I found and go from there.
When I browse into the Netflix data context, I see a few directions I can head:
“People” and “Genres” also seem like they may be interesting to explore at some point, but for the moment, I’m interested in their “Titles” catalog, which has info about lots of movies. There is a lot of information available for each movie title:
Looking down this list, it seems that these two are the ones I need:
I note that “AverageRating” is a Nullable<float>, which my intuition makes sense of—they probably don’t have rating information for every title in their catalog, so some are null. I’m not sure how to sort a nullable key, but once again IntelliSense comes to the rescue when I typed “sor” and pressed Ctrl-Space:
Yes, “sortByNullableDescending” is clearly what I need here to get the results in descending order by the “AverageRating” field. So I craft the query that filters just the titles I am interested in, in sorted order, and print out the results.
This is tremendously easy for me; the only part I needed to do outside the Visual Studio editor was the original Bing search to find the URI of a data source that had the information I needed. From there, I’m just typing code in the Visual Studio editor, using IntelliSense to steer me through all the new-to-me APIs. I did not have to search the web for detailed API information to find out how to use their web service, how to craft requests or parse responses. I did not have to use some kind of UI “wizard” interface to connect to the data source. I did not have to explicitly invoke a code generation tool to generate .NET object model classes and add that code to my project. I just pressed “dot”—and immediately I was able to explore the APIs to find the code I need to solve my problem.
I like to think that Type Providers turn IntelliSense into “Intelli-Dollars.” While there are perhaps a thousand classes in the .NET Framework, there are hundreds of thousands of schematized data types available for consumption in our information-rich world, available as web services, OData and RSS feeds, databases inside enterprises, in the Azure DataMarket, on your Sharepoint sites—the list goes on and on. Type providers create a simple bridge to make all these information sources immediately available programmatically within your statically-typed F# programming environment, browseable via IntelliSense. A world of data is at your fingertips with F#—grab Visual Studio 11 and glimpse the future of the developer experience in an information-rich world.
We’ve made a number of improvements to F# IntelliSense in Visual Studio 11. Smart-filtering, parameter help, and contextual-filtering make everyday coding simpler and more productive. Type Providers extend this rich IDE experience to the reach of all the data available around us.
Brian McNamaraVisual Studio F# Developer
Hi, great, congratulation to improvements!
And what about other features, which we know from C# like find all references or highlighting all occurrences of identifier when staying with cursor on it, or regions ? What are plans? I am not much humble now, I know. ;-)
Thanks
Please, no regions!
I prefer not to sweep code under the carpet.