October 2008

October 31, 2008

Thanks again to Augusto Gonçalves, from our DevTech Americas team, for providing the original VB.NET code for this sample, as well as helping investigate an issue I faced during implementation.

When I saw a recent reply to a developer, showing how to implement a custom object snap in AutoCAD using .NET, I had a really strong sense of nostalgia: it reminded me of a couple of early samples I contributed to the ObjectARX SDK: the "third" sample, which showed how to create a custom osnap that snapped to a third of the way along a curve, and "divisor" which generalised the approach to fractions of any size and was my first real attempt at using C++ templates. Ah, the memories. The samples were retired from this year's SDK, but were still included up to and including the ObjectARX SDK for AutoCAD 2008.

Anyway, the code Augusto sent was very familiar, and it turns out he based it on some documentation that was probably, in turn, based on my C++ sample. So it has come full circle. :-)

One thing I hadn't realised until I saw Augusto's email was that the ability to define custom object snaps had been exposed through .NET.

Here's the C# code that implements a new "quarter" object snap, which snaps to 1/4 and 3/4 along the length of a curve.

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.GraphicsInterface;

[assembly:ExtensionApplication(

typeof(OsnapApp.CustomOSnapApp))

]

namespace OsnapApp

{

// Register and unregister custom osnap

publicclassCustomOSnapApp : IExtensionApplication

{

privateQuarterOsnapInfo _info =

newQuarterOsnapInfo();

privateQuarterGlyph _glyph =

newQuarterGlyph();

privateCustomObjectSnapMode _mode;

publicvoid Initialize()

{

// Register custom osnap on initialize

_mode =

newCustomObjectSnapMode(

"Quarter",

"Quarter",

"Quarter of length",

_glyph

);

// Which kind of entity will use the osnap

_mode.ApplyToEntityType(

RXObject.GetClass(typeof(Polyline)),

newAddObjectSnapInfo(_info.SnapInfoPolyline)

);

_mode.ApplyToEntityType(

RXObject.GetClass(typeof(Curve)),

newAddObjectSnapInfo(_info.SnapInfoCurve)

);

_mode.ApplyToEntityType(

RXObject.GetClass(typeof(Entity)),

newAddObjectSnapInfo(_info.SnapInfoEntity)

);

// Activate the osnap

CustomObjectSnapMode.Activate("_Quarter");

}

// Unregister custom osnap on terminate

publicvoid Terminate()

{

CustomObjectSnapMode.Deactivate("_Quarter");

}

}

// Create new quarter object snap

publicclassQuarterGlyph : Glyph

{

privatePoint3d _pt;

publicoverridevoid SetLocation(Point3d point)

{

_pt = point;

}

publicoverridevoid ViewportDraw(ViewportDraw vd)

{

int glyphPixels =

CustomObjectSnapMode.GlyphSize;

Point2d glyphSize =

vd.Viewport.GetNumPixelsInUnitSquare(_pt);

// Calculate the size of the glyph in WCS

// (use for text height factor)

// We'll add 20% to the size, as otherwise

// it looks a little too small

double glyphHeight =

(glyphPixels / glyphSize.Y) * 1.2;

string text = "¼";

// Translate the X-axis of the DCS to WCS

// (for the text direction) and the snap

// point itself (for the text location)

Matrix3d e2w = vd.Viewport.EyeToWorldTransform;

Vector3d dir = Vector3d.XAxis.TransformBy(e2w);

Point3d pt = _pt.TransformBy(e2w);

// Draw the centered text representing the glyph

vd.Geometry.Text(

pt,

vd.Viewport.ViewDirection,

dir,

glyphHeight,

1,

0,

text

);

}

}

// OSnap info

publicclassQuarterOsnapInfo

{

publicvoid SnapInfoEntity(

ObjectSnapContext context,

ObjectSnapInfo result)

{

// Nothing here

}

publicvoid SnapInfoCurve(

ObjectSnapContext context,

ObjectSnapInfo result

)

{

// For any curve

Curve cv = context.PickedObject asCurve;

if (cv == null)

return;

double startParam = cv.StartParam;

double endParam = cv.EndParam;

// Add osnap at first quarter

double param =

startParam + ((endParam - startParam) * 0.25);

Point3d pt = cv.GetPointAtParameter(param);

result.SnapPoints.Add(pt);

// Add osnap at third quarter

param =

startParam + ((endParam - startParam) * 0.75);

pt = cv.GetPointAtParameter(param);

result.SnapPoints.Add(pt);

if (cv.Closed)

{

pt = cv.StartPoint;

result.SnapPoints.Add(pt);

}

}

publicvoid SnapInfoPolyline(

ObjectSnapContext context,

ObjectSnapInfo result)

{

// For polylines

Polyline pl = context.PickedObject asPolyline;

if (pl == null)

return;

// Get the overall start and end parameters

double plStartParam = pl.StartParam;

double plEndParam = pl.EndParam;

// Get the local

double startParam = plStartParam;

double endParam = startParam + 1.0;

while (endParam <= plEndParam)

{

// Calculate the snap point per vertex...

// Add osnap at first quarter

double param =

startParam + ((endParam - startParam) * 0.25);

Point3d pt = pl.GetPointAtParameter(param);

result.SnapPoints.Add(pt);

// Add osnap at third quarter

param =

startParam + ((endParam - startParam) * 0.75);

pt = pl.GetPointAtParameter(param);

result.SnapPoints.Add(pt);

startParam = endParam;

endParam += 1.0;

}

}

}

}

Some comments on the implementation:

There's a blank callback that is the base implementation for entities

We then override that for all Curve objects, using some code to divide a curve into quarters

We do yet another implementation for all Polyline objects (which are Curves, but we want to treat them as a special case)

For Polylines we snap within segments

We could have implemented this by retrieving each segment and dividing that into quarters

Instead I chose to rely on the fact that a Polyline's parameter is a "whole number" at each vertex, which means the code is the same for any kind of segment

In my original sample I adjusted the position of the text, to centre it on the snap point

In this example I haven't done this, as when I looked at the code it wasn't accurate - when you zoomed in the text appeared in the wrong position

As we're just using a single character (¼) as our glyph, this isn't a significant problem

Here's what happens when we load our module and try snapping to a line inside AutoCAD:

Update:

I've just made a few minor changes to the above code to update it to work with AutoCAD 2012 (and maybe this is needed for prior versions, too - I'm not sure when the behaviour changed).

October 27, 2008

This post continues on from Part 1 of this series. You'll find much of this content has been used before in thesepreviousposts, although post does include content updated for F# 1.9.6.2 (the September 2008 CTP).

The first thing we need to do is – as with any AutoCAD .NET project – add project references to AutoCAD’s managed assemblies, acmgd.dll and acdbmgd.dll. With F#’s integration into Visual Studio 2008 you do this in exactly the same way as you would for a C# or VB.NET project, by selecting Project -> Add Reference... from the pull-down menu or right-clicking the project inside the Solution Explorer and selecting Add Reference... from the context menu.

Here you then browse to the AutoCAD 2009 folder and filter for *mgd* files (at least this is the way I do it), and select the two we want:

Figure 10 – Adding project references to AutoCAD’s managed assemblies

Now we need to make sure AutoCAD recognizes a module within a namespace, from which it is able to load commands. I found – by using .NET Reflector – that the appropriate structure is to declare your functions as the contents of a module (this needs to come after the #light directive):

module MyNamespace.MyApplication

Next we’re going to specify the .NET namespaces we’ll be using inside this application:

Most of this section should be familiar to anyone who has used the .NET API to AutoCAD – there are really only a couple of ideas that may need explanation:

The use keyword is just like C#’s using – but we don’t use curly braces to define scope. The scope gets defined as the remainder of the function in which the use statement has been used. Once the function completes the used object will be disposed of automatically.

We’re using the dynamic cast operator (:?>) to specify the type of object we’re opening with GetObject(). This operator involves a query to check whether this is valid – if we wanted to do a static cast we could use :> instead.

Now we have opened our modelspace and paperspace objects (we could go further and open other layouts, but – once again – I’ll leave that as a follow-on exercise for those who feel the need to do it :-) we can look at the code we need to extract the text from our database-resident objects.

Let’s start by defining a local function which takes an ObjectId and uses it to open an object, and for a textual object (DBText or MText) it will return its contents:

// A function that accepts an ObjectId and returns

// a list of the text contents, or an empty list.

// Note the valid use of tr, as it is in scope

let extractText x =

let obj = tr.GetObject(x,OpenMode.ForRead)

match obj with

| :? MText as m -> m.Contents

| :? DBText as d -> d.TextString

| _ ->""

Once again we haven’t specified the type of the argument – this will be inferred by the system – but we could very easily do so. We’re using the transaction previously started in the listWords function – the reason for defining extractText local to it – which is quite valid, as it’s in scope.

After opening the object for read from its ID we’re using pattern-matching – a technique that is a huge timesaver for functional programmers – to check on the type of the object and return the appropriate property of it. This is just like a much cleaner switch statement in C#.

We could choose to match against any property of the object, but in our case we want to check the type, so use this operator: :?. The as keyword is a syntactic shortcut that defines a value we can then use to easily dereference the object and get at its properties and methods.

The final clause of the three is a wildcard: it will match all object that are not DBText or MText objects and return an empty string.Now that we can get at the contents of our text objects, let’s write a quick recursive function to display the contents of the final list of words inside AutoCAD:

// A recursive function to print the contents of a list

letrec printList x =

match x with

| h :: t -> ed.WriteMessage("\n" + h); printList t

| [] -> ed.WriteMessage("\n")

Once again, this is a local function, so using our Editor (accessed via the ed value) is quite valid. We’re using pattern-matching again to create a recursive function (indicated via the rec keyword and then the recursive call to printList). When we find an empty list ([]) we simply print a newline, but when we find a list with a head (h) and a tail (t – which may well end up being empty, by the way, we’ll find out the next time we recurse into printList), we print the head and recurse with the tail.

One thing to look out for when defining recursive functions: they really need to be defined as tail-recursive, which means that the recursive call should be the last operation. This allows the compiler to perform tail call optimization, which replaces the declared recursion with a simply while loop inside the generated code.

Why does this matter? Well, calling a function does have some overhead, as stack space is required to store information about the function and its arguments, so if we have a list of 10,000 words to print and the function hasn’t been optimized, the recursion could cause problems. (The number could be 100,000 or 1,000,000, but the point is there is a number).

The above code does get optimized properly (even if the pattern for the empty list comes after the recursive call – it’s really about the position of the recursive call in the clause that recurses, rather than the overall program), and this is easy to check with .NET Reflector. In fact there’s an article on my blog covering just this:

A couple of comments on the above plumbing: ms and ps are both IEnumerable types (which correspond to the Seq class in F#), but are both untyped. This means we have to cast them, to be able to access them properly from F#, and then we can simply call Seq.to_list to get the contents into a list. The @ operator appends the list of ObjectIds of objects in modelspace with those in paperspace, and we then pipe the list into a call to List.map which runs our extractText function on all the objects in the combined list. The results get piped into our sortedWords function, and we finally print them to the command-line using our recursive printList function.

Finally, we’re just going to call commit on our transaction object, as for performance reasons this is currently best practice:

// As usual, committing is cheaper than aborting

tr.Commit()

That’s it for our first AutoCAD application. Let’s see the entire listing:

As mentioned previously, pure functional code lends itself to be run on multiple computing cores in parallel. While the tools aren’t yet there to make this happen automatically – via implicit parallelization – this is a likely outcome, over the coming years. For now we have the possibility of writing code that uses explicit parallelization – where we specify the tasks we know can be executed at the same time and leave the language and runtime to take care of the coordination.

There are a couple of ways to do this, right now: the Parallel Extensions to .NET (also in CTP stage and due for inclusion in Visual Studio 2010) provide a number of parallel constructs, such as parallel versions of for and while loops. F# currently provides the capability to define and execute Asynchronous Workflows, which is what we’re going to look at now.

First, let’s take a look at a sample application that we’re going to parallelize. This sample goes through and queries, via RSS, the latest posts on a number of different blogs. It then generates AutoCAD geometry – text with a hyperlink – for each of these posts. So we turn AutoCAD into an RSS reader, for all intents and purposes.

80 ("//*[name()='description' or name()='subtitle' or name()='summary']")

81-> n.InnerText ]

82

83// A local function to filter out duplicate entries in

84// a list, maintaining their current order.

85// Another way would be to use:

86// Set.of_list lst |> Set.to_list

87// but that results in a sorted (probably reordered) list.

88

89letrec nub lst =

90match lst with

91 | a::[] -> [a]

92 | a::b ->

93if a = List.hd b then

94 nub b

95else

96 a::nub b

97 | [] -> []

98

99// Filter the links to get (hopefully) the same number

100// and order as the titles and descriptions

101

102let real = List.filter (fun (x:string) -> x.Length > 0)

103let lnks = real links |> nub

104

105// Return a link to the overall blog, if we don't have

106// the same numbers of titles, links and descriptions

107

108let lnum = List.length lnks

109let tnum = List.length titles

110let dnum = List.length descs

111

112if tnum = 0 || lnum = 0 || lnum <> tnum || dnum <> tnum then

113 [(name,url,url)]

114else

115 List.zip3 titles lnks descs

116with _ -> []

117

118// For a particular (name,url) pair,

119// create an AutoCAD HyperLink object

120

121let hyperlink (name,url,desc) =

122let hl = new HyperLink()

123 hl.Name <- url

124 hl.Description <- desc

125 (name, hl)

126

127// Download an RSS feed and return AutoCAD HyperLinks for its posts

128

129let hyperlinksSync (name, url, feed) =

130let xml = httpSync feed

131let tl = titlesAndLinks (name, url, xml)

132 List.map hyperlink tl

133

134// Now we declare our command

135

136 [<CommandMethod("rss")>]

137let createHyperlinksFromRss() =

138

139let starttime = System.DateTime.Now

140

141// Let's get the usual helpful AutoCAD objects

142

143let doc =

144 Application.DocumentManager.MdiActiveDocument

145let ed = doc.Editor

146let db = doc.Database

147

148// "use" has the same effect as "using" in C#

149

150use tr =

151 db.TransactionManager.StartTransaction()

152

153// Get appropriately-typed BlockTable and BTRs

154

155let bt =

156 tr.GetObject

157 (db.BlockTableId,OpenMode.ForRead)

158 :?> BlockTable

159let ms =

160 tr.GetObject

161 (bt.[BlockTableRecord.ModelSpace],

162 OpenMode.ForWrite)

163 :?> BlockTableRecord

164

165// Add text objects linking to the provided list of

166// HyperLinks, starting at the specified location

167

168// Note the valid use of tr and ms, as they are in scope

169

170let addTextObjects (pt : Point3d) lst =

171// Use a for loop, as we care about the index to

172// position the various text items

173

174let len = List.length lst

175for index = 0 to len - 1 do

176let txt = new DBText()

177let (name:string,hl:HyperLink) = List.nth lst index

178 txt.TextString <- name

179let offset =

180if index = 0 then

181 0.0

182else

183 1.0

184

185// This is where you can adjust:

186// the initial outdent (x value)

187// and the line spacing (y value)

188

189let vec =

190new Vector3d

191 (1.0 * offset,

192 -0.5 * (Int32.to_float index),

193 0.0)

194let pt2 = pt + vec

195 txt.Position <- pt2

196 ms.AppendEntity(txt) |> ignore

197 tr.AddNewlyCreatedDBObject(txt,true)

198 txt.Hyperlinks.Add(hl) |> ignore

199

200// Here's where we use the varous functions

201// we've defined

202

203let links =

204 List.map hyperlinksSync feeds

205

206// Add the resulting objects to the model-space

207

208let len = List.length links

209for index = 0 to len - 1 do

210

211// This is where you can adjust:

212// the column spacing (x value)

213// the vertical offset from origin (y axis)

214

215let pt =

216new Point3d

217 (15.0 * (Int32.to_float index),

218 30.0,

219 0.0)

220 addTextObjects pt (List.nth links index)

221

222 tr.Commit()

223

224let elapsed =

225 System.DateTime.op_Subtraction(System.DateTime.Now, starttime)

226

227 ed.WriteMessage("\nElapsed time: " + elapsed.ToString())

I have numbered the lines, to make it easier for us to talk about the changes that are needed to introduce parallelism into this sample. Both synchronous and asynchronous versions of this application are available on my blog.

I won’t go through the above code in detail, here: firstly, it’s not intended as a perfect implementation of an RSS consumer – there are too many variations in the way RSS is implemented by different sites, so I know for a fact that this code will not work for certain blogs – it’s really intended to be an example of a – potentially time-consuming – asynchronous (in this case network-based) activity that is easy to run in parallel.

A word of caution: AutoCAD is not thread-safe – it is very much a single-threaded application – so we need to coordinate the results of these tasks prior to making the changes to the AutoCAD database. Luckily F# makes this very easy for us to do, so that’s really not a problem.

Here is the updated source that makes use of Asynchronous Workflows, with the modified/new lines highlighted in red (with a grey background for those reading this in black & white :-):

80 ("//*[name()='description' or name()='subtitle' or name()='summary']")

81-> n.InnerText ]

82

83// A local function to filter out duplicate entries in

84// a list, maintaining their current order.

85// Another way would be to use:

86// Set.of_list lst |> Set.to_list

87// but that results in a sorted (probably reordered) list.

88

89letrec nub lst =

90match lst with

91 | a::[] -> [a]

92 | a::b ->

93if a = List.hd b then

94 nub b

95else

96 a::nub b

97 | [] -> []

98

99// Filter the links to get (hopefully) the same number

100// and order as the titles and descriptions

101

102let real = List.filter (fun (x:string) -> x.Length > 0)

103let lnks = real links |> nub

104

105// Return a link to the overall blog, if we don't have

106// the same numbers of titles, links and descriptions

107

108let lnum = List.length lnks

109let tnum = List.length titles

110let dnum = List.length descs

111

112if tnum = 0 || lnum = 0 || lnum <> tnum || dnum <> tnum then

113 [(name,url,url)]

114else

115 List.zip3 titles lnks descs

116with _ -> []

117

118// For a particular (name,url) pair,

119// create an AutoCAD HyperLink object

120

121let hyperlink (name,url,desc) =

122let hl = new HyperLink()

123 hl.Name <- url

124 hl.Description <- desc

125 (name, hl)

126

127// Use asynchronous workflows in F# to download

128// an RSS feed and return AutoCAD HyperLinks

129// corresponding to its posts

130

131let hyperlinksAsync (name, url, feed) =

132 async { let! xml = httpAsync feed

133let tl = titlesAndLinks (name, url, xml)

134return List.map hyperlink tl }

135

136// Now we declare our command

137

138 [<CommandMethod("arss")>]

139let createHyperlinksFromRssAsync() =

140

141let starttime = System.DateTime.Now

142

143// Let's get the usual helpful AutoCAD objects

144

145let doc =

146 Application.DocumentManager.MdiActiveDocument

147let ed = doc.Editor

148let db = doc.Database

149

150// "use" has the same effect as "using" in C#

151

152use tr =

153 db.TransactionManager.StartTransaction()

154

155// Get appropriately-typed BlockTable and BTRs

156

157let bt =

158 tr.GetObject

159 (db.BlockTableId,OpenMode.ForRead)

160 :?> BlockTable

161let ms =

162 tr.GetObject

163 (bt.[BlockTableRecord.ModelSpace],

164 OpenMode.ForWrite)

165 :?> BlockTableRecord

166

167// Add text objects linking to the provided list of

168// HyperLinks, starting at the specified location

169

170// Note the valid use of tr and ms, as they are in scope

171

172let addTextObjects (pt : Point3d) lst =

173// Use a for loop, as we care about the index to

174// position the various text items

175

176let len = List.length lst

177for index = 0 to len - 1 do

178let txt = new DBText()

179let (name:string,hl:HyperLink) = List.nth lst index

180 txt.TextString <- name

181let offset =

182if index = 0 then

183 0.0

184else

185 1.0

186

187// This is where you can adjust:

188// the initial outdent (x value)

189// and the line spacing (y value)

190

191let vec =

192new Vector3d

193 (1.0 * offset,

194 -0.5 * (Int32.to_float index),

195 0.0)

196let pt2 = pt + vec

197 txt.Position <- pt2

198 ms.AppendEntity(txt) |> ignore

199 tr.AddNewlyCreatedDBObject(txt,true)

200 txt.Hyperlinks.Add(hl) |> ignore

201

202// Here's where we do the real work, by firing

203// off - and coordinating - asynchronous tasks

204// to create HyperLink objects for all our posts

205

206let links =

207 Async.Run

208 (Async.Parallel

209 [ for (name,url,feed) in feeds ->

210 hyperlinksAsync (name,url,feed) ])

211 |> Array.to_list

212

213// Add the resulting objects to the model-space

214

215let len = List.length links

216for index = 0 to len - 1 do

217

218// This is where you can adjust:

219// the column spacing (x value)

220// the vertical offset from origin (y axis)

221

222let pt =

223new Point3d

224 (15.0 * (Int32.to_float index),

225 30.0,

226 0.0)

227 addTextObjects pt (List.nth links index)

228

229 tr.Commit()

230

231let elapsed =

232 System.DateTime.op_Subtraction(System.DateTime.Now, starttime)

233

234 ed.WriteMessage("\nElapsed time: " + elapsed.ToString())

Let's look at the specific changes:

Line 7 has been changed to allow both files to be part of the same project.

Lines 45-50 implement a new, asynchronous function to download content from a URL. The async primitive coordinates a set of activities, while the let! and use! statements indicate that these right-hand side of the operation will be run asynchronously and that the results should be bound to the left. So here we're only getting the HTTP content asynchronously - the reading is to occur synchronously.

Lines 131-134 implement an asynchronous task that not only calls our asynchronous HTTP request function but coordinates the creation of AutoCAD geometry based on the contents received.

Lines 207-211 are where we make use of these newly-defined functions by firing them off in parallel (the framework will use the processing capabilities available to it to execute the tasks as efficiently as possible) and coordinating the results into a single array, which we convert to a list to maintain our previous processing code.

When we run either the RSS or ARSS (its asynchronous version), we should see this kind of result:

Figure 11 – AutoCAD geometry created from our RSS feeds

Now let’s see how they compare in terms of performance. I executed the RSS and ARSS commands a number of times in sequence to get a feel for relative performance.

Command: rss

Elapsed time: 00:00:08.1958195

Command: arss

Elapsed time: 00:00:02.2802280

Command: rss

Elapsed time: 00:00:04.1264126

Command: arss

Elapsed time: 00:00:03.6343634

Command: rss

Elapsed time: 00:00:03.6563656

Command: arss

Elapsed time: 00:00:01.9891989

Command: rss

Elapsed time: 00:00:03.1673167

Command: arss

Elapsed time: 00:00:03.1223122

Command: rss

Elapsed time: 00:00:05.7375737

Command: arss

Elapsed time: 00:00:01.9391939

The first execution time is much higher due to an initial startup penalty or the need to fill some page cache with the content. On average, though, the asynchronous code runs in 60-70% of the time needed by the synchronous version. The code was run a dual-core notebook: some of the performance will be related to using both cores, but most will be due to the parallelization of asynchronous tasks that have some latency due to use of the network. With more accesses in parallel you would see this performance difference become increasingly exaggerated.

October 24, 2008

AU Unplugged is the unconference component of Autodesk University. The sessions have been submitted and the voting is now on: based on external feedback the event organizers will schedule the most interesting classes at this year's event.

Last year I held a poorly publicized (and therefore poorly attended :-) session on comparative AutoCAD development tools/technologies, but I've decided not to repeat that this year, and hang on the coat-tails of one of my team...

Stephen Preston, the manager of DevTech Americas and our worldwide platform products technical lead, is planning the following session:

AutoCAD .NET: Help Us to Help You – Stephen Preston, DevTech Americas Manager

Come and talk about the resources available to help you work with the AutoCAD .NET API. What works for you? What is missing? What more do you need to make your AutoCAD .NET programming successful? Suitable for programmers of all skill levels.

If you think this session is interesting (and I know it will be) please vote for it via this survey (scroll right down to the bottom of the page to find it - it's the second from last session listed).

I expect a number of interested parties to attend this session (assuming it fits into people's schedules), including people responsible for writing API reference/developer guide material, API development, tool development (what do you need from an AutoCAD .NET Wizard? That's likely to be one of the topics covered...), and API blogging (yes, I plan on being there).

If the session gets approved I'll follow up with a post nearer the time to let people know when and where it's being be held.

F# is a new programming language from Microsoft, due to become a first-class .NET citizen (joining its siblings C# and VB.NET) and fully integrated with Visual Studio 2010. In this class we’ll introduce many of the concepts behind the F# language, and look at examples where we use it to create applications inside AutoCAD.

At the time of writing, F# is available as a Community Technology Preview (CTP), installable on Visual Studio 2008. Prior versions of F# provide some integration with Visual Studio 2005, but in this session I’ll primarily be using the superior integration with Visual Studio 2008.

Let’s start by creating an F# project and adding some very simple code.

In Visual Studio 2005, you’ll find the F# project type under “Other Project Types”, assuming you’ve installed a version of F# that integrates with VS 2005, of course:

Figure 1 – Creating a new F# project in Visual Studio 2005

In Visual Studio 2008 we can already see an example of a tighter integration - the F# project types are included at a higher level in the tree-view of project types:

Figure 2 – Creating a new F# project in Visual Studio 2008

The blank project in Visual Studio 2005 is just that – it doesn’t even include a source file. If you right-click the project in the solution explorer and Add -> New Item, you’ll get a dialog showing the various types of source file that you can add:

The initial F# source file created in Visual Studio 2005 already contains a lot of code intended to introduce you to various F# language features. To get the equivalent code in Visual Studio 2008, you need to create a “F# Tutorial” project type.

The standard file created by default in a new Visual Studio 2008 F# project – Program.fs – contains only this text, which we’ll use as a starting point:

#light

This directive tells the F# compiler that we’ll be using “light” syntax, which essentially means a lighter-weight version of the language that relies more heavily on indentation and reduces the need for additional keywords in your source files. The light syntax is very much the standard: almost all F# samples you’ll come across - except for those designed to show the heavyweight syntax – make use of this convention.

Before we write some code, let’s launch the “F# Interactive” (FSI) window in Visual Studio – a very useful explorative environment for developing and testing F# code.

In Visual Studio 2008 this has, once again, become more tightly integrated:

Figure 5 - Launching F# Interactive in Visual Studio 2008

Once launched, you should see the FSI window at the bottom of Visual Studio. FSI is an integrated component that allows on-the-fly compilation and evaluation of F# code. It doesn’t actually interpret the code, but it can often feel as though that’s what’s happening.

OK, now we’re ready top write our first F# function. Type the following code into the F# code window:

let f a b = a + b

The let operator binds a value or a function to a symbol. In this case the function is called f, and takes two arguments, a and b. The result of this function is the sum of a and b.

You’ll probably notice something interesting about this function, right off the bat: there are no types declared. These are inferred by the system, based on how the code is used. The default will be to consider f to take two integers and return an integer, but if your code uses it with real numbers then the arguments will be inferred to be of type float.

It is also possible to specify the type of the arguments by saying, for instance:

let f (a : float) (b : float) = a + b

This can be useful, but makes your code less composable (i.e. harder to copy and paste and use elsewhere). Trusting F#’s type inference to determine the right types is the best approach, where possible: there is no performance penalty as the types are inferred at compile-time, not at runtime.

Before we see this thrilling function in action, let me point out a few more significant facts about it. This function is pure, which means a few things:

Its outputs are a simple function of its inputs

It attempts no side-effects

No shared state is modified

It doesn’t attempt to write to a file or to the screen

If you execute this function multiple times with the same arguments, you will always get the same result

Pure code has a number of advantages: it can more easily be parallelized (farmed out to multiple computing cores), and is also more composable. Having whole programs that are pure isn’t realistic, though: some side-effects are needed to let the user know what’s happening, for instance :-), but having pure sections of code is going to become an increasingly important goal over the coming years.

OK, let’s now highlight our code and press Alt-Enter to load it into FSI:

Figure 6 – Loading our first F# function into F# Interactive

After loading the function we can test it by typing this at the command-line:

f 1 2;;

This calls the function f with arguments 1 and 2 (you can see the result above). You need to terminate code in the FSI window with a double semi-colon – if your code doesn’t appear to be executing properly, then it’s most likely you’re forgetting to do that.

You can see that the type of the function has been inferred as:

val f : int -> int -> int

This means it takes two integers and returns an integer. You may find the type format somewhat strange: there’s no real distinction between the arguments and the returned value, other than their order in the “pipeline”. This allows us to do things like partial application and currying – an example of partial application being if we define an “increment” function called inc:

let inc = f 1

Here we have just stated that calling inc on an integer is like calling f on 1 and that integer. It may seem strange – once again – that we don’t write it like this:

let inc a = f 1 a

In my view one of the beauties of functional programming is that this is not needed – you can define functions simply by “pinning down” arguments of other functions.

We’re here to find out how to create F# code that works with AutoCAD, so let’s go ahead and do that. We’re going to create an AutoCAD command that goes through the contents of our drawing and creates a list of all the words used (removing duplicates along the way). As you’ll see in this code, processing lists of data is very easy from a functional programming language.

At this point I’m going to stop explaining how to do most things in the pre-CTP versions of F# - a VS 2005-compatible version of the code has been posted to my blog, as there will now start to be an increasing number of differences both at the project level and in the source code that we’re going to create. Code written against the eventual released version of F# is much more likely to code written against the CTP, so that’s what we’ll focus on here.

A word of caution: F# Interactive is not hosted inside AutoCAD’s process, so calling F# functions that access AutoCAD objects via the .NET API from FSI will not work. That said, we will create some core functions that are capable of being tested within FSI, so there is some value to understanding how this is possible.

Let’s now make sure our project is going to create a Class Library (DLL) rather than a Windows Application (EXE). We do this by modifying the project properties (using either the main pull-down menus, Project -> FirstFSharpProject Properties…, or right-clicking the FirstFSharpProject project in the Solution Explorer and selecting Properties from the context menu).

Figure 7 – Changing our project settings to create a Class Library

Let’s now replace our code inside the main file (in my case called Program.fs) with this:

#light

// Partial application of split which can then be

// applied to a string to retrieve the contained words

let words =

String.split [' ']

What we have here is a function called words which is simply a call to the String.split function (a static function belonging to the String class – this is where we start to use F#’s object-oriented capabilities, as well as its functional ones). The words function still needs an argument, and, of course, we could also write it like this, if we chose:

let words text =

String.split [' '] text

But we won’t, as the previous definition is more elegant. :-)

OK, so let’s give this a try in FSI. Select the whole contents of the file and hit Alt-Enter.

All being well we should see an error such as this:

C:\...\ FirstFSharpProject\Program.fs(7,10): error FS0039: The value, constructor, namespace or type 'split' is not defined. A construct with this name was found in FSharp.PowerPack.dll, which contains some modules and types that were implicitly referenced in some previous versions of F#. You may need to add an explicit reference to this DLL in order to compile this code.

That’s actually a very accurate and helpful error message: to make use of String.split in our project we need to add a reference to it. And to use it in FSI we need to do the same.

Add a reference via the pull-down menu or the Solution Explorer, selecting this module:

Figure 8 – Adding a project reference to the F# PowerPack

That works for the project, but FSI will give us exactly the same error as before. Within FSI, type the following instruction, which will add a reference to the assembly (and is, in fact, the easiest way to add references to your project when working with pre-CTP F#):

Great! But right now we’re only using the space character to separate words. There are a number of characters that make sense to use as separators in the context of text found in AutoCAD drawings, for example, along with space, I would also choose tab and a number of symbols such as: ~`!@#$%^&*()-=_+{}|[]\;':"<>?,./

So how do we do that? Well, the ugly way is to pass that in as a list of characters into our function:

Yes, that’s certainly ugly. A better approach would be to just have a string that we decompose into a list (a relatively inexpensive operation that is insignificant when compared with the code maintenance benefits).

Let’s create an intermediate value called seps and assign our string to it. We can then use the string’s ToCharArray() method to generate a nice array of characters, which we then turn into a list using Array.to_list:

let words =

let seps = " \t~`!@#$%^&*()-=_+{}|[]\\;':\"<>?,./"

String.split (Array.to_list (seps.ToCharArray()))

It should be obvious how we’re using brackets to choose the execution order of the above code.

To test this out, let’s pass in a few paragraphs from this document, to see how it copes:

> words "We’re here to find out how to create F# code that works with AutoCAD, so let’s go ahead and do that. We’re going to create an AutoCAD command that goes through the contents of our drawing and creates a list of all the words used (removing duplicates along the way). As you’ll see in this code, processing lists of data is very easy from a functional programming language.

At this point I’m going to stop explaining how to do most things in the pre-CTP versions of F# - a VS 2005-compatible version of the project has been posted to my blog, as there will now start to be an increasing number of differences both at the project level and in the source code that we’re going to create. Code written against the eventual released version of F# is much more likely to code written against the CTP, so that’s what we’ll focus on here.

A word of caution: F# Interactive is not hosted inside AutoCAD’s process, so calling F# functions that access AutoCAD objects from FSI will not work. That said, we will create some core functions that are capable of being tested within FSI, so there is some value to understanding how this is possible.

Let’s now make sure our project is going to create a Class Library (DLL) rather than a Windows Application (EXE). We do this by modifying the project properties (using either the main pull-down menus, Project -> FirstFSharpProject Properties…, or right-clicking the FirstFSharpProject project in the Solution Explorer and selecting Properties from the context menu).";;

The display of the returned value has been truncated to the first 100 elements, but it is all there. You may also see additional characters that could be added to the list of separators, but that is left as an exercise for the reader. :-)

So far the words we have are neither sorted nor de-duplicated. Let’s now look into doing that, by defining a new sortedWords function that takes a list of strings (as it’s going to make sense later to pass in a list of strings, rather than just having one monolithic string as the input) and returns a sorted, de-duplicated list of all the words contained within.

let sortedWords x =

x |>

List.map words |> // Get the words from each string

List.concat |> // No need for the outer list

Set.of_list |> // Create a set from the list

Set.to_list // Create a list from the set

We have a new operator in the above code, and it’s one you’ll see a lot in F# code: the pipeline operator, “|>”. This operator is actually conceptually very simple, but makes it possible to create elegant code where the data flows from the beginning of the pipeline to its end, going from function to function.

This function is actually equivalent to this:

let sortedWords x =

List.map words x |> // Get the words from each string

List.concat |> // No need for the outer list

Set.of_list |> // Create a set from the list

Set.to_list // Create a list from the set

The choice is really about readability. To understand the pipeline operator, it can help to see its definition:

let (|>) x f = f x

This means our code is actually equivalent to the (in my opinion) less readable:

let sortedWords x =

Set.to_list (Set.of_list (List.concat (List.map words x)))

If you look back to the definition of words, we see it follows a similar form. Let’s re-write it to use pipelines:

let words =

let seps = " \t~`!@#$%^&*()-=_+{}|[]\\;'’:\"<>?,./"

seps.ToCharArray() |> Array.to_list |> String.split

Now let’s go back to our sortedWords definition. In all versions of the function we start by passing our only argument – x, a list of strings – into a function that “maps” a function across a list, creating a list containing the results of the various operations. Here’s a simple example using the inc function we created earlier:

let f a b = a + b

let inc = f 1

let x = List.map inc [1; 2; 3; 4; 5; 6; 7]

When we load the code into FSI and check the value of x, we see:

val f : int -> int -> int

val inc : (int -> int)

val x : int list

> x;;

val it : int list = [2; 3; 4; 5; 6; 7; 8]

As you can see, the map function applies a function (in our case inc) to each member of the input list and has placed the results in an output list of the same length.

If we really wanted to get clever we could use a lambda (i.e. anonymous) function to avoid having to define inc in the first place:

let x = List.map (fun i -> i+1) [1; 2; 3; 4; 5; 6; 7]

Lambda functions are just one example of a functional programming concept that has made its way into a mainstream, general-purpose language such as C#.

Back to our pipeline... as we’re mapping the words function to a list, and the words function itself returns a list, each time it is called, we’re going to have a list of lists of strings on our hands. So we’re going to call List.concat to concatenate the contents of the outer list – we therefore end up with a single list of all the words across our strings.

This “gross” list of words then gets passed into the Set.of_list function, which creates a set from our list, and sorts/de-duplicates it in the process. Very handy.

As we want to get back to a list of words on the output, we simply call Set.to_list on our set to generate our “net” list.

Here’s the sortedWords function working on a simple list of strings:

> sortedWords ["this is my first sentence"; "this is my second sentence"; "this is my third and final sentence"];;

October 21, 2008

I'm currently working on the handouts for my AU classes: two are sessions I delivered last year, so much of the work for those has been to go through make sure everything works on the latest product versions (and to update the screenshots, as they do look much nicer now that I'm running Vista, it has to be said :-).

The best way to see the capabilities of the new Javascript API to Project Freewheel is to check out this page. I'll hopefully get more time to work on a client-side sample to show this working in the coming weeks, but in the meantime it's very interesting to note - in particular - the ability to receive events fired by changes to the current camera, path or section.

October 17, 2008

A member of my team recently asked me to extend this blog's standard RSS feed to include more than 10 entries: he wanted a feed that contained all the entries ever posted to "Through the Interface". It turns out he uses Outlook 2007's RSS capability to download the full contents of items in an RSS feed, so he can then use his Outlook-integrated search capabilities to search his various email archives - as well as this blog's contents - whenever he's researching a technical query. He had a number of the earlier posts missing from Outlook and wanted the full collection.

I ended up creating a new RSS feed containing all posts specifically for this purpose. If you're new to "Through the Interface" and wish to keep an offline archive of the blog's contents, then this feed may prove useful to you.

On a related note, a very cool tool I use to archive this blog's content is HTTrack. This tool sucks down the content from a particular URL or set of URLs, follows the various links and remaps them to relative links on your local hard-drive. Very cool, indeed. In case you're wondering why I bother... I take the archive created by this tool and transfer it across to a colleague in Shanghai, who extracts it on an internal server for our China-based Engineering teams to access. TypePad blogs are apparently all blocked by the Great Firewall of China, and that's the way we've chosen to work around this problem, for now.

One final reminder, if you're interested in catching up on old posts... as mentioned previously, a master post index is now available in this blog's right-hand navigation sash. This proved immensely popular the day it was launched (that day had the highest ever number of page-hits on this blog, although a few days since have now approached it), but I suspect that people have generally now forgotten about it: it's a relatively inconspicuous grey-on-grey link, after all.

October 15, 2008

How can I show the AutoCAD color dialog from .NET? I need to allow the user to select a block, show the AutoCAD color dialog and apply the selected color to the contents of the selected block.

A new member of DevTech Americas - Augusto Gonçalves, who's based in our São Paulo office - answered with the following code (which I've modified slightly, mostly to follow this blog's coding conventions). Thanks, Augusto!

By the way, these previousposts may also be useful to those interested in this topic.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;

using Autodesk.AutoCAD.Colors;

namespace ColorPicking

{

publicclassCommands

{

[CommandMethod("CB")]

publicvoid ColorBlock()

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;

// Ask the user to select a block

PromptEntityOptions peo =

newPromptEntityOptions("\nSelect a block:");

peo.AllowNone = false;

peo.SetRejectMessage("\nMust select a block.");

peo.AddAllowedClass(typeof(BlockReference), false);

PromptEntityResult per =

ed.GetEntity(peo);

if (per.Status != PromptStatus.OK)

return;

// Open the entity using a transaction

Transaction tr =

db.TransactionManager.StartTransaction();

using (tr)

{

try

{

Entity ent =

(Entity)tr.GetObject(

per.ObjectId,

OpenMode.ForRead

);

// Should always be a block reference,

// but let's make sure

BlockReference br = ent asBlockReference;

if (br != null)

{

// Select the new color

ColorDialog cd = newColorDialog();

cd.IncludeByBlockByLayer = true;

cd.ShowDialog();

// Change the color of the block itself

br.UpgradeOpen();

br.Color = cd.Color;

// Change every entity to be of color ByBlock

BlockTableRecord btr =

(BlockTableRecord)tr.GetObject(

br.BlockTableRecord,

OpenMode.ForRead

);

// Iterate through the BlockTableRecord contents

foreach (ObjectId id in btr)

{

// Open the entity

Entity ent2 =

(Entity)tr.GetObject(id, OpenMode.ForWrite);

// Change each entity's color to ByBlock

ent2.Color =

Color.FromColorIndex(ColorMethod.ByBlock, 0);

}

}

// Commit if there hasn't been a problem

// (even if no objects changed: it's just quicker)

tr.Commit();

}

catch (Autodesk.AutoCAD.Runtime.Exception e)

{

// Something went wrong

ed.WriteMessage(e.ToString());

}

}

}

}

}

Here's a quick example of running the CB command on a block inserted from the "Architectural - Imperial" sample block library that ships with AutoCAD.

After launching the CB command selecting our sports car, we can see the colour selection dialog, which allows us to select an AutoCAD colour index, a true color or a standard colour from a color book:

We can then see our block is changed to this colour (well, in fact the block is changed to be this colour and all its contents are all changed to be coloured ByBlock):

This block happens to be a dynamic block, so if we change it to its truck representation, we see the colour has propagated there, also (as the geometry for this view also resides in the block table record, of course):

By the way, for those of you who are confused by my apparently inconsistent use of spelling, please see this previous post. :-)

October 13, 2008

As mentioned in this previous post, my team delivers regular webcasts on programming with Autodesk technologies.

Assuming you're reading this while the metaphorical ink's still damp, it's still not too late to register for a class being held on Thursday October 16th at 8am Pacific, 5pm CET: AutoCAD: .NET for LISP Programmers.

Otherwise you should be able to find a recording of the webcast on this page within a few weeks of the session being delivered. In fact, here's the recording of the last time this session was delivered (although it may well have been updated slightly, as the session will also be delivered at AU 2008).

Here's a brief synopsis of the topic covered by this webcast:

You know that .NET is a modern and powerful programming environment. But, no matter how much you might want to start using it, you can't abandon all your old LISP code. We’ll show you how to write .NET code that can interoperate with your existing LISP code, with a special emphasis on user interface components.

October 10, 2008

As mentioned in this previous post, I had the great pleasure of spending a day up at Microsoft Research in Cambridge last week. My host, Don Syme, took great care of me and was very generous with his time and knowledge.

Some background on why I decided to request a meeting with Don: Don is the person behind F#, a new programming language that has, over the last year or so, transitioned from being a research project to a fully-fledged .NET language with full support in Microsoft's development tools. Expect to see the capability to create F# projects (just as you can today with VB and C#) inside Visual Studio in the coming releases. I haven't seen a formal announcement stating F# would be part of the Visual Studio 2010 release, but I have to believe that's the plan. (To be clear: this isn't a question I asked Don, this is pure speculation on my part.)

In the past I've referred to Don as both "the father of F#" and "Mr. F#", but - given his modest manner - he prefers the title of "designer" or "implementer" of F#. One thing is clear: Don has been a significant driving force behind F# and has very much led both its development and its transition to being fully supported by Microsoft.

At the risk of repeating myself, I'll briefly go through some of the fundamentals again...

F# is primarily a functional programming language, which means its syntax is quite different from the languages with which most of us are currently most familiar. In your code you define a series of values using the ubiquitous "let" operator, and values which take arguments are functions. Each value you define is based on the inputs or values you've assigned previously. And the last value quoted in a function is its output. That's the very simplistic view: while it's largely possible to write C# or VB code that follows this pattern, the capabilities of functional languages mean that certain types of operation are much easier to handle: as Don mentions in the interview, F# is very good at working with large sets of data, for instance.

You can also use F# to write pure code. Pure code, from a functional perspective, neither contains side-effects (which include, for instance, writing to a file or printing to the screen) nor modifies mutable state (i.e. it doesn't contain variables: you assign values to symbols, but these values don't change, they're immutable). Pure code has certain advantages in the world in which we live today: with the collapse of Moore's Law (or, more generously, its shift to chip vendors delivering multiple cores rather than trying to keep on cranking up the clock speed) and with the shift towards cloud computing, pure code brings many benefits from the fact it's much easier to parallelize. One other neat feature of pure code is its potential for memoization: a pure function will, given the same inputs, always generate the same output, and, as there are no side-effects or state, we don't get any benefit from calling the function multiple times. Which basically means we can store the results and use them directly rather than repeating redundant (and possibly expensive) function calls.

Purely functional programming is still used mostly in academia: real-world implementations tend to need to perform side-effects from time to time (the classic joke is that you can only tell pure functional programs are running because the box gets warmer :-), so Don has championed - very wisely, in my opinion - the development of a pragmatic functional language, one that, while being capable of creating pure code, does not restrict you from maintaining state and making side-effects. What F# primarily brings to the table - beyond OCaml, the pragmatic language upon which it is based - is its ability to run on top of the Common Language Runtime (CLR) and to interoperate both with .NET components and code written in other .NET languages.

So why do I think this is important to what we do? Functional programming is a really good fit for scientific programming, in general, and we have an increasing need for that as engineering analysis and simulation get more tightly integrated into the design process. And we also have an increasingly fully-fledged .NET-based tool-set being exposed from our various products, which means F# code can be integrated with - e.g. used to analyse and modify - models in pretty much all Autodesk's Windows-based design products, whether based on AutoCAD, Revit, Inventor or something else.

I hope this introduction is helpful for those of you who have not yet spent much time looking into this paradigm. I fully agree with Don that, while functional programming isn't going to replace the existing tools we use to develop code today, it is very, very good at solving certain problems and understanding its principles will help us all become better programmers.

The basic premise of F# is to make sure that typed functional programming has a home on the .NET platform. This is a paradigm with a huge amount to offer, as users of languages such as Miranda, OCaml and Haskell have known for a while. I was also quite influenced by seeing Intel make good use of a typed functional language (called FL) in-house. They use that in their hardware verification and some of their design pipelines.

Why use OCaml as a foundation?

Typed functional programming is about simple, compositional, high-level data manipulations using basic orthogonal building blocks. OCaml is a great example of a typed functional programming system and has been highly influential in guiding work in the area. The OCaml approach to language design has the right kind of ethos to make a practical functional language, and the core language is one that is well known and well tested, and has often been used as the basis for experimentation. OCaml itself was the result of this kind of experimentation, based on a system called Caml-Light.

From 1999 to 2003 we were laying the foundations for F#. In 1999 we began Project 7, where we worked with research groups around the world to target different languages at the .NET Common Language Runtime (CLR). Project 7 led directly to the incorporation of .NET Generics in C# 2.0. The next logical step was to implement an OCaml-style language directly, and the OCaml designers were very encouraging when we talked to them about bringing this class of languages into the .NET space. That led to the early versions of F#.

Can (and do) people cross-compile between F# and OCaml? Is that possible?

In practice cross-compilation doesn't tend to be so important: differences in libraries between the .NET and OCaml often get in the way. It's more about transitioning and reusability of techniques and occasionally core engines, such as the PDF processing example.

That said, it's possible, and we do it in our own group for some components. The technique is also used commercially – there's a company that does OCaml-based PDF manipulation tools – a great use of functional programming – they cross-compile between F# and OCaml.

What are the benefits of "thinking functionally" or "thinking FP" for people coding with other languages (C++, C#, VB.NET)?

You have to look at the problem domain to understand if FP is applicable. I like to characterize the domains where functional programming is highly applicable as being either data-intensive or control-intensive. AutoCAD programming is an example of data-intensive work. Symbolic programming is also data-intensive: e.g. manipulating a PDF as a format – sucking it in, parsing it, transforming it. Parallel and asynchronous programming are control-intensive and are both highly suited to functional programming.

There are places where FP won't give you an advantage. Programming the kernel? Then don't use functional programming. Programming a GUI, or some other very presentation-oriented work? Then it may not matter which language you're using: it's the designer tools that are most important.

The first thing C# or C++ programmers notice when they come to F# is how functional programming changes "programming in the small": they are surprised by the elimination of boiler-plate code and the reduction in complexity in object and function implementations. The next thing people notice is the orientation towards immutability. I've seen people give whole talks on how immutability changes your perspective on programming.

It's also true that functional language concepts are definitely having an influence on other .NET languages, as well.

I like to say that pretty much everything we've added to the .NET platform on the languages side since 1.0 has been functional programming. If we look at the additions to C#: generics, added by a functional programming group, based on functional programming principles. Anonymous functions, the query syntax in C# 3.0, the expression tree-based meta-programming, these are all strongly influenced by functional programming. Even C# iterators are closer to functional programming than OO programming, something that comes out clearly in the F# version of this language feature.

.NET itself is also well-suited to functional programming. You'll notice that .NET doesn't have really deep inheritance hierarchies; it's more oriented towards delegates and interfaces. Also many types are immutable – for example System.DateTime. Overall I see this as part of a long trend towards integrating functional ideas into object-oriented programming.

Some of the features in .NET 2.0 have enabled, to a great extent, your ability to implement F# - generics being one. Did you anticipate that, did you implement generics to enable implementation of F#?

Yes, definitely. That was definitely a factor. The first version of F# – the very, very first version – was put out in 2003, when we were still working on .NET generics.

So it was definitely part of a plan.

It was a plan to make sure we were able to support that class of language. We got in what we needed into .NET 2.0.

Do you see yourself as fundamentally a purist or a pragmatist?

I've never been asked that before. :-) To a purist, then I'm pragmatist, to a pragmatist I probably come across as a purist. I'm probably just in the middle. :-)

My job has definitely been to bridge the gap between the academically-oriented programming worlds and industry. If you go back to 2004, in our summary talks on .NET generics, we've got these slides where there was academia on one side and industry on the other and a huge divide in-between. Before Project 7 there was very little communication between these camps, with some notable exceptions, such as the Java generics work. It's been great fun to be able to help bridge this divide.

And you have colleagues in Microsoft Research who are very much purists.

Yes, we do everything: at Microsoft itself we have everything from ultra-purists to ultra-pragmatists.

And you all get on?

We all get on. It's true. :-)

On the other languages side, you might define Haskell as being on the more pure side. I'm very glad for the support we've had from the Haskell research group here at MSR: it's been a great period of cooperation.

Are there any trade-offs when designing a pragmatic (versus a pure) functional language?

Yes, very much. It was very interesting to hear at, last week, the users at the Commercial Users of Functional Programming conference from Howard Mansell at Credit Suisse. Credit Suisse use F# extensively, in their global modeling and analysis group. They described why they use F#, and it was very humorous, their descriptions about how people felt about F# [see this document for notes, which were taken, coincidentally, by an old professor of mine during the conference].

They talked about a couple of possible future extensions they'd like to see to F# - some things such as pre-conditions. What interested me was that they understood why we weren't doing these things, at least in F# V1: part of our aim with F# is to keeps things simple. This means the F# team has made several deliberate limitations in the F# design to make it simple and accessible.

This is important: when you meet another F# programmer they will probably be using the same language devices in similar ways. Languages aren't all about power and expressiveness: they are also about sharing and consistency.

With F# you have a pragmatic development environment, where you can create side-effects as you wish. Mutability is not the default, and you tell when variables are being mutated because you have an explicit operator to do so… do you anticipate a situation where purity will be checked automatically and the code will be profiled and deployed appropriately?

Meaning some kind of automatic parallelization?

Yes, that's what the original question I had written down said, in fact. :-)

Introducing a pure subset to F# is not something we'll be doing in the first version of F# but is a design direction we'll be looking at in the future. Our first priority is to interoperate smoothly, without barriers. If you look in the AutoCAD programming example you were showing me, where you went from data to AutoCAD objects: interoperability is essential. Those AutoCAD objects don't have any guarantee of purity, but it's crucially important not to place barriers in the way of creating and manipulating those objects.

For parallelization, the major focus for F# V1 is on explicit parallelization to give you the tools to control the complexity of explicit parallelization. The fork-join Async.Parallel control pattern you've been using is one example of this [Don was referring to the sample in this post] . Similarly you can capture the essence of an agent-based architecture, sending results back to a visualization thread. A simulation architecture, for example.

Automatic parallelization will eventually make it through to industry. We're going to see a mix of compilation technologies and parallelizing engines: a database such as SQL Server extracts all sorts of parallelism in the engine, as does a web server, as does a graphics pipeline. Source-language compilers may look after relatively easy cases such as the automatic parallelization of CPU-intensive "for" loops over pure objects. We're going to tame parallelism by a mix of techniques: it's not like any one of these is going to be a silver bullet for the parallelism problem.

What attracted you to the functional programming paradigm?

My first programming was AppleBasic, then a lot of different languages, LOGO was one, so I was pleased to see your interpreter. My first real-world programming job was in PROLOG, where I saw the value of a high-level symbolic language, in the context of decision support systems for government services. I then used functional language full-time for 5 years for symbolic manipulation and verification problems. It was just an amazingly powerful paradigm. So, my attraction to functional programming was very much based on experience. It is a great paradigm for information-rich programming.

The industry is also starting to agree.

Yes, it's funny how things come around. The key thing for me is that platforms like .NET really allow you to take a multi-language view of the world, which opens up possibilities of reuse and for using the right tool for the job . F#, itself is implemented in a mix of F#, C# and Visual Basic. We could just drop in those components, make some modifications, and they work.

Additionally, the move to heterogeneous, web-based and service-based architectures also let you choose the right tool for the job. So there's been a sort of shift in the role that languages play.

You don't see F# taking over the world, in the sense of displacing C# and VB.NET.

That's correct. I said F# is very good at data-rich applications, or work such as parallel programming where the control logic plays a significant role. However there are many things that aren't covered by this, for example presentation-rich work: writing a GUI or designing a web site. We don't see that as F#'s primary role in the world. F# is a good language for presentation-rich work, but it's not its primary strength.

Presentation meaning user-interface development.

That's right. For many F# applications, the presentation layer uses the C# and Visual Basic designer tools, with core computational and algorithmic components in F#. That doesn't mean F# components are just crunching numbers and symbols – they may be handling asynchronous programming, for example – but the actual presentation designer work, we're very happy to see that done using tools that generate, say, C# or VB.

There seems to have been interest in F# in the financial computing sector. What other domains do you expect to find F# compelling?

The engineering domains come to mind. These are associated with major applications like AutoCAD and GIS, and traditionally those applications haven't had good extensibility by a typed functional programming language. So F# is really the first time people will be able to use typed functional programming in conjunction with those tools.

More broadly speaking, we see a lot of interest from technical computing domains, meaning science, technology, engineering, mathematics. Another area is in statistical machine learning. Look at what a company like Google does: smart web-based applications and advertising based on statistical processing of massive data sets. At first it's not really so obvious why a web-advertising company would hire so many programmers, but programming is at the heart of their business, and it's a kind of programming where F# excels. We've had some case studies inside Microsoft, using F# to process web advertising data, and it's been extremely successful in that role. So when I say "statistical machine learning", it sounds like some kind of niche area: but in reality whole businesses can now be built on good algorithms.

Do you see much server-side usage of F#?

That's a good question. Yes, I'd say it's a fairly even split between components for server and components for desktop applications. Most deployed applications, right now, would be server-side. That's where the data often is.

Cases like AutoCAD are interesting, as the data is more on the client machine. In fact, I wouldn't necessarily categorise F# as client or server: it's really about where the data is. For example, there are uses of F# internally at Microsoft to analyse the access control lists (ACLs) on machines on the internal network. The ACLs are scraped by a sysadmin process and analyzed by an F# program. The F# programs run at the point of aggregation of the data.

Let's take a look at how F# is used in, say, a quantitative finance group. The F# code begins life as a problem investigation on the analyst's client machine, against local data sets or live market data streamed from some kind of programmatic service. If the algorithm makes it through to a production system it'll end up running as a valuation algorithm on overnight servers.

So when you ask "where is the F# code?" it's all the way through from the concept development through to the actual execution on the servers. So it's server-side, but the users don't think of it in that way: they would think of themselves as quantitative finance guys writing an algorithm.

So typical uses of F# are very domain-focused. F# users may not be so familiar with computer science concepts. They'll just be focused on their domain, like engineering analysis with AutoCAD, or probabilistic modeling. Where it's run isn't the key factor: people doing the deployment will normally look after that kind of thing.

How did you feel when the decision was made for F# to be productized?

Very happy. Very excited. I'm proud of the collective decision-making process inside Microsoft. The process for deciding to bring F# to product quality was very much one that shows Microsoft Research at its best. It also shows the Microsoft teams at their best: there were many open doors to come and talk to the product teams about our research and why we were doing it. We did the project because it was great research, but the fact that it turned out valuable enough to take it through to product quality: that's fantastic.

Has your job changed much since that decision was made?

Certainly. Originally the two of us at Microsoft Research had to do everything: architecture, development, testing, program management, evangelism, book writing – we had to do all these jobs between us. Now we're able to concentrate more on our core expertise. This means I get to spend a bit more time doing architecture and development.