<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3205414380859703216</id><updated>2012-02-16T11:26:24.427-08:00</updated><category term='c#'/><category term='visual studio'/><category term='speculation'/><category term='inheritance'/><category term='f#'/><category term='cooperative multitasking'/><category term='wp7'/><category term='custom workflows'/><category term='xnautils'/><category term='tutorial'/><category term='gc'/><category term='performance'/><category term='storage'/><category term='fsi'/><category term='asteroidhunter'/><category term='xna'/><category term='oop'/><category term='xbox'/><category term='testing'/><category term='computation expressions'/><category term='c++'/><category term='worldconquest'/><title type='text'>F# for game development</title><subtitle type='html'>About F#, game development and programming for .net in general.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>83</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-569598453027798612</id><published>2012-02-14T10:21:00.000-08:00</published><updated>2012-02-14T10:24:57.116-08:00</updated><title type='text'>Units of measure for array indices</title><content type='html'>In F#, arrays play an important part in &lt;a href="http://sharp-gamedev.blogspot.com/2010/03/thoughts-about-f-and-xbox-games.html"&gt;optimizing&lt;/a&gt; performance-critical parts of your code. This is especially true on Xbox 360, where arrays of value types can help avoid snags due to slow garbage collection.Unfortunately, index out-of-bound exceptions are common when working with arrays. This post shows a little trick to help detect cases where the wrong variable is used as the index.&lt;br/&gt;&lt;br/&gt;&lt;pre class="brush:f#"&gt;/// An array whose index has a unit of measure&lt;br /&gt;type MarkedArray&amp;lt;[&amp;lt;Measure&amp;gt;] 'K, 'T&amp;gt; = MarkedArray of 'T[]&lt;br /&gt;with&lt;br /&gt;    member this.Content =&lt;br /&gt;        let (MarkedArray arr) = this&lt;br /&gt;        arr&lt;br /&gt;&lt;br /&gt;    member this.First : int&amp;lt;'K&amp;gt; =&lt;br /&gt;        LanguagePrimitives.Int32WithMeasure 0&lt;br /&gt;&lt;br /&gt;    member this.Last : int&amp;lt;'K&amp;gt; =&lt;br /&gt;        let (MarkedArray arr) = this&lt;br /&gt;        LanguagePrimitives.Int32WithMeasure (arr.Length - 1)&lt;br /&gt;&lt;br /&gt;    member this.Item&lt;br /&gt;        with get (i : int&amp;lt;'K&amp;gt;) =&lt;br /&gt;            let (MarkedArray arr) = this&lt;br /&gt;            arr.[int i]&lt;br /&gt;        and set (i : int&amp;lt;'K&amp;gt;) (v : 'T) =&lt;br /&gt;            let (MarkedArray arr) = this&lt;br /&gt;            arr.[int i] &amp;lt;- v&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;The interesting bit lies in the definition of &lt;tt&gt;this.Item&lt;/tt&gt;. It allows to access the content of a MarkedArray using the usual array notation &lt;tt&gt;arr.[idx]&lt;/tt&gt;&lt;br/&gt;&lt;br/&gt;To illustrate how this is used, imagine you are making an Asteroids clone. You'll probably need arrays for the positions and velocities of the ships (assuming it's a multiplayer game), and similarly for the asteroids. Using units of measures as shown in the &lt;a href="http://sharp-gamedev.blogspot.com/2012/01/units-of-measure-to-rescue.html"&gt;previous post&lt;/a&gt; will help avoid mixing speeds and positions, but it's still possible to pick a position from the wrong array.&lt;br&gt;&lt;br&gt;This is the problem that &lt;tt&gt;MarkedArray&lt;/tt&gt; solves, see below.&lt;pre class="brush:f#"&gt;[&amp;lt;Measure&amp;gt;] type Ship&lt;br /&gt;[&amp;lt;Measure&amp;gt;] type Asteroid&lt;br /&gt;&lt;br /&gt;type State =&lt;br /&gt;  { shipPositions : MarkedArray&amp;lt;Ship, TypedVector3&amp;lt;m&amp;gt;&amp;gt;&lt;br /&gt;    shipVelocities : MarkedArray&amp;lt;Ship, TypedVector3&amp;lt;m/s&amp;gt;&amp;gt; &lt;br /&gt;    asteroidPositions : MarkedArray&amp;lt;Asteroid, TypedVector3&amp;lt;m&amp;gt;&amp;gt;&lt;br /&gt;    asteroidVelocities : MarkedArray&amp;lt;Asteroid, TypedVector3&amp;lt;m/s&amp;gt;&amp;gt; }&lt;br /&gt;&lt;br /&gt;let getShipPosition (state : State) (idx : int&amp;lt;Ship&amp;gt;) : TypedVector3&amp;lt;m&amp;gt; =&lt;br /&gt;  state.asteroidPositions.[idx] // Fails: idx has the wrong type, expected int&amp;lt;Asteroid&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;Note also that creating marked arrays isn't as tedious as one might fear, thanks to type inferrence&lt;br&gt;&lt;pre class="brush:f#"&gt;let state' = { state with shipPositions = state.shipPositions.Content |&amp;gt; Array.map f |&amp;gt; MarkedArray }&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;A small remark to finish off, this is how to iterate over all positions in a marked array, note the &lt;tt&gt;1&amp;lt;Ship&amp;gt;&lt;/tt&gt; increment:&lt;pre class="brush:f#"&gt;for idx in state.shipPositions.First .. 1&amp;lt;Ship&amp;gt; .. state.shipPositions.Last do&lt;br /&gt;  ...&lt;br /&gt;&lt;/pre&gt;By the way, both &lt;tt&gt;TypedVector3&lt;/tt&gt; and &lt;tt&gt;MarkedArray&lt;/tt&gt; are available in &lt;a href="https://bitbucket.org/johdex/xnautils/wiki/Home"&gt;XNAUtils&lt;/a&gt; on bitbucket.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-569598453027798612?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/569598453027798612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=569598453027798612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/569598453027798612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/569598453027798612'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2012/02/units-of-measure-for-array-indices.html' title='Units of measure for array indices'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-9189442209673262903</id><published>2012-01-16T13:48:00.000-08:00</published><updated>2012-01-16T13:49:45.466-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Units of measure to the rescue!</title><content type='html'>Physics can really improve immersion in a game, regardless of how faithful they are to reality. That's why I always enjoyed writing simple physics engine. Even though I have stuck to really simple physics engine, I always end up mixing accelerations and forces. That usually doesn't lead to much trouble in the final result, as masses tend to be constant, and physical properties of game objects are typically chosen after experimentation to maximize fun.&lt;br/&gt;&lt;br/&gt;The feeling that there is something wrong with the math in my code is always annoying, though. It turns out F# has a solution for that, called &lt;i&gt;units of measure&lt;/i&gt;.&lt;br/&gt;&lt;br/&gt;A unit of measure is a type annotation that helps programmers write correct formulas. It's obviously useful for formulas in simulations, whether one is dealing with physics, finances or any other domain where models play an important role.&lt;br/&gt;&lt;br/&gt;The code below shows how to declare a unit measure.&lt;br/&gt;&lt;pre class="brush:f#"&gt;/// Position, meters&lt;br /&gt;[&amp;lt;Measure&amp;gt;] type m&lt;br /&gt;&lt;br /&gt;/// Time, seconds&lt;br /&gt;[&amp;lt;Measure&amp;gt;] type s&lt;br /&gt;&lt;br /&gt;/// Mass, kilograms&lt;br /&gt;[&amp;lt;Measure&amp;gt;] type kg&lt;br /&gt;&lt;/pre&gt;Units in physics have a certain level of redundancy, one might say. For instance, forces can be expressed in Newtons or in kilograms time meters per squared seconds. Newtons are obviously more convenient to use, but you want that masses multiplied by accelerations be recognized as forces. This is how you capture Newton's law:&lt;br/&gt;&lt;pre class="brush:f#"&gt;/// Force, Newtons&lt;br /&gt;[&amp;lt;Measure&amp;gt;] type N = kg m/s^2&lt;br /&gt;&lt;/pre&gt;Units of measure can be used with primitive numeric types such as &lt;tt&gt;int&lt;/tt&gt;, &lt;tt&gt;float&lt;/tt&gt; and &lt;tt&gt;float32&lt;/tt&gt;.&lt;pre class="brush:f#"&gt;let integrateShips (dt : float32&amp;lt;s&amp;gt;) (ships : Ships) ...&lt;br /&gt;&lt;/pre&gt;&lt;tt&gt;dt&lt;/tt&gt; above denotes a time duration in seconds represented using a 32-bit floating point value. Units of measure can also be applied to complex types. The code below shows the code for a wrapper around Xna's Vector3.&lt;pre class="brush:f#"&gt;/// A three-dimensional vector with a unit of measure. Built on top of Xna's Vector3.&lt;br /&gt;type TypedVector3&amp;lt;[&amp;lt;Measure&amp;gt;] 'M&amp;gt; =&lt;br /&gt;    struct&lt;br /&gt;        val v : Vector3&lt;br /&gt;        new(x : float32&amp;lt;'M&amp;gt;, y : float32&amp;lt;'M&amp;gt;, z : float32&amp;lt;'M&amp;gt;) =&lt;br /&gt;            { v = Vector3(float32 x, float32 y, float32 z) }&lt;br /&gt;        new(V) = { v = V }&lt;br /&gt;&lt;br /&gt;        member this.X : float32&amp;lt;'M&amp;gt; = LanguagePrimitives.Float32WithMeasure this.v.X&lt;br /&gt;        member this.Y : float32&amp;lt;'M&amp;gt; = LanguagePrimitives.Float32WithMeasure this.v.Y&lt;br /&gt;        member this.Z : float32&amp;lt;'M&amp;gt; = LanguagePrimitives.Float32WithMeasure this.v.Z&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;[&amp;lt;RequireQualifiedAccessAttribute&amp;gt;]&lt;br /&gt;module TypedVector =&lt;br /&gt;    let add3 (U : TypedVector3&amp;lt;'M&amp;gt;, V : TypedVector3&amp;lt;'M&amp;gt;) =&lt;br /&gt;        new TypedVector3&amp;lt;'M&amp;gt;(U.v + V.v)&lt;br /&gt;&lt;br /&gt;    let sub3 (U : TypedVector3&amp;lt;'M&amp;gt;, V : TypedVector3&amp;lt;'M&amp;gt;) =&lt;br /&gt;        new TypedVector3&amp;lt;'M&amp;gt;(U.v - V.v)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type TypedVector3&amp;lt;[&amp;lt;Measure&amp;gt;] 'M&amp;gt;&lt;br /&gt;with&lt;br /&gt;    static member public (+) (U, V) = TypedVector.add3 (U, V)&lt;br /&gt;    static member public (-) (U, V) = TypedVector.sub3 (U, V)&lt;br /&gt;&lt;/pre&gt;This allows to add and subtract vectors with compatible units of measure. It took me some effort to figure out how to handle multiplication by a scalar. First, in module &lt;tt&gt;TypedVector&lt;/tt&gt;:&lt;pre class="brush:f#"&gt;let scale3 (k : float32&amp;lt;'K&amp;gt;, U : TypedVector3&amp;lt;'M&amp;gt;) : TypedVector3&amp;lt;'K 'M&amp;gt; =&lt;br /&gt;        let conv = LanguagePrimitives.Float32WithMeasure&amp;lt;'K 'M&amp;gt;&lt;br /&gt;        let v = Vector3.Multiply(U.v, float32 k)&lt;br /&gt;        new TypedVector3&amp;lt;_&amp;gt;(conv v.X, conv v.Y, conv v.Z)&lt;br /&gt;&lt;/pre&gt;Then the type extension:&lt;pre class="brush:f#"&gt;type TypedVector3&amp;lt;[&amp;lt;Measure&amp;gt;] 'M&amp;gt;&lt;br /&gt;with&lt;br /&gt;    static member public (*) (k, U) = TypedVector.scale3 (k, U)&lt;br /&gt;&lt;/pre&gt;Note the use of &lt;tt&gt;LanguagePrimitives.Float32WithMeasure&amp;lt;'K 'M&amp;gt;&lt;/tt&gt; to produce a number with a specific unit of measure in a generic fashion.&lt;br/&gt;&lt;br/&gt;I have designed the class to reuse Xna's implementation although it wouldn't have been hard to write my own from scratch. The key benefit, on Windows Phone 7, is to take advantage of some fast vector math that's only accessible through Xna's types. The PC and Xbox platforms don't support fast vector math, but who knows, it may come.&lt;br/&gt;&lt;br/&gt;Finally, here comes an example of how to use all this:&lt;pre class="brush:f#"&gt;    let speeds2 =&lt;br /&gt;        Array.map2&lt;br /&gt;            (fun speed (accel : TypedVector3&amp;lt;m/s^2&amp;gt;) -&amp;gt;&lt;br /&gt;                let speed : TypedVector3&amp;lt;m/s&amp;gt; = speed + dt * accel&lt;br /&gt;                speed)&lt;br /&gt;            ships.speeds.Content accels.Content&lt;br /&gt;&lt;br /&gt;    let posClient =&lt;br /&gt;        ArrayInlined.map3&lt;br /&gt;            (fun pos speed speed2-&amp;gt; pos + 0.5f * dt * (speed + speed2))&lt;br /&gt;            ships.posClient.Content&lt;br /&gt;            ships.speeds.Content&lt;br /&gt;            speeds2&lt;br /&gt;&lt;/pre&gt;There is more to be said and written about units of measures, a future post will show how they can be used for safe access of array contents.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-9189442209673262903?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/9189442209673262903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=9189442209673262903' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/9189442209673262903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/9189442209673262903'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2012/01/units-of-measure-to-rescue.html' title='Units of measure to the rescue!'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-915077198773991134</id><published>2012-01-12T13:31:00.000-08:00</published><updated>2012-01-14T02:40:20.997-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Parallel draw-update XNA game component</title><content type='html'>Video games are often demanding when it comes to computation power, especially simulations and 3d games. The Xbox 360 has 3 cores with two hardware threads each. Of these 2 are reserved for the system, leaving 4 available to the programmer.&lt;br /&gt;This article describes an easy to use custom XNA game component that allows to run computations in parallel with rendering.&lt;br /&gt;&lt;br /&gt;The typical game loop is often divided in two steps, update and draw. I suggest a slightly different workflow divided in three steps, two of which run in parallel: update, compute and draw. The traditional update stage is divided in two new steps, update and compute.&lt;br /&gt;&lt;br /&gt;In this new setting, update is used for receiving inputs from the player and the network, in the case of an online multiplayer game. Compute is potentially cpu-hungry operation implemented in a purely functional way. Rendering plays the same role as usual.&lt;br /&gt;&lt;br /&gt;The &lt;a href="https://gist.github.com/1603109"&gt;code&lt;/a&gt; for the entire component fits in little over 100 lines, see below.&lt;br/&gt;&lt;pre class="brush:f#"&gt;namespace CleverRake.XnaUtils&lt;br /&gt;&lt;br /&gt;open Microsoft.Xna.Framework&lt;br /&gt;open System.Threading&lt;br /&gt;&lt;br /&gt;type IFramePerSecondCounter =&lt;br /&gt;    abstract FramesPerSecond : float&lt;br /&gt;&lt;br /&gt;/// An update-able and drawable game component which performs light updates on the main&lt;br /&gt;/// thread, then draws on a separate thread in parallel of more computation-heavy updates.&lt;br /&gt;/// initialize_fun is called when assets are loaded.&lt;br /&gt;/// dispose is called when the component is disposed, and should be used to unload assets.&lt;br /&gt;/// update_fun takes a GameTime and a state, and should produce draw data and computation&lt;br /&gt;/// data.&lt;br /&gt;/// draw_fun takes a game time and draw data and should return nothing.&lt;br /&gt;/// compute_fun takes a game time and computation data and should return a new state.&lt;br /&gt;type ParallelUpdateDrawGameComponent&amp;lt;'State, 'DrawData, 'ComputationData&amp;gt;&lt;br /&gt;    (game,&lt;br /&gt;     initial_state : 'State,&lt;br /&gt;     initialize_fun : unit -&amp;gt; unit,&lt;br /&gt;     update_fun : GameTime -&amp;gt; 'State -&amp;gt; 'DrawData * 'ComputationData,&lt;br /&gt;     compute_fun : GameTime -&amp;gt; 'ComputationData -&amp;gt; 'State,&lt;br /&gt;     draw_fun : GameTime -&amp;gt; 'DrawData -&amp;gt; unit,&lt;br /&gt;     dispose : unit -&amp;gt; unit) =&lt;br /&gt;&lt;br /&gt;    inherit DrawableGameComponent(game)&lt;br /&gt;&lt;br /&gt;    let mutable state = initial_state&lt;br /&gt;    let mutable draw_data = Unchecked.defaultof&amp;lt;'DrawData&amp;gt;&lt;br /&gt;    let mutable compute_data = Unchecked.defaultof&amp;lt;'ComputationData&amp;gt;&lt;br /&gt;    let mutable gt_shared = GameTime()&lt;br /&gt;&lt;br /&gt;    let mutable enabled = true&lt;br /&gt;    let mutable update_order = 0&lt;br /&gt;&lt;br /&gt;    let signal_start = new AutoResetEvent(false)&lt;br /&gt;    let mutable kill_requested = false&lt;br /&gt;    let signal_done = new AutoResetEvent(false)&lt;br /&gt;&lt;br /&gt;    let do_compute() =&lt;br /&gt;#if XBOX360&lt;br /&gt;        // Set affinity&lt;br /&gt;        // 0 and 2 are reserved, I assume the &amp;quot;main&amp;quot; thread is 1.&lt;br /&gt;        Thread.CurrentThread.SetProcessorAffinity(3)&lt;br /&gt;#endif&lt;br /&gt;        while not kill_requested do&lt;br /&gt;            signal_start.WaitOne() |&amp;gt; ignore&lt;br /&gt;            state &amp;lt;- compute_fun gt_shared compute_data&lt;br /&gt;            signal_done.Set() |&amp;gt; ignore&lt;br /&gt;&lt;br /&gt;    let compute_thread = new Thread(new ThreadStart(do_compute))&lt;br /&gt;&lt;br /&gt;    // Must be called from the main thread.&lt;br /&gt;    let post_compute_then_draw gt =&lt;br /&gt;        if not kill_requested then&lt;br /&gt;            let state = state&lt;br /&gt;            gt_shared &amp;lt;- gt&lt;br /&gt;            signal_start.Set() |&amp;gt; ignore&lt;br /&gt;            draw_fun gt draw_data&lt;br /&gt;            signal_done.WaitOne() |&amp;gt; ignore&lt;br /&gt;&lt;br /&gt;    let mutable frameCounter = 0&lt;br /&gt;    let mutable timeCounter = 0.0&lt;br /&gt;    let mutable fps = 0.0&lt;br /&gt;    let fpsUpdatePeriod = 0.3&lt;br /&gt;&lt;br /&gt;    do&lt;br /&gt;        compute_thread.IsBackground &amp;lt;- true&lt;br /&gt;        compute_thread.Start()&lt;br /&gt;&lt;br /&gt;    override this.Initialize() =&lt;br /&gt;        base.Initialize()&lt;br /&gt;        initialize_fun()&lt;br /&gt;&lt;br /&gt;    override this.Update(gt) =&lt;br /&gt;        if base.Enabled then&lt;br /&gt;            base.Update(gt)&lt;br /&gt;            let draw, compute = update_fun gt state&lt;br /&gt;            draw_data &amp;lt;- draw&lt;br /&gt;            compute_data &amp;lt;- compute&lt;br /&gt;&lt;br /&gt;    override this.Draw(gt) =&lt;br /&gt;        if base.Visible then&lt;br /&gt;            base.Draw(gt)&lt;br /&gt;            post_compute_then_draw gt&lt;br /&gt;        else&lt;br /&gt;            state &amp;lt;- compute_fun gt compute_data&lt;br /&gt;        timeCounter &amp;lt;- timeCounter + gt.ElapsedGameTime.TotalSeconds&lt;br /&gt;        frameCounter &amp;lt;- frameCounter + 1&lt;br /&gt;        if timeCounter &amp;gt; fpsUpdatePeriod then&lt;br /&gt;            fps &amp;lt;- float frameCounter / timeCounter&lt;br /&gt;            timeCounter &amp;lt;- timeCounter - fpsUpdatePeriod&lt;br /&gt;            frameCounter &amp;lt;- 0&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    interface System.IDisposable with&lt;br /&gt;        member this.Dispose() =&lt;br /&gt;            base.Dispose()&lt;br /&gt;            dispose()&lt;br /&gt;            signal_start.Dispose()&lt;br /&gt;            signal_done.Dispose()&lt;br /&gt;&lt;br /&gt;    interface IFramePerSecondCounter with&lt;br /&gt;        member this.FramesPerSecond = fps&lt;br /&gt;&lt;br /&gt;    member this.FramesPerSecond = fps&lt;br /&gt;&lt;br /&gt;    member this.RequestKill() =&lt;br /&gt;        kill_requested &amp;lt;- false&lt;br /&gt;        signal_start.Set() |&amp;gt; ignore&lt;br /&gt;&lt;br /&gt;    member this.WaitUntilDead() =&lt;br /&gt;        compute_thread.Join()&lt;br /&gt;&lt;br /&gt;    member this.IsDead = not(compute_thread.IsAlive)&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;To be noted is that this component isn't meant to be extended the usual way which consists in inheriting and overriding. I'm experimenting with staying away from traditional OOP. I'm not sure it's the nicest way to do things, but building a wrapper from which to inherit shouldn't be hard. The OOP way will definitely be more appealing when using this component from C#, so I'll probably have to take this step anyway.&lt;br/&gt;&lt;br/&gt;The constructor of the class takes an initial state and an initializing function which shouldn't be mixed. The initializing function is meant for loading assets. The &lt;tt&gt;dispose&lt;/tt&gt; function should undo the effects of the initializing function and should dispose of any disposable asset.&lt;br/&gt;&lt;br/&gt;The initial state represents the state of the world when the game starts. This is typically built from a level description when entering a new level, or by loading a previously saved session.&lt;br/&gt;&lt;br/&gt;When the game is running, the state is passed to the update function, which isn't so well named, in retrospect. Its role is to prepare data for the compute and draw functions, which are run in parallel. In most cases I expect that &lt;tt&gt;ComputationData&lt;/tt&gt; and &lt;tt&gt;State&lt;/tt&gt; are the same type.&lt;br/&gt;&lt;br/&gt;As is common in parallel update/draw scenarios, the draw function renders the state produced by the compute function in the previous frame. This is necessary to avoid race conditions between the compute and draw functions.&lt;br/&gt;&lt;br/&gt;I am not yet sure whether I'm happy with my implementation of IDisposable, and this may change if turns out to be impractical or wrong. I've been using this component in a new game I'm working on, and I have been positively surprised. I hope you will find it useful!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-915077198773991134?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/915077198773991134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=915077198773991134' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/915077198773991134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/915077198773991134'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2012/01/parallel-draw-update-xna-game-component.html' title='Parallel draw-update XNA game component'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-1187838502588822515</id><published>2011-12-12T07:27:00.000-08:00</published><updated>2011-12-12T07:31:49.859-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Converting FS project files to target Xbox 360</title><content type='html'>Of interest to anyone using F# and XNA to make games targeting the Xbox 360: I'm working on a script to convert fsproj files for the PC platform to the Xbox platform.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://bitbucket.org/johdex/xnautils/src/a2cc6e8c7455/WinPc/ConvertFsProj.fsx"&gt;https://bitbucket.org/johdex/xnautils/src/a2cc6e8c7455/WinPc/ConvertFsProj.fsx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's not 100% ready yet, the converted files need some manual editing before they are usable.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The advantage of using a script over using the &lt;a href="http://visualstudiogallery.msdn.microsoft.com/e981f57c-c7e4-457c-a32b-38001a4dc860"&gt;project template&lt;/a&gt; is that no additional and unnecessary directory is created. It also keeps all project content, no need to re-add all dll references and source files.&lt;br /&gt;&lt;br /&gt;Here are some known issues:&lt;br /&gt;- Project references are not automatically updated.&lt;br /&gt;- System.Xml and System.Xml.Serialization and possibly other XNA dlls cannot be added from Visual Studio. It complains that those libs are not compatible with the targeted framework despite the fact that they are.&lt;br /&gt;- You need the custom FSharp.Core.dll and accompanying files for Xbox360 somewhere in your solution. You get them as part of the F# + XNA templates, they are also in &lt;a href="https://bitbucket.org/johdex/xnautils/src/a2cc6e8c7455/FSharpCore"&gt;XNAUtils/FSharpCore&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-1187838502588822515?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/1187838502588822515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=1187838502588822515' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1187838502588822515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1187838502588822515'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/12/converting-fs-project-files-to-target.html' title='Converting FS project files to target Xbox 360'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-746501112122706894</id><published>2011-11-12T08:38:00.001-08:00</published><updated>2011-11-12T09:20:55.490-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><title type='text'>Defeating the blank page</title><content type='html'>Programmers have two ways to approach implementation of complex programs:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Start by building bricks, combine them to build larger bricks, repeat until the brick is actually a house.&lt;/li&gt;&lt;li&gt;Work the other way around.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;The second approach is actually the more sensible one for new problems. In general, you know &lt;i&gt;what &lt;/i&gt;is the problem you want to solve, not &lt;i&gt;how &lt;/i&gt;to solve it. It's therefore easier to write the top-level of an application first.&lt;br /&gt;The obvious problem is: On what do you build the top level?&lt;br /&gt;&lt;br /&gt;There is a trick I used in F# that I wanted to share.&lt;br /&gt;Consider the following problem: I want to implement a racing game, which requires multiple data structures to represent the track. In the track editor, the track is basically a curve controlled by a number of points and directions. In the game, the track is a set of triangles used for rendering and simulation.The problem is to convert a track segment defined using the first representation to the second.&lt;br /&gt;A track segment is either linear (it connects two control points), a fork (for the entrance and exit of the pit lane) or a bridge. We can imagine other kinds of segments (+ and T -shaped crossings), but that's enough for a start.&lt;br /&gt;I start with this function:&lt;br /&gt;&lt;pre class="brush:f#"&gt;let triangulate segment =&lt;br /&gt;   match segment with&lt;br /&gt;   | Linear data -&amp;gt; ()&lt;br /&gt;   | Fork data -&amp;gt; ()&lt;br /&gt;   | Bridge data -&amp;gt; ()&lt;br /&gt;&lt;/pre&gt;It's not doing much, obviously. Let's look at the easy case first. A solution would be to get an ordered set of vertices for one side of the road segment, and another set for the other side.&lt;br /&gt;&lt;pre class="brush:f#"&gt;| Linear data -&amp;gt;&lt;br /&gt;   let leftSide = getLeftSide data&lt;br /&gt;   let rightSide = getRightSide data&lt;br /&gt;   knit triangles leftSide rightSide&lt;br /&gt;&lt;/pre&gt;This code isn't valid, because getLeftSide, getRightSide knit and triangles aren't defined. Let's add them as parameters to triangulate:&lt;br /&gt;&lt;pre class="brush:f#"&gt;let triangulate getLeftSide getRightSide knit triangles segment =&lt;br /&gt;   match segment with&lt;br /&gt;   | Linear data -&amp;gt;&lt;br /&gt;      let leftSide = getLeftSide data&lt;br /&gt;      let rightSide = getRightSide data&lt;br /&gt;      knit triangles leftSide rightSide&lt;br /&gt;&lt;/pre&gt;After a few more iterations of this I get the following function:&lt;br /&gt;&lt;pre class="brush:f#"&gt;let triangulate getLeftSide getRightSide getLeftSideOfFork getLeftInner getRightSideOfFork getRightInner intersect glue knit triangles segment =&lt;br /&gt;    let triangulateLinear data =&lt;br /&gt;        let leftSide = getLeftSide data&lt;br /&gt;        let rightSide = getRightSide data&lt;br /&gt;        knit triangles leftSide rightSide&lt;br /&gt;&lt;br /&gt;    match segment with&lt;br /&gt;    | Linear data -&amp;gt;&lt;br /&gt;        triangulateLinear data&lt;br /&gt;&lt;br /&gt;    | Fork data -&amp;gt;&lt;br /&gt;        let outSide0 = getLeftSideOfFork data&lt;br /&gt;        let inSide0 = getLeftInner data&lt;br /&gt;        let outSide1 = getRightSideOfFork data&lt;br /&gt;        let inSide1 = getRightInner data&lt;br /&gt;        let inSide0, inSide0', inSide1, inSide1' = intersect inSide0 inSide1&lt;br /&gt;        knit triangles outSide0 (glue inSide0 inSide1')&lt;br /&gt;        knit triangles outSide1 (glue inSide1 inSide0')&lt;br /&gt;        knit triangles inSide0' inSide1'&lt;br /&gt;&lt;br /&gt;    | Bridge data -&amp;gt;        &lt;br /&gt;        triangulateLinear data.under&lt;br /&gt;        triangulateLinear data.over&lt;br /&gt;&lt;/pre&gt;The function takes quite a few parameters, maybe too many. I can clean this up later after I have implemented getLeftSide and all other functions.&lt;br /&gt;&lt;br /&gt;Notice how far I can get never worrying about types, yet I never need to worry about whether the parts fit together.&lt;br /&gt;&lt;br /&gt;This way of writing code has helped me get over a number of situations where I was suffering some sort of "blank page syndrome", not knowing where to start to tackle a complex problem.&lt;br /&gt;Of course, there is no guarantee that the final implementation will keep the same architecture, but at least I'm going forward!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-746501112122706894?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/746501112122706894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=746501112122706894' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/746501112122706894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/746501112122706894'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/11/defeating-blank-page.html' title='Defeating the blank page'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-7649802754957986756</id><published>2011-09-23T13:13:00.000-07:00</published><updated>2011-09-23T13:29:01.484-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='inheritance'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>An example of inheritance gone wrong</title><content type='html'>In an earlier post entitled &lt;a href="http://sharp-gamedev.blogspot.com/2011/07/why-inheritance-for-code-reuse-should.html"&gt;Why inheritance for code reuse should be avoided&lt;/a&gt;&amp;nbsp;I pointed out that the key problem was conforming to the Liskov Substitution Principle.&lt;br /&gt;&lt;br /&gt;Although I guess there is nothing controversial in what I wrote, I fear I probably did not convince anyone who wasn't already convinced.&lt;br /&gt;&lt;br /&gt;Today at work, I had the pleasure of being hit by a bug that is a wonderful example of inheritance gone wrong.&lt;br /&gt;&lt;br /&gt;Let me give a bit of context. Once upon a time there was an application that allowed viewing and editing a database in a nice and user-friendly somewhat buggy GUI. As it was felt the application could be user-friendlier and more stable, additional development efforts were planned to improve it. This logically led to the decision of distributing what was a stand-alone file-oriented program over a server-client architecture.&lt;br /&gt;&lt;br /&gt;In case you hadn't noticed, I'm being a bit sarcastic, but the fact is that the original plans for the application included extensions to a server-client architecture, and the source code was cleanly organized in modules, keeping the GUI and the database separated by a middle layer.&lt;br /&gt;&lt;br /&gt;When moving to the new architecture, it felt natural to turn the middle layer into a web service. This required all data types in the API of the middle layer to be serializable so that they could be sent over the net between the client (the GUI) and the server. This was fairly easily achieved using WCF and DataContract.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;[DataContract]&lt;br /&gt;class Item {&lt;br /&gt;   [DataMember]&lt;br /&gt;   public int Data { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Today, I opened a bug report with an unexpected exception stating that a type named "...Dialog+GuiItem" could not be serialized. Indeed, I could recognize the "Item" part, which was serializable thanks to DataContract, but the GUI component most certainly wasn't! What was going on there?&lt;br /&gt;&lt;br /&gt;Looking at the definition of Item, I could see it was a fairly simple type GuiItem augmenting a simple data-type (called Item) with GUI thingies.&lt;pre class="brush:csharp"&gt;&lt;br /&gt;class GuiItem : Item {&lt;br /&gt;   public Gui SomeGuiStuff;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The problem is, the GUI-augmented type couldn't provide all features the basic type did: It could not be sent over the net.&lt;br /&gt;&lt;br /&gt;In the first version of the software, passing the GUI-augmented instance to the middle layer was not a problem. The middle layer expected a basic Item or anything that can be implicitly converted to such an item. As long as all passing of arguments occurs within the same process, no additional effort or processing was needed.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;class MidLayer {&lt;br /&gt;   public void DoSomething(Item item);&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;void OnClick(GuiItem item) {&lt;br /&gt;  midlayer.DoSomething(item); // Fine, GuiItem is also an Item.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the new version, passing arguments is a significantly more complex operation involving doing a deep dump of the content of the instance, streaming over the net, and summoning a new instance stuffed with the dump on the other side of the wire. This only works for types which are purely data-oriented. Inject any kind of "live" resource in there, and you are out of luck.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;[WebService]&lt;br /&gt;class MidLayer {&lt;br /&gt;   [WebMethod]&lt;br /&gt;   public void DoSomething(Item item);&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;void OnClick(GuiItem item) {&lt;br /&gt;  midlayer.DoSomething(item); // Exception: can't serialize GuiItem!&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The solution was simple enough, simply include the basic Item as a member of the GUI-augmented type, and provide a getter to easily send it from the GUI to the server.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;class GuiItem {&lt;br /&gt;   Item item;&lt;br /&gt;   Item Item {&lt;br /&gt;      get {&lt;br /&gt;         return item;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Gui SomeGuiStuff { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void OnClick(GuiItem item) {&lt;br /&gt;  midlayer.DoSomething(item.Item); // Fine again.&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;When inheriting from a type, you don't just get its nice features, but also its responsibilities.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-7649802754957986756?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/7649802754957986756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=7649802754957986756' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7649802754957986756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7649802754957986756'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/09/example-of-inheritance-gone-wrong.html' title='An example of inheritance gone wrong'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5144047118025531447</id><published>2011-08-21T00:28:00.000-07:00</published><updated>2011-08-21T00:28:08.678-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>New e-book: FRIENDLY F# with game development and XNA</title><content type='html'>I received a mail from Giuseppe Maggiore, one of the authors of a new book: FRIENDLY F# with game development and XNA. Giuseppe helped me put together the project templates for F# and XNA on the Xbox 360.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The main subject of the book is the F# language and its various&lt;br /&gt;constructs, but every single chapter is centered around a game-related&lt;br /&gt;problem. Each one of the first 5 chapters describes a problem, shows&lt;br /&gt;and discusses its solution and then discusses in depth the F#&lt;br /&gt;constructs used. The book has a (relatively rare) "problem-solution"&lt;br /&gt;approach where everything is explained because of how well it works in&lt;br /&gt;solving the problem, and not just "because". The 5 problems we present&lt;br /&gt;are:&lt;br /&gt;- a bouncing ball&lt;br /&gt;- the Saturn V rocket&lt;br /&gt;- an asteroid field&lt;br /&gt;- a large asteroid field optimized with quad trees&lt;br /&gt;- a police starship that must fight off a pirate ship attacking a&lt;br /&gt;cargo freighter&lt;br /&gt;In the last two chapters we use XNA to build a 2D and 3D renderer for&lt;br /&gt;two of the samples we have seen. We show the basics of the SpriteBatch&lt;br /&gt;class, the Model class, input management and audio with this powerful&lt;br /&gt;framework. Basically, we cover the most important aspects of XNA in a&lt;br /&gt;simple and succint way.&lt;/blockquote&gt;I had a quick look at the book and I think Giuseppe's description is a fair one. In other words, this is not a book primarily about game programming, but an introduction to F#. Although it touches some advanced topics such as custom workflows, it is not a comprehensive coverage of the language.&lt;br /&gt;All in all, if you are looking for a gentle and quick introduction to the language, and you are interested in game programming, you should definitely check this book.&lt;br /&gt;&lt;br /&gt;The book is available on &lt;a href="http://www.amazon.com/Friendly-Fun-game-programming-ebook/dp/B005HHYIWC/ref=sr_1_12?s=digital-text&amp;amp;ie=UTF8&amp;amp;qid=1313593351&amp;amp;sr=1-12%0A"&gt;Amazon&lt;/a&gt; and &lt;a href="http://www.smashwords.com/books/view/81765"&gt;Smashwords&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5144047118025531447?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5144047118025531447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5144047118025531447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5144047118025531447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5144047118025531447'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/08/new-e-book-friendly-f-with-game.html' title='New e-book: FRIENDLY F# with game development and XNA'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-1199175971364029823</id><published>2011-08-03T09:32:00.000-07:00</published><updated>2011-08-04T01:14:35.411-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><title type='text'>The forgotten control flow construct</title><content type='html'>There is a truly powerful control flow construct that many programmers have forgotten. It helps implement complex flows that ifs, whiles and matches can't handle. Not even throwing and catching exceptions can measure itself to this construct.&lt;br /&gt;&lt;br /&gt;You may wonder what kind of situation would require something that traditional constructs can't handle. Here is an example taken from &lt;a href="http://david.tribble.com/text/goto.html"&gt;Go To Statement Considered Harmful: A Retrospective&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c"&gt;int parse()&lt;br /&gt;{&lt;br /&gt;    Token   tok;&lt;br /&gt;&lt;br /&gt;reading:&lt;br /&gt;    tok = gettoken();&lt;br /&gt;    if (tok == END)&lt;br /&gt;        return ACCEPT;&lt;br /&gt;shifting:&lt;br /&gt;    if (shift(tok))&lt;br /&gt;        goto reading;&lt;br /&gt;reducing:&lt;br /&gt;    if (reduce(tok))&lt;br /&gt;        goto shifting;&lt;br /&gt;    return ERROR;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Let's see how using a while turns out:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type Token = END&lt;br /&gt;&lt;br /&gt;type ParseState = Reading | Shifting | Reducing | Accepted | Errored&lt;br /&gt;type Status = ACCEPT | ERROR&lt;br /&gt;&lt;br /&gt;let parse gettoken shift reduce () =&lt;br /&gt;    let mutable state = Reading&lt;br /&gt;    let mutable tok = Unchecked.defaultof&amp;lt;Token&amp;gt;&lt;br /&gt;    &lt;br /&gt;    while state &amp;lt;&amp;gt; Accepted &amp;amp;&amp;amp; state &amp;lt;&amp;gt; Errored do&lt;br /&gt;        state &amp;lt;-&lt;br /&gt;            match state with&lt;br /&gt;            | Reading -&amp;gt;&lt;br /&gt;                tok &amp;lt;- gettoken()&lt;br /&gt;&lt;br /&gt;                if tok = END then&lt;br /&gt;                    Accepted&lt;br /&gt;                else&lt;br /&gt;                    Shifting&lt;br /&gt;&lt;br /&gt;            | Shifting -&amp;gt;&lt;br /&gt;                if shift tok then&lt;br /&gt;                    Reading&lt;br /&gt;                else&lt;br /&gt;                    Reducing&lt;br /&gt;&lt;br /&gt;            | Reducing -&amp;gt;&lt;br /&gt;                if reduce tok then&lt;br /&gt;                    Shifting&lt;br /&gt;                else&lt;br /&gt;                    Errored&lt;br /&gt;&lt;br /&gt;            | Errored | Accepted -&amp;gt; failwith &amp;quot;Invalid state&amp;quot;&lt;br /&gt;&lt;br /&gt;    match state with&lt;br /&gt;    | Errored -&amp;gt; ERROR&lt;br /&gt;    | Accepted -&amp;gt; ACCEPT&lt;br /&gt;    | _ -&amp;gt; failwith &amp;quot;Non-final state&amp;quot;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Note that I have introduced extra parameters gettoken, shift and reduce; I wanted to be able to write concise code that syntactically correct without explicitly defining these functions).&lt;br /&gt;&lt;br /&gt;It looks OK, but we had to introduce an extra type, ParseState. There are also some issues with mutability and initialization of tok.&lt;br /&gt;&lt;br /&gt;If you have some experience with functional programming, you are probably thinking that recursion is the right tool. I will leave writing a recursive version of parse to the reader, and jump to a slightly different idea that many might have missed.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type Token = END | SOMETHINGELSE&lt;br /&gt;&lt;br /&gt;type Status = ACCEPT | ERROR&lt;br /&gt;&lt;br /&gt;let parse gettoken shift reduce () =&lt;br /&gt;    let rec do_read() =&lt;br /&gt;        match gettoken() with&lt;br /&gt;        | END -&gt; ACCEPT&lt;br /&gt;        | _ as tok -&gt; do_shift tok&lt;br /&gt;&lt;br /&gt;    and do_shift tok =&lt;br /&gt;        if shift tok then&lt;br /&gt;            do_read()&lt;br /&gt;        else&lt;br /&gt;            do_reduce tok&lt;br /&gt;&lt;br /&gt;    and do_reduce tok =&lt;br /&gt;        if reduce tok then&lt;br /&gt;            do_shift tok&lt;br /&gt;        else&lt;br /&gt;            ERROR&lt;br /&gt;&lt;br /&gt;    do_read()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;do_read, do_shift and do_reduce are mutually recursive functions. All recursive calls are in tail position, which makes it possible to avoid stack overflows (on some platforms...).&lt;br /&gt;&lt;br /&gt;Here you have it: calls in tail position are basically safe versions of goto.&lt;br /&gt;&lt;br /&gt;The fantastic control flow construct that many have forgotten is simply the procedure call. Every programmer uses it a countless number of times every working day, but fear of recursion and stack overflows have kept many from using it in situations where it fits well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-1199175971364029823?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/1199175971364029823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=1199175971364029823' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1199175971364029823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1199175971364029823'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/08/forgotten-control-flow-construct.html' title='The forgotten control flow construct'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2394829571031240926</id><published>2011-08-02T08:58:00.000-07:00</published><updated>2011-08-02T09:01:15.143-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Is it worth it?</title><content type='html'>In my previous post, I explained why &lt;a href="http://sharp-gamedev.blogspot.com/2011/07/why-inheritance-for-code-reuse-should.html"&gt;inheritance for code reuse is a bad idea&lt;/a&gt;. The blog was a bit on the theoretical side, and I wanted to know if I wasn't sitting in an ivory tower.&lt;br /&gt;&lt;br /&gt;For this reason, I have decided to rewrite one of my uses of inheritance by composition. The piece of code in question is the BaseScreen class in XnaUtils.&lt;br /&gt;&lt;br /&gt;Before I go any further, I need to give you a bit of context. The user interface of video games is usually composed of screens. The library provides a class called ScreenManager which is responsible for managing stacks of screens, notifying each screen when to load/unload resources such as textures...&lt;br /&gt;&lt;br /&gt;I have created an interface named "Screen" which serves as the interface between the framework and the screens in a game. The framework also provides a few screens which can be used in simple games, namely TextScreen, MenuScreen and PressStartScreen.&lt;br /&gt;&lt;br /&gt;These screens all share common functionality which I needed to put somewhere to avoid code duplication. In my first version, BaseScreen was an abstract class from which screen implementations inherited, overriding a few key methods to customize rendering.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Differences in ScreenBase&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The changes are not very extensive. Abstract methods were replaced by fields. Instead of defining overrides, inheritors set properties using lambdas.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;+    let post_drawer : ('T -&amp;gt; unit) ref = ref (fun _ -&amp;gt; ())&lt;br /&gt;...&lt;br /&gt;-    abstract member EndDraw : 'T -&amp;gt; unit&lt;br /&gt;-    default this.EndDraw(_) = ()&lt;br /&gt;-&lt;br /&gt;+    member this.PostDrawer&lt;br /&gt;+        with get() = !post_drawer&lt;br /&gt;+        and set(d) = post_drawer := d&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Differences in inheritors&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A few "this" had to be replaced by "impl", the name of the variable I have used to hold the instance of ScreenBase.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type PressStartScreen(sys : Environment, fade_in, fade_out, blink) =&lt;br /&gt;-    inherit ScreenManager.ScreenBase&amp;lt;unit&amp;gt;()&lt;br /&gt;+    let impl = new ScreenManager.ScreenBase&amp;lt;_&amp;gt;()&lt;br /&gt;+    let impl_screen = impl :&amp;gt; ScreenManager.Screen&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;// Task to check if a button is pressed. Sets player when that happens.&lt;br /&gt;let player : PlayerIndex option ref = ref None&lt;br /&gt;while (!player).IsNone do&lt;br /&gt;-            do! sys.WaitUntil(fun () -&amp;gt; this.IsActive)&lt;br /&gt;+            do! sys.WaitUntil(fun () -&amp;gt; impl.IsActive)&lt;br /&gt;for p in all_players do&lt;br /&gt;let state = GamePad.GetState(p)&lt;br /&gt;if state.IsConnected&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Boiler-plate code had to be written to implement interfaces Screen and IDisposable, forwarding calls to "impl". As ScreenBase implements these interfaces explicitly, I had to introduce an extra variable "impl_screen" to refer to impl's implementation of Screen. Otherwise, I would have had to use casts in all forwarding code, as shown in the implementation of IDisposable.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;+    interface ScreenManager.Screen with&lt;br /&gt;+        member this.ClearScreenManager() = impl_screen.ClearScreenManager()&lt;br /&gt;+        member this.Draw() = impl_screen.Draw()&lt;br /&gt;+        member this.LoadContent() =&lt;br /&gt;+            impl_screen.LoadContent()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;+&lt;br /&gt;+    interface System.IDisposable with&lt;br /&gt;+        member this.Dispose() = (impl :&amp;gt; System.IDisposable).Dispose()&lt;br /&gt;+&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Advantages of composition and delegation over inheritance&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. Inheritors can reuse code from multiple classes (F# does not have multiple inheritance).&lt;br /&gt;2. The code for ScreenBase is a bit shorter.&lt;br /&gt;3. Inheritors have more control.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Advantages of inheritance over composition and delegation:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. The "IDisposability" of ScreenBase is implicitly propagated to its inheritors.&lt;br /&gt;2. No risk of errors in delegation.&lt;br /&gt;3. The code for inheritors is shorter.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Although I believe most of the weaknesses of the approach using composition and delegation could be lifted by additions to the F# language, in its current shape, I would not dare to force users of my library to use composition.&lt;br /&gt;&lt;br /&gt;The ideal solution is to write my library code to allow users to use the approach they prefer, which I expect would be inheritance in most cases. Providing this approach as the only one is not acceptable, as it would prevent users to reuse features from multiple classes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2394829571031240926?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2394829571031240926/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2394829571031240926' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2394829571031240926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2394829571031240926'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/08/is-it-worth-it.html' title='Is it worth it?'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3304567195229230251</id><published>2011-07-17T03:21:00.000-07:00</published><updated>2011-07-22T01:38:08.221-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='inheritance'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Why inheritance for code reuse should be avoided</title><content type='html'>The question of when to use inheritance and when not to has been asked many times. I have noticed answers can be put in one of three categories:&lt;br /&gt;&lt;br /&gt;1. Use as much as you can. It's a convenient way to maximize code reuse with very few keystrokes. Actually, this answer is seldom explicitly given, but if I judge by the code I see, this is a wide-spread opinion.&lt;br /&gt;&lt;br /&gt;2. There are situations when inheritance is appropriate, and situations when it isn't. Namely, inheritance is appropriate to express IS-A relationships.&lt;br /&gt;&lt;br /&gt;3. Never use it for the purpose of code reuse. Some take it even further and say never use it at all. Inheritance is flawed by design.&lt;br /&gt;&lt;br /&gt;Throughout my life as a programmer, I have gone through all of these stages, in order. I think most of the controversy focuses on inheritance for the purpose of code reuse, and I'll start with that.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Inheritance for the purpose of code reuse&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;The first answer is easy to discard, as explained in &lt;a href="http://programmers.stackexchange.com/questions/12439/code-smell-inheritance-abuse/12446#12446"&gt;this answer&lt;/a&gt; on the programmers stackexchange. Systematically using inheritance quickly leads to excessively large objects. The author of the code probably won't see this as a problem at first, and may indeed be oblivious to the problem. Unfortunately, this makes it very easy to fall into this trap.&lt;br /&gt;&lt;br /&gt;The second answer begs for an answer to the question "what is an IS-A relationship?". I find that all IS-A relationships can be expressed as HAS-A, and vice-versa. Taking the usual example of cars, we can say a car has four wheels, and it is a four-wheeled vehicle. A car has an engine, and it is an engine-powered vehicle. Which is the correct way of expressing relationships between cars and their components?&lt;br /&gt;&lt;br /&gt;Instead of relying on IS-A vs HAS-A, one can use the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov Substitution Principle&lt;/a&gt; (LSP), as pointed out in &lt;a href="http://programmers.stackexchange.com/questions/12439/code-smell-inheritance-abuse/12448#12448"&gt;this other answer&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Informally, the principle states that if B inherits from A, then B must be usable in all places where A is used.&lt;br /&gt;&lt;br /&gt;This is a bit of a loose definition, and even the more formal definition by Barbara Liskov and Jeanette Wing stated below invites further questions.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.&lt;/blockquote&gt;&lt;br /&gt;What is the proof system assumed here? What kind of sentences can be expressed? Do the axioms include knowledge about the program?&lt;br /&gt;&lt;br /&gt;Informally, how should "usable" be interpreted in the informal statement of the principle?&lt;br /&gt;&lt;br /&gt;I don't think there is a single fit-all answer to this question. There are a number of aspects to consider, which all affect the initial development time and degree of maintainability of a software project.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Language Semantics.&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;Note that a language which allows to query the concrete type of an object makes it impossible to meet the LSP.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;let f (x : A) =&lt;br /&gt;    match x with&lt;br /&gt;    | :? B -&amp;gt; failwith "Failing!"&lt;br /&gt;    | _ -&amp;gt; x.DoSomething()    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Obviously, an instance of B cannot be used with f, as it would cause the program to behave differently as when provided with instances of A (or some other subtype of A).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Notion of equivalence.&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;That instances of B can be used instead of A means that the behavior of the software when B is used is "observably equivalent" to that of the software when A is used.&lt;br /&gt;&lt;br /&gt;There are different levels of strictness regarding equivalence. Including internal state in the observable behavior is a bad idea, as this forbids method overriding and polymorphism.&lt;br /&gt;&lt;br /&gt;Even limiting oneself to "user-visible events" may be too limiting, as this closes the door to plug-ins that extend or modify functionality.&lt;br /&gt;&lt;br /&gt;In the end, I think a popular but very weak notion is whether the program crashes or not. And even that may be too strong, as it's probably acceptable for instances of B to work where instances of A crash (OK, that's nit-picking).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Scope.&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;Does "all places where A is used" refer to the places as they exist in the current form of the software, in the current and expected future forms, or in all possible forms?&lt;br /&gt;&lt;br /&gt;There is a bit of overlap with the first aspect. When assuming the scope is limited to the current state, and if no concrete type tests on instances of A are made anywhere, then meeting the LSP seems feasible.&lt;br /&gt;&lt;br /&gt;Assuming the second alternative (current and expected future forms) requires either a clear idea of what the future looks like, or a coding standard prohibiting the use of all language constructs potentially incompatible with the LSP.&lt;br /&gt;&lt;br /&gt;If you are designing a library or framework to be used by other parties you don't control, you are condemned to the last option, "all possible forms". Unless you have a low level of ambition on the notion of equivalence, the LSP is impossible to meet in this setting.&lt;br /&gt;&lt;br /&gt;There may well be other aspects I haven't thought of, but I hope I made it clear that the LSP isn't quite as simple as it may seem at a first glance. Using inheritance only "when it conforms to the LSP" often equates to "never" if one really cares about the LSP. Moreover, it requires an understanding of the principle itself as well as clearly identifiable decisions on all the points mentioned above, two conditions which are not met that often out-there-in-the-real-world. &lt;br /&gt;&lt;br /&gt;Note that it's possible and indeed desirable to specify limitations on language features, equivalence and scope on a per-type basis. Doing it on a project-wide level would probably make it impossible to respect the LSP.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Inheritance limited to interfaces&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;My standing on the question of inheritance when limited to interfaces is not quite clear yet. I can't quite put my finger on the exact problem yet, so I'll leave it to another day to express my thoughts in details on the subject.&lt;br /&gt;&lt;br /&gt;Shortly, it seems to me this kind of inheritance brings little, if anything at all, over composition. The argument of the "keystroke minimality" applies only to subtyping between interfaces, which I have had little practical use for so far.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Alternatives to inheritance&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Composition is often cited as the right way to take advantage of code reuse. To put it mildly, mentioning it often fails to trigger the enthusiasm of proponents of inheritance for code reuse. It's easy to understand why:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type A =&lt;br /&gt;   ...&lt;br /&gt;   member this.DoSomething1() = ...&lt;br /&gt;   ...&lt;br /&gt;   member this.DoSomething15() = ...&lt;br /&gt;&lt;br /&gt;type OhForGodsSake_B =&lt;br /&gt;   let an_a : A = ...&lt;br /&gt;   member this.DoSomething1() = an_a.DoSomething1()&lt;br /&gt;   ...&lt;br /&gt;   member this.DoSomething15() = an_a.DoSomething15()&lt;br /&gt;&lt;br /&gt;type WhatABreeze_B() =&lt;br /&gt;   inherit A()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Indeed, there is something to be said for the second approach. I wish F# had some way to achieve the conciseness of inheritance through composition, but that's not the case. This may be an oversight, or may be by design. As Matthieu M. writes in his answer, forcing verbosity can be beneficial:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;[It] means that at least a couple keystrokes are needed for each method, and suddenly people begin to think about whether or not it's such a great idea to reuse this "fat" class for just a small piece of it.&lt;/blockquote&gt;&lt;br /&gt;I would add that this would also force the author of B to think about whether all 15 DoSomething() methods really are needed in B, or if it's enough to provide just a few of them. &lt;br /&gt;&lt;br /&gt;By the way, should the methods in B have the same name as their counter-parts in A? If A is "VehicleWithWeels", and "B" is "Airplane", it makes sense to expose "VehicleWithWeels.Brake" as "Airplane.BrakeWithWheels", as airplanes have different means of braking. It's easy to miss that subtle point when using inheritance.&lt;br /&gt;&lt;br /&gt;All-in-all, I don't think I should value my laziness and comfort over cleaner code, at least not in a professional setting. Still, I can't help being lazy... Programming isn't all about writing clean code, it's about having fun too.&lt;br /&gt;&lt;br /&gt;When dealing with implementation relationships between concrete types and interfaces, I am happy with seeing it as "HAS-A" kind of relationship, or more precisely (and verbosely) "OFFERS-FUNCTIONALITY-AS-SPECIFIED-BY-INTERFACE". This can be achieved in two ways in F#:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;// Explicit implementation&lt;br /&gt;type B1 =&lt;br /&gt;   ...&lt;br /&gt;   interface A with&lt;br /&gt;      method this.DoSomething() = ...&lt;br /&gt;&lt;br /&gt;// Composition using object expressions&lt;br /&gt;type B2 =&lt;br /&gt;   ...&lt;br /&gt;   member this.AsA() =&lt;br /&gt;      { new A with&lt;br /&gt;           member x.DoSomething() = ... // Note "x" vs "this". "this" refers to B2.&lt;br /&gt;      }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The first approach can be used when it's clear B1 can only provide A in one single sensible way at all times, the second approach is more general and flexible. One might wonder if the second approach shouldn't always be preferred. Where do extremes end? ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3304567195229230251?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3304567195229230251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3304567195229230251' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3304567195229230251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3304567195229230251'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/07/why-inheritance-for-code-reuse-should.html' title='Why inheritance for code reuse should be avoided'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3218566300402897173</id><published>2011-07-15T03:04:00.000-07:00</published><updated>2011-07-15T09:45:18.261-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>OOP without classes in F#</title><content type='html'>Did you know that F# allows to use some object-oriented features with types that are not classes? This includes methods, dynamic dispatch, open recursion and encapsulation.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Methods&lt;/i&gt; are functions or procedures which are tightly coupled to a type of object.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Dynamic dispatch&lt;/i&gt; is the ability to execute different implementations of an operation depending on the concrete types of arguments. A special case which often has dedicated syntax is when the operation is a method, and the argument controlling the dispatch is the object itself.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Open recursion&lt;/i&gt; makes the object available to its methods through an identifier, typically called &lt;i&gt;this&lt;/i&gt; or &lt;i&gt;self&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Encapsulation&lt;/i&gt; restricts access to the internal data and operations of an object to a restricted area of the code. Typically this area is the methods of the object itself, F# works at the module level instead.&lt;br /&gt;&lt;br /&gt;The code below shows how a vector type can be defined using records.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;[&amp;lt; CustomComparison &amp;gt;]&lt;br /&gt;[&amp;lt; CustomEquality &amp;gt;]&lt;br /&gt;type Vector2 =&lt;br /&gt;    private { x : float&lt;br /&gt;              y : float }&lt;br /&gt;with&lt;br /&gt;    // Constructors&lt;br /&gt;    static member New(x, y) = { x = x; y = y }&lt;br /&gt;    static member Zero = { x = 0.0; y = 0.0 }&lt;br /&gt;&lt;br /&gt;    // Accessors&lt;br /&gt;    member this.X = this.x&lt;br /&gt;    member this.Y = this.y&lt;br /&gt;    member this.Length = let sq x = x * x in sqrt(sq this.x + sq this.y)&lt;br /&gt;&lt;br /&gt;    // Methods&lt;br /&gt;    member this.CompareTo(other : obj) =&lt;br /&gt;        match other with&lt;br /&gt;        | null -&amp;gt; nullArg &amp;quot;other&amp;quot;&lt;br /&gt;        | :? Vector2 as v -&amp;gt; this.CompareTo(v)&lt;br /&gt;        | _ -&amp;gt; invalidArg &amp;quot;other&amp;quot; &amp;quot;Must be an instance of Vector2&amp;quot;&lt;br /&gt;&lt;br /&gt;    member this.CompareTo(other : Vector2) =&lt;br /&gt;        let dx = lazy (this.x - other.x)&lt;br /&gt;        let dy = lazy (this.y - other.y)&lt;br /&gt;&lt;br /&gt;        if dx.Value &amp;lt; 0.0 then -1&lt;br /&gt;        elif dx.Value &amp;gt; 0.0 then +1&lt;br /&gt;        elif dy.Value &amp;lt; 0.0 then -1&lt;br /&gt;        elif dy.Value &amp;gt; 0.0 then +1&lt;br /&gt;        else 0&lt;br /&gt;        &lt;br /&gt;    // Overrides for System.Object&lt;br /&gt;    override this.ToString() = sprintf &amp;quot;(%f, %f)&amp;quot; this.x this.y&lt;br /&gt;    override this.Equals(other) = this.CompareTo(other) = 0&lt;br /&gt;    override this.GetHashCode() = (this.x, this.y).GetHashCode()&lt;br /&gt;&lt;br /&gt;    // Explicit interface implementations&lt;br /&gt;    interface System.IComparable&amp;lt;Vector2&amp;gt; with&lt;br /&gt;        member this.CompareTo(other) = this.CompareTo(other)&lt;br /&gt;&lt;br /&gt;    interface System.IComparable with&lt;br /&gt;        member this.CompareTo(other) = this.CompareTo(other)&lt;br /&gt;&lt;br /&gt;    interface System.IEquatable&amp;lt;Vector2&amp;gt; with&lt;br /&gt;        member this.Equals(other) = this.CompareTo(other) = 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The use of private on line 4 makes the representation (not the type itself or its methods) private to the enclosing module (Thanks to Anton for pointing that out in the comments).&lt;br /&gt;Members can access the object through an identifer (this), and open recursion is covered.&lt;br /&gt;Vector2 can be used as one would expect to be able to use an object, as illustrated below.&lt;br /&gt;Dynamic dispatch is exercised by Array.sortInPlace (which calls CompareTo).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;let playWithIt() =&lt;br /&gt;    let v = Vector2.New(0.0, 2.0)&lt;br /&gt;    let v2 = Vector2.New(v.y, -v.x)&lt;br /&gt;    printfn &amp;quot;%s and %s have %s lengths&amp;quot;&lt;br /&gt;        (v.ToString())&lt;br /&gt;        (v2.ToString())&lt;br /&gt;        (if (let epsilon = 1e-6 in abs(v.Length - v2.Length) &amp;lt; epsilon)&lt;br /&gt;            then&lt;br /&gt;            &amp;quot;close&amp;quot;&lt;br /&gt;            else&lt;br /&gt;            &amp;quot;different&amp;quot;)&lt;br /&gt;        &lt;br /&gt;    let rnd = System.Random()&lt;br /&gt;    let vs = [| for i in 1..10 -&amp;gt; Vector2.New(rnd.NextDouble(), rnd.NextDouble()) |]&lt;br /&gt;    Array.sortInPlace vs&lt;br /&gt;    printfn &amp;quot;%A&amp;quot; vs&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I cannot write an entire article about OOP and not mention inheritance. F#-specific datatypes do not support inheritance, but I will try to show in a later post why this is not as big a problem as one might think.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3218566300402897173?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3218566300402897173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3218566300402897173' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3218566300402897173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3218566300402897173'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/07/oop-without-classes-in-f.html' title='OOP without classes in F#'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5412161595859284021</id><published>2011-07-08T07:04:00.000-07:00</published><updated>2011-07-08T07:10:58.225-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='gc'/><title type='text'>Reference-counting just isn't enough and actually is harmful</title><content type='html'>I recently came across a blog entry titled &lt;a href="http://mortoray.wordpress.com/2011/03/30/why-garbage-collection-is-not-necessary-and-actually-harmful/"&gt;"Why Garbage Collection is not Necessary and actually Harmful"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I used to share the same opinion in my C++ days, when I used to think no better language could be written. A few years later, I have drastically changed my opinion on the subject. I am not going to address all points made against garbage collection, and instead will focus on one issue: The claim that reference-counting is a viable alternative.&lt;br /&gt;&lt;br /&gt;Reference-counting is an automatic memory management system where memory allocated to an object is freed when the object is no longer referred to. C++ makes it relatively easy to replace pointers by wrappers that act like pointers, with the addition that reference counts in objects are automatically increased and decreased, as wrappers are created and destroyed.&lt;br /&gt;&lt;br /&gt;Reference-counting by itself is flawed as it does not account for cycles. The aim of automatic memory management is to deallocate memory when it is no longer reachable from the program. Reference-counting deallocates memory when it is no longer reachable from reference-counted objects. These two coincide only in the absence of cycles (and provided a number of other conditions are met, e.g. all reference-counted objects are referenced through wrappers)&lt;br /&gt;&lt;br /&gt;Edaqa says:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;simple reference counting also covers the vast majority of memory management needs. Sweeping collection has a distinct feature of being able to resolve cyclic dependencies. That is when A points to B and B points to A. Reference counting cannot manage this in the general case.&lt;br /&gt;&lt;br /&gt;Obviously if you have such a feature you will make use of it. I don’t see however that cyclic dependencies are a significant obstacle in most programs. Such object relationships can normally be resolved, or significantly mitigated, by one of a number of other techniques.&lt;/blockquote&gt;&lt;br /&gt;I strongly object to the claim that cyclic dependencies are not a significant obstacle in most programs. It may be so in version 1.0 of a program, but even that is stretching it. A reference-counting based memory recollection can introduce enough chaos into a software product that early retirement may be needed earlier than expected.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Potential cyclic dependencies are hard to detect.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It might seem at first that it should be possible and easy to detect cycles when looking at the class diagram. In practice, detecting loops involving more than 3 steps is in my experience tricky. Maybe not when you first design your classes, but when you or someone else alters it later. A developer who does not have the entire class diagram at his disposal or in his mind simply cannot know whether an addition can introduce cycles or not.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Actual cyclic dependencies are harder to detect.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cycles at the class level are not necessarily problematic. There are moreover very common. Consider for instance the usual definition of lists:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c++"&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;struct Node&amp;lt;T&amp;gt; {&lt;br /&gt;   T data;&lt;br /&gt;   struct Node&amp;lt;T&amp;gt;* next;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Although it is in theory possible to create a cyclic list, this should never happen in any run of the program. How does one convince oneself that this is indeed the case? The problem is solved for lists through the use of a safe API, but home-made more complex types seldom offer such an API.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;There is no easy way to deal with cycles.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In order to avoid memory leaks, cycles must be broken in one way or another. This involves manually decreasing the count of an object, or simply not accounting for a reference.&lt;br /&gt;&lt;br /&gt;The problem here is which link to choose in the cycle? Obviously, the link must be part of the cycle. Finding a candidate can be difficult by itself for the reasons mentioned above, and there is another restriction. The candidate link must never be a potential member of a cycle-free path for any run of your program, or you might end up deallocating objects that are still in use.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The real problem with reference-counting and avoiding cycles is that there is no good way to convince oneself of the absence of bugs through static analysis or inspection of source code. Absence of cycles is a dynamic property of program runs, and is therefore difficult to analyse. Testing might help, but to my knowledge, few write and maintain test cases specifically for the purpose of validating reference counting.&lt;br /&gt;&lt;br /&gt;What makes matters worse is that it's very easy to mistake reference-counting pointer wrappers for substitutes to classic pointers. Systematically using the wrappers often ends up introducing memory leaks. Fixing them introduces dangling pointers.&lt;br /&gt;&lt;br /&gt;Mark-and-sweep is no silver bullet, but at least it's a bullet aimed in the right direction.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5412161595859284021?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5412161595859284021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5412161595859284021' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5412161595859284021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5412161595859284021'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/07/reference-counting-just-isnt-enough-and.html' title='Reference-counting just isn&apos;t enough and actually is harmful'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-301164622568793823</id><published>2011-06-26T02:02:00.000-07:00</published><updated>2011-06-26T02:02:27.613-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><title type='text'>My impressions of F# after three years</title><content type='html'>It will be soon 3 years that I have been using F# both professionally and privately.&lt;br /&gt;&lt;br /&gt;At &lt;a href="http://www.prover.com/"&gt;work&lt;/a&gt;, I have used it to implement the simulator module of Prover iLock. This is a complete rewrite of the first version of the simulator, which was initially written in C#. The rewrite was necessary for a number of reasons. As is often the case with the first version of any software, its design did not age well, leading to bugs, excessive memory use and long execution times. I think the main reason was simply that requirements were not clear when the project was started.&lt;br /&gt;&lt;br /&gt;The main challenge of this simulator is to support distributed systems where components use different execution models and link protocols. The term "execution model" is a bit specific to the field, namely railway signalling systems. Historically, these systems were implemented using relays. Their modern counter-parts include relays (they are still popular), software which emulates relays (to take advantage of existing field knowledge and practices) and to a lesser extent procedural languages.&lt;br /&gt;The second category include platforms such as VHLC and Microlok, but there are many other similar yet different technologies. Although similar, they all differ slightly in how they handle communication with remote devices, how timers are handled, in what order instructions are executed...&lt;br /&gt;&lt;br /&gt;I am happy to report that so far, most of the objectives for the new implementation have been reached or exceeded:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Adding a new platform takes little effort.&lt;/li&gt;&lt;li&gt;Memory use has drastically gone down, despite massive use of short-lived arrays to hold state.&lt;/li&gt;&lt;li&gt;Run-time efficiency is OK, although a bit worse than the first version in some cases. The main reason here is that I made no attempt to perform some of the&amp;nbsp;optimizations that introduced bugs in the first version (maintaining consistency with respect to time when simulating distributed systems is difficult).&amp;nbsp;&lt;/li&gt;&lt;li&gt;Few known bugs.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Time will tell how this second version ages, but so far, I haven't needed to spend a lot of time extending or fixing it. Which is a bit sad, as it means I am not spending as much time working with F# as I would like :)&lt;br /&gt;&lt;br /&gt;Another important F# module I developed was a bridge translating the C# representation of systems from the main program to the simulator module. This other project is also successful. The main lesson learned is not to reuse data between different software modules. This may sound surprising at first, but the gains of designing data structures that do one thing well outweigh the costs of maintaining similar types which appear to duplicate code. The data structures in the main program are designed to make it easy to build and modify them via a scripting API. The data structures in the simulator are designed for efficiency of simulation.&lt;br /&gt;&lt;br /&gt;Defining types in F# is easily done thanks to records and discriminated unions. Translating from one type hierarchy to another is facilitated by pattern matching. I'm inclined to think the lack for these constructs in other languages leads to excessively large and complex data-types, as they try solve multiple problems at once. Although the evils of code duplication are well known, there are also risks associated to excessive code sharing. Getting the right balance in the number of data types requires a flexible and rich family of types, and it's now clear to me that C# is too poor in that respect. Classes and enums are not enough.&lt;br /&gt;&lt;br /&gt;I have used F# in a range of projects, mostly game-related. &lt;a href="http://marketplace.xbox.com/en-US/Product/Asteroid-Sharpshooter/66acd000-77fe-1000-9115-d80258550797"&gt;Asteroid Sharpshooter&lt;/a&gt; was released in January. Although not a commercial success (168 copies sold so far), it showed it was possible to write games with high performance requirements in F#, despite the &lt;a href="http://sharp-gamedev.blogspot.com/2011/02/why-we-need-better-garbage-collection.html"&gt;weaknesses&lt;/a&gt; of .Net on the Xbox 360. I have not gotten a single bug report so far, but this may be due to the small amount of users. Its rating of slightly over 3 stars out of 5 seems to indicate users are moderately satisfied with the game.&lt;br /&gt;&lt;br /&gt;I have also developed a "&lt;a href="http://sharp-gamedev.blogspot.com/2011/01/untying-game-update-loop.html"&gt;new&lt;/a&gt;" way of developing game user interfaces which I think blows the "old" way out of the water. The new way I am&amp;nbsp;referring&amp;nbsp;too allows to write reactive UIs over the game update loop in a simple way, allowing for much faster development and more robust software. The old way either leads to unresponsive interfaces or buggy ones that fail to deal with storage management or any other lengthy processing requiring asynchronous programming. I doubt many programmers without a functional background realize the power of computation expressions in F#.&lt;br /&gt;&lt;br /&gt;By the way, I often hear and read that "F# is not good for UI". This is total nonsense. I normally try to express myself in a gentle, moderate, non-controversial way on this blog, so just to emphasize how I feel about this:&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;b&gt;"F# is not good for UI" is total nonsense&lt;/b&gt;.&lt;/div&gt;&lt;br /&gt;There are basically two problems with UI.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Lots of boring code to write: widget layout, boiler-plate...&lt;/li&gt;&lt;li&gt;Achieving good responsiveness&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Point 1 is addressed by tools and code generation, and is actually language-independent. What do I care if automatically-generated code is in C#, IL or F#? As long as I don't have to write it...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even in the case when I do write the code myself, I don't find C# and F# to differ significantly in that matter. F#'s supported for nested &amp;nbsp;variable and function definitions help limit the number of members in a class, which avoids one of C# problems, namely over-blown classes with numerous private fields and methods.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Point 2 is solved by F#'s async. In that respect, I wonder how people have been dealing with the problem in C#? BackgroundWorker and threads are not so fun to use.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In all my projects, I think I have noticed two strong differences with developing in a C++-like procedural language:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;I spend a lot less time debugging. Modulo trivial bugs, functional code that is correctly typed just works out of the box. Any time I went out of the pure functional path to introduce mutability, direct access to items in arrays... I introduced bugs.&lt;/li&gt;&lt;li&gt;The relatively low verbosity of F# and its high-level constructs make it easier to implement more complex algorithms. For instance, I could never get my head around Runge-Kutta(4) in C++, implementing it in F# was trivial, all while learning F#.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;On the negative sides, I found that Visual Studio's debugger can be difficult to use with F#. In other words, it's good you don't spend a lot of times debugging, because it can be hard to understand what's going on in the debugger. Two of the main issues, I think, reside on the one hand in the fact that a debugger is statement and line oriented, where a functional language is expression-oriented, and on the other hand in a somewhat confusing handling of F# closures and lambdas by the debugger. For instance, debugging code in computation expressions is close to impossible.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's all for now. If you are decision-taker in your company, and .Net is part of the technologies you use, I think you simply cannot afford not looking at F#. I know every time a new language is introduced, productivity gains are claimed by its inventors.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I did not invent F# and don't work for Microsoft, but I can vouch for the&amp;nbsp;alleged&amp;nbsp;productivity gains. Your mileage may vary, but I don't think it will.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-301164622568793823?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/301164622568793823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=301164622568793823' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/301164622568793823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/301164622568793823'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/06/my-impressions-of-f-after-three-years.html' title='My impressions of F# after three years'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8998535464553372070</id><published>2011-06-10T02:42:00.000-07:00</published><updated>2011-06-10T02:42:30.193-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='speculation'/><title type='text'>Is that a cloud, or is it a storm?</title><content type='html'>I was recently forced to spend some time at a &lt;a href="http://jode0178.blogspot.com/2011/06/week-end-spent-in-hospital.html"&gt;hospital &lt;/a&gt;due to a bowel inflammation. The inflammation is due to a chronic disease whose cause is still unknown. It's also not clear whether there are non-surgical treatments to completely cure the disease. I won't go into details in this post, suffices it to say the event has distracted me a bit from my usual focus on games, Xbox360 and XNA. &lt;br /&gt;&lt;br /&gt;Let me start with a few words about nutrition journals. Although there is little scientifically established information about  the link between food types and inflammations of the digestive tract, many patients report that  specific diets do help. The problem is that there does not  seem to be any single diet that fits all.&lt;br /&gt;&lt;br /&gt;It is therefore important for each individual to assess the  effect of each food type on one's digestive system. Any good programmer  knows it: before you optimize, you need to measure. The same goes for  nutrition. Before doing changes to one's regime, it is important to keep track of what goes in and, well, what comes  out.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The difficulty is that keeping such a journal requires  discipline, as it's best to record that information as soon as meals are  eaten, and directly after visits to the bathroom.&lt;br /&gt;&lt;br /&gt;This is were mobile devices and the net comes into the picture. Smart phones make it easy to fill in the journal. The journal itself is probably best kept on a central server (in the "cloud") in order to be accessible from anywhere at any time through any device. &lt;br /&gt;&lt;br /&gt;All of this is a good excuse for me to start having fun with &lt;a href="http://websharper.com/Home.aspx"&gt;WebSharper&lt;/a&gt; and F#, of course. WebSharper makes it possible to design web applications entirely in F#. The client code is compiled into javascript and executed in the browser.&lt;br /&gt;&lt;br /&gt;The recent panic about &lt;a href="http://www.reddit.com/r/programming/comments/hve2i/silverlight_and_net_what_role_will_they_play_in/"&gt;.NET and Silverlight being dropped from Windows 8&lt;/a&gt; is interesting in many aspects. .NET developers are reluctant to switch to javascript, a feeling I share and understand. The current tendency however seems to use javascript as a virtual machine targeted by a range of nicer technologies. Examples include F# through WebSharper, &lt;a href="http://hildr.luminance.org/Platformer/Platformer.html"&gt;XNA&lt;/a&gt;, &lt;a href="http://www.reddit.com/r/programming/comments/alrwd/jsc64_is_a_c64_emulator_written_in_javascript/"&gt;emulators&lt;/a&gt;... I for one rejoice in Microsoft's adoption of open standards.&lt;br /&gt;&lt;br /&gt;But do I? I see Windows 8 as an attempt to regain control over the Web. What place will have competing web browsers (Firefox, Google Chrome, Opera...) in the new operating system when it includes it's own browser as a mandatory component? If the web view of Windows 8 succeeds in pushing out other browsers, Microsoft will be free to invent new technologies, forcing others to play catch up. Are we getting back to the Windows 98 and "optimized for IE6" days?&lt;br /&gt;&lt;br /&gt;Happily, I don't see that happening. Non-Microsoft smart phones and tablets have conquered large portions of territory once owned by Microsoft and Intel. Hopefully HTML5+js will gain adoption and proper support across all platforms.&lt;br /&gt;&lt;br /&gt;Note that the irrelevance of platform-specific technologies such as Silverlight applies to others as well. Why keep making iPhone and Android apps when you can make a web app instead? Are the specificities of GUIs compelling arguments to redevelop client apps multiple times? Will users be willing to pay for apps when free web apps become ubiquitous?&lt;br /&gt;&lt;br /&gt;We can turn to the PC platform to find hints of answers. The computing power they offer still has no equivalent in the cloud, and demanding applications such as development tools, CAD and video games will always feel best at home on a PC. I expect those applications to keep being developed using a mix of native and VM-based languages and frameworks.&lt;br /&gt;&lt;br /&gt;Is there a similar place on the smart phone? Applications requiring unrestricted access to the mobile's resources come to my mind. This includes media players, games, device management... I expect however that a very large eco-system based on "silly apps" will soon disappear, possibly in a very sudden manner.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8998535464553372070?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8998535464553372070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8998535464553372070' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8998535464553372070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8998535464553372070'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/06/is-that-cloud-or-is-it-storm.html' title='Is that a cloud, or is it a storm?'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4455760586476353985</id><published>2011-05-03T14:52:00.000-07:00</published><updated>2011-05-03T14:57:47.092-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>The myths about the risks of introducing F# in your development team</title><content type='html'>At work we are a couple people who have been using F#. All people who have used it are enthusiastic, yet I was surprised today when I heard a project leader had asked to limit the use of F#. &lt;br /&gt;&lt;br /&gt;There is a question on programmers' stack exchange which touches the subject titled &lt;a href="http://programmers.stackexchange.com/questions/29912/real-world-pitfalls-of-introducing-f-into-a-large-codebase-and-engineering-team"&gt;"Real world pitfalls of introducing F# into a large codebase and engineering team"&lt;/a&gt;. I'm quoting:&lt;br /&gt;&lt;blockquote&gt;1) Everyone has to learn F#, and it's not as trivial as switching  from, say, Java to C#.  Team members that have not learned F# will be  unable to work on F# parts of the codebase.&lt;br /&gt;2) The pool of hireable F# programmers, as of now (Dec 2010) is  non-existent.  Search various software engineer resume databases for  "F#", way less than 1% of resumes contain the keyword.&lt;/blockquote&gt;The fear is that maintaining F# code might be difficult because current employees and job applicants lack functional programming skills.&lt;br /&gt;&lt;br /&gt;It seems some decision makers are still stuck at the time when C# 1.0, C++ and Java 2 were the languages of choice. Since then, a few things have happened.&lt;br /&gt;&lt;br /&gt;Firstly, Python has become hugely popular. Although many were horrified by its use of white space to delimit blocks, &lt;i&gt;it would be difficult to take seriously a programmer who claims he can't adjust to Python's syntax&lt;/i&gt;. Some love it, some hate it, but all can write Python code.&lt;br /&gt;Why would the syntax of F# be any harder to adopt?&lt;br /&gt;&lt;br /&gt;Secondly, C# has introduced a number of functional programming and other high-level concepts in each new version that has come out. Modern C# programmers are expected to master LINQ to objects, lambdas and yield return. The next version will introduce a specific syntax for asynchronous programming.&lt;i&gt; Would you consider hiring a programmer would admits he knows nothing about these features and is unwilling to learn about them?&lt;/i&gt;&lt;br /&gt;F#'s higher order functions, functions as first-class citizen, sequence expressions and asynchronous workflows match directly the modern features of C#. Why would these be harder to use in F# than in C#?&lt;br /&gt;&lt;br /&gt;Dear reader, if you are a decision maker, I hope these two simple remarks dissipated your fears. You may be wondering why adopt F# when C# is evolving? You won't hear it from Microsoft, but the fact is that C# is breaking at the seams in its attempts to bring in new constructs. I won't give an exhaustive list, but here are a few examples of the limits of C#:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Limits of &lt;a href="http://stackoverflow.com/questions/1217729/in-c-why-cant-an-anonymous-method-contain-a-yield-statement/1217757#1217757"&gt;iterator blocks (yield return)&lt;/a&gt;. No such restriction in F#.&lt;/li&gt;&lt;li&gt;&lt;a href="https://msmvps.com/blogs/peterritchie/archive/2010/11/03/deep-dive-on-closure-pitfals.aspx"&gt;Closures capture variables, not values&lt;/a&gt;. In F#, closures capture values, which is in my opinion a much saner design decision.&lt;/li&gt;&lt;li&gt;Language-integrated queries are nice, but they don't sound as generic as they actually are. F#'s notion of quotation is more elegant, and makes it easier to see the applicability of LINQ beyond SQL.&lt;/li&gt;&lt;li&gt; Although it's nice that C# is "stealing" async from F#, why not introduce the more general concept of custom workflows?&lt;/li&gt;&lt;/ol&gt;Moreover, F# supports a few data-types that somehow got forgotten when class-based OOP became dominant, namely records and discriminated unions. Together with pattern-matching, they are doing their come-back in the main stream and I have no doubt they will shortly become tools top programmers are expected to master.&lt;br /&gt;&amp;nbsp; &lt;br /&gt;Now, I'm not saying you should ditch C# and replace it "en masse" by F#. C# has better tooling support, features implicit conversions and a lighter syntax for implicit interface inheritance. I don't think these features are a must-have in all situations, but they can be handy at times.&lt;br /&gt;&lt;br /&gt;Adopting all new hyped technologies has its dangers, but if you refrain from getting on with the times because of a few dinosaurs among your developers, your business will eventually go the way of the dinosaurs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4455760586476353985?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4455760586476353985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4455760586476353985' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4455760586476353985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4455760586476353985'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/05/myths-about-risks-of-introducing-f-in.html' title='The myths about the risks of introducing F# in your development team'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6906557297757438802</id><published>2011-04-30T01:39:00.000-07:00</published><updated>2011-04-30T01:39:17.239-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='worldconquest'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><title type='text'>Planing and designing WorldConquest</title><content type='html'>I have been using &lt;a href="http://www.fogcreek.com/fogbugz/"&gt;fogbugz &lt;/a&gt;from FogCreek to plan and track my previous project, Asteroid Sharpshooter. So called "on-demand" installations are free for single developers. I chose fogbugz over other free alternatives because it's the only platform that I know of supporting a time planning process that has been thoroughly thought out, namely &lt;a href="http://www.joelonsoftware.com/items/2007/10/26.html"&gt;evidence-based scheduling&lt;/a&gt; (EBS for short).&lt;br /&gt;&lt;br /&gt;One of the dev teams at work is also using fogbugz, but we haven't been able to validate the value of EBS, possibly because I'm the only one interested enough in both programming and planning to follow the process in a disciplined way. One of the problems of the method is that it basically requires a waterfall design process, which isn't very popular these days in professional circles.&lt;br /&gt;&lt;br /&gt;I am curious to see whether my use of EBS for the development of WorldConquest will validate the nice ideas upon which EBS is built.&lt;br /&gt;&lt;br /&gt;My time estimates for implementing simultaneous turns in the game have shown to be wildly off-target. I thought writing to state update function would take 3 hours. I am now reaching 16 hours, and I am still in the testing phase.&lt;br /&gt;&lt;br /&gt;It turned out executing orders in parallel can be tricky due to conflicts. For instance, how do you handle a melee attack order and a regular move order. The first order causes the attacking unit to move towards the targeted unit and attack it when it reaches it. But what happens if the targeted unit has an order to move away? The same kind of issues arise for units embarking and disembarking, if the transporting unit moves or is destroyed.&lt;br /&gt;&lt;br /&gt;There are quite a few ways to resolve these issues, solving is really just a matter of deciding. Still, having a clear understanding of the design before implementing it is necessary, and I find that using data-flow graphs really helps. I use &lt;a href="http://www.yworks.com/en/products_yed_about.html"&gt;yED&lt;/a&gt; to draw graphs. This tool can redo the layout of graphs all by itself, a feature I cannot live without. It really beats drawing on paper or drawing on screen without automatic layout.&lt;br /&gt;&lt;br /&gt;I ended up with the design below:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-q5SUUs4sxKo/TbvIjrTfKpI/AAAAAAAAAko/6eDNNpoQHxE/s1600/game+state+update.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-q5SUUs4sxKo/TbvIjrTfKpI/AAAAAAAAAko/6eDNNpoQHxE/s320/game+state+update.png" width="274" /&gt;&lt;/a&gt;&lt;/div&gt;Boxes are operations, octagons are data. It's not a very complex process, but trying to implement it without a proper design (as I was hoping to do at first) is not an option.&lt;br /&gt;Here is the implementation of the function that puts all parts together:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;let update (gs : GameState) (orders : Order[][]) =&lt;br /&gt;    let damages =&lt;br /&gt;        seq {&lt;br /&gt;            for player in 0 .. gs.player_units.Length - 1 do&lt;br /&gt;                let player_id = PlayerId player&lt;br /&gt;                let attacks = extractAttackOrders gs.player_units.[player] player orders.[player]&lt;br /&gt;                yield! computeDamages gs player attacks |&gt; accumulateDamage                &lt;br /&gt;        }&lt;br /&gt;        |&gt; dict&lt;br /&gt;&lt;br /&gt;    let getDamages u =&lt;br /&gt;        match damages.TryGetValue(u) with&lt;br /&gt;        | false, _ -&gt; 0.0f&lt;br /&gt;        | true, x -&gt; x&lt;br /&gt;&lt;br /&gt;    let gs = applyDamage gs getDamages&lt;br /&gt;&lt;br /&gt;    let dead_units = getUnitDeaths gs damages&lt;br /&gt;&lt;br /&gt;    let isDead u =&lt;br /&gt;        dead_units.Contains u&lt;br /&gt;&lt;br /&gt;    let player_units =&lt;br /&gt;        [|&lt;br /&gt;            for player in 0 .. gs.player_units.Length - 1 do&lt;br /&gt;                let player_id = PlayerId player&lt;br /&gt;                let units = gs.player_units.[player]&lt;br /&gt;                let orders = orders.[player]&lt;br /&gt;&lt;br /&gt;                let isThisDead u = isDead(player_id, u)&lt;br /&gt;                let move_orders =&lt;br /&gt;                    extractMoveOrders units player orders&lt;br /&gt;                    |&gt; filterDeadMoveOrders isThisDead&lt;br /&gt;&lt;br /&gt;                let early_disembark, late_disembark = extractDisembarkOrders units player orders&lt;br /&gt;                let late_disembark = filterDeadDisembarkOrders isDead player late_disembark&lt;br /&gt;                let disembark_orders = Array.concat [early_disembark ; late_disembark]&lt;br /&gt;&lt;br /&gt;                let embark_orders =&lt;br /&gt;                    extractEmbarkOrders units player orders&lt;br /&gt;                    |&gt; filterDeadEmbarkOrders isDead player&lt;br /&gt;                                &lt;br /&gt;                let units = applyMoves move_orders units&lt;br /&gt;&lt;br /&gt;                yield&lt;br /&gt;                    units&lt;br /&gt;                    |&gt; growUnitTree embark_orders disembark_orders&lt;br /&gt;                    |&gt; shrinkUnitTree embark_orders disembark_orders&lt;br /&gt;        |]&lt;br /&gt;&lt;br /&gt;    { gs with player_units = player_units }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I have found that comprehensions and the pipeline operator |&gt; are very nice tools to process arrays of units.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6906557297757438802?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6906557297757438802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6906557297757438802' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6906557297757438802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6906557297757438802'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/04/planing-and-designing-worldconquest.html' title='Planing and designing WorldConquest'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-q5SUUs4sxKo/TbvIjrTfKpI/AAAAAAAAAko/6eDNNpoQHxE/s72-c/game+state+update.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-9113862548591639194</id><published>2011-04-30T01:03:00.000-07:00</published><updated>2011-04-30T01:03:48.285-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='worldconquest'/><title type='text'>My next project: WorldConquest</title><content type='html'>I started working on a new project during the 2010 Christmas break. It's a turn-based strategy game whose working title is WorldConquest. The final title will differ, as there already are quite a few strategy games with identical or similar names.&lt;br /&gt;&lt;br /&gt;The game is loosely based on a &lt;a href="http://gemcandy.atari-users.net/index.php?name=Reviews&amp;amp;req=showcontent&amp;amp;id=27"&gt;game&lt;/a&gt; for Atari ST written by Alois Felber from WisiSoft games in 1992.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-WPn1CzfwFx0/Tbu4_J09GTI/AAAAAAAAAkk/YSERBo8ovXg/s1600/wconq.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="239" src="http://4.bp.blogspot.com/-WPn1CzfwFx0/Tbu4_J09GTI/AAAAAAAAAkk/YSERBo8ovXg/s320/wconq.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-qSniCaM7CFY/Tbu49RVMeBI/AAAAAAAAAkg/LswDdotpsEs/s1600/WorldConquest_001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-qSniCaM7CFY/Tbu49RVMeBI/AAAAAAAAAkg/LswDdotpsEs/s1600/WorldConquest_001.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The new game will feature the same units as the original game. I am planning improvements of my own, some of which are already implemented.&lt;br /&gt;&lt;br /&gt;The original game used square tiles, I will be using hexagonal tiles. Although the new game will be turn-based it will use a simultaneous variant where players plan their moves simultaneously. When all players are ready, orders are executed simultaneously. The game will support on-line and hot-seat multiplayer. I have been thinking about and planning AI from day one. Although my experience in this domain&lt;br /&gt;At this point, I have implemented map generation and some parts of AI, namely path finding. Execution of orders is what I am working on now. Design and basic implementation are done, I am testing and fixing bugs.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;I am still open about the platforms I will target. The genre should fit hand-held devices such as smart phones and iPad-style tablets. PC and Mac will probably be first, as these are the only platforms that might have the CPU required to run a rough and slow AI. I would also love to publish on Xbox Live Indie Games, but the prospects are uncertain. On one hand this is a genre that isn't much represented on this market, but on the other hand I am not sure console gamers are the right customer base. Moreover, the .Net platform on Xbox features a poor garbage collector which requires code to be written in a very specific way, and I feel designing and implementing AI is challenging enough as it is. Adding constraints on allocation of temporary objects would add to the difficulty, and "optimising" code to work around the weakness of the garbage collector isn't my idea of fun.&lt;br /&gt;To summarize, the platforms will may include the following, ordered by decreasing order of priority and likeliness:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;PC / Windows using XNA&lt;/li&gt;&lt;li&gt;Mac and PC/Linux using Mono and possibly a port of XNA&lt;/li&gt;&lt;li&gt;Windows Phone 7 with XNA; although the garbage collector there currently suffers the same problems as on Xbox, announcements were made during MIX11 that the Mango update would introduce a new ephemeral garbage collector&lt;/li&gt;&lt;li&gt;Xbox 360 with XNA if the next update includes improvements to the garbage collector. No announcements have been made, but I'm hoping that &lt;a href="http://www.microsoftgamefest.com/"&gt;Gamefest 2011&lt;/a&gt; will bring positive news. &lt;/li&gt;&lt;li&gt;Android using Mono. I have no idea what technical limitations Mono on Android has when it comes to efficiency and garbage collection, but I'm hopeful the Mono team will be working hard to lift whatever limitations there might be. Unlike Microsoft's .Net, it's also easier to see where Mono is heading.&lt;/li&gt;&lt;li&gt;iPhone and iPad using Mono would be nice, but it does not seem feasible at this time. F# relies on generic virtual methods for function values, which are a corner stone of functional programming. Unfortunately, restrictions on run-time code generation on iPhone (and I guess iPad) make these hard to support. Sadly, this probably means no support for these platforms.&lt;/li&gt;&lt;/ol&gt;Although the game itself won't be free software, I will update XNAUtils with whatever reusable code I will write. This includes A* path-finding, a UI framework supporting menus and a network component.&lt;br /&gt;&lt;br /&gt;I am planning several iterations, steadily moving toward a Civilization-style strategy game. I will release the source code of old iterations as new ones are published.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-9113862548591639194?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/9113862548591639194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=9113862548591639194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/9113862548591639194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/9113862548591639194'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/04/my-next-project-worldconquest.html' title='My next project: WorldConquest'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-WPn1CzfwFx0/Tbu4_J09GTI/AAAAAAAAAkk/YSERBo8ovXg/s72-c/wconq.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4823545735810420484</id><published>2011-04-29T09:16:00.000-07:00</published><updated>2011-04-29T09:16:56.076-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='fsi'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='gc'/><title type='text'>Using F# scripts for testing and performance measurement</title><content type='html'>I have just heard about a new project being started by a game developer, &lt;a href="http://www.xnajunkie.com/2011/04/26/nperformant-volunteers-needed/"&gt;NPerformant&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The developer writes&lt;br /&gt;&lt;blockquote&gt;At various times in my “day job/career” I’ve used commercial profilers  with varying results, but I don’t want or need to profile the whole  application or even a whole library. &amp;nbsp;I also don’t want to code two  solutions into my product in order to let a normal profiler test them  side by side in order to remove the loser later.&lt;/blockquote&gt;The problem about creating additional solutions also occurs in testing and when writing small utilities and editors while developing your game.&lt;br /&gt;&lt;br /&gt;F# scripts help avoid this issue. You can add number of .fsx files to your project, and executing them using F# interactive (aka fsi) is very easy. For my current game, I have a script to render parts of my engine data using XNA and winforms, and another script to test some of the game logic. I don't know how long I will need these, but the day I lose the use for them, removing them is as easy as removing a single file from your project. Compare that to removing an entire project, which in my case would involve getting out of Visual Studio and using Windows Explorer then TortoiseHg.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-nHgXsQz3lJE/TbrkT3zwEhI/AAAAAAAAAkc/tx8J7wT6NdU/s1600/AttackOrBombard.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="180" src="http://4.bp.blogspot.com/-nHgXsQz3lJE/TbrkT3zwEhI/AAAAAAAAAkc/tx8J7wT6NdU/s320/AttackOrBombard.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Back to the topic of measuring performance, did you know about the #time command you can use in fsi:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;&amp;gt; #time "on";;&lt;br /&gt;&lt;br /&gt;--&amp;gt; Timing now on&lt;br /&gt;&lt;br /&gt;randomTest();;&lt;br /&gt;Real: 00:00:15.761, CPU: 00:00:54.725, GC gen0: 1917, gen1: 2, gen2: 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that you get information about garbage collection too, which is interesting information when developing games for the Xbox 360.&lt;br /&gt;&lt;br /&gt;Regarding testing, I just found out yet another case when pattern matching saves the day. In the code extract below, I'm using it to express the expected result of the code being tested.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;match gs'.player_units with&lt;br /&gt;    | [| _; [| { health = x } |] |] when x &amp;lt; 1.0f -&amp;gt; true // Injured&lt;br /&gt;    | [| _; [||] |] -&amp;gt; true  // Killed&lt;br /&gt;    | _ -&amp;gt; false&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;player_units is an array of player units, where players units are represented using arrays of units. My test has an artillery belonging to the first player fire at a helpless infantry of the second player.&lt;br /&gt;&lt;br /&gt;The first branch of the pattern matching says: "An array composed of two elements where the first element can be anything, and the second element is a one-element array of units where x is the value of field health, and x is strictly less than 1".&lt;br /&gt;&lt;br /&gt;I don't know how I would have written that in C# in a similarly concise fashion.&lt;br /&gt;&lt;br /&gt;Informally, my pattern match checks that the unit of the second player was injured or killed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4823545735810420484?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4823545735810420484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4823545735810420484' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4823545735810420484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4823545735810420484'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/04/using-f-scripts-for-testing-and.html' title='Using F# scripts for testing and performance measurement'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-nHgXsQz3lJE/TbrkT3zwEhI/AAAAAAAAAkc/tx8J7wT6NdU/s72-c/AttackOrBombard.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6957360869241768866</id><published>2011-04-18T06:01:00.000-07:00</published><updated>2011-05-28T09:05:37.167-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>"I'll Whack Your Fingers"-Oriented Programming</title><content type='html'>Every now and then, &lt;a href="http://forums.create.msdn.com/forums/t/80685.aspx"&gt;a question about how to transfer data between game screens&lt;/a&gt; pops up on the App Hub forums. The source of the problem is that many try to solve this problem using synchronous programming. This does not work because game screens require interaction with users, which cannot be handled in a synchronous manner without freezing the game.&lt;br /&gt;&lt;br /&gt;Although F# gives you tools to solve that problem using e.g. async workflows, most people are using C#.&lt;br /&gt;&lt;br /&gt;How do you solve that problem in this language? Usually, people use a combination of events and public fields. This solution is fine, but I just don't like events much. They make bugs tricky to track, because I lose track of where handlers fit in the expected flow of execution of my code. Moreover, the only practical way that I know of to pass data from an event handler to the main code is through a shared variable (which I call "I'll Whack My Own Fingers"-oriented programming).&lt;br /&gt;&lt;br /&gt;For this reason, I suggested to use Begin-End-style asynchronous programming. This requires an implementation of IAsyncResult if you want to do it in a nice .NET-ish kind of way. I am not aware of any such implementation (EDIT: Here is &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163467.aspx"&gt;one&lt;/a&gt;, thanks mausch), so I wrote my own:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c#"&gt;/// &lt;summary&gt; &lt;br /&gt;  /// An implementation of IAsyncResult that wraps result data. &lt;br /&gt;  /// &lt;/summary&gt; &lt;br /&gt;  /// &lt;typeparam name="T"&gt;Type of the result data.&lt;/typeparam&gt; &lt;br /&gt;  class AsyncResult&amp;lt;T&amp;gt; : IAsyncResult, IDisposable { &lt;br /&gt;    public AutoResetEvent signal = new AutoResetEvent(false); &lt;br /&gt;    public bool isDone = false; &lt;br /&gt;    public T result = default(T); &lt;br /&gt; &lt;br /&gt;    public object AsyncState { &lt;br /&gt;      get { return state; } &lt;br /&gt;    } &lt;br /&gt; &lt;br /&gt;    public WaitHandle AsyncWaitHandle { &lt;br /&gt;      get { return signal; } &lt;br /&gt;    } &lt;br /&gt; &lt;br /&gt;    public bool CompletedSynchronously { &lt;br /&gt;      get { throw new NoneOfYourBusinessException(); } &lt;br /&gt;    } &lt;br /&gt; &lt;br /&gt;    public bool IsCompleted { &lt;br /&gt;      get { return isDone; } &lt;br /&gt;    } &lt;br /&gt; &lt;br /&gt;    public void Dispose() { &lt;br /&gt;      signal.Dispose(); &lt;br /&gt;    } &lt;br /&gt;  } &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Did you notice how I made all fields public? I think many a modern programmer would wince when reading this. What if some careless programmer accessed &lt;tt&gt;isDone&lt;/tt&gt; and modified it? Bad things can follow, and surely we should restrict access to these fields using the private keyword.&lt;br /&gt;&lt;br /&gt;I like to call this "I'll whack your fingers if you touch this"-oriented programming. Beside "private" and "protected", which were probably invented to tempt stressed programmers to replace them with "public", enthusiasts of this approach enjoy using "sealed" to punish users who might be tempted to reuse your code.&lt;br /&gt;&lt;br /&gt;There are better ways to prevent accidental tempering with an object's internal state: access objects via interfaces.&lt;br /&gt;&lt;br /&gt;For instance, here is the code for the Begin-End pair of methods that use my AsyncResult:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c#"&gt;/// &lt;summary&gt; &lt;br /&gt;        /// Open a MessageBoxScreen asynchronously. &lt;br /&gt;        /// &lt;/summary&gt; &lt;br /&gt;        /// &lt;params name="sm"&gt;The screen manager to which the screen is to be added.&lt;/params&gt; &lt;br /&gt;        /// &lt;params name="player"&gt;The index of the player who has control, or null.&lt;/params&gt; &lt;br /&gt;        /// &lt;params name="msg"&gt;The text of the message to show.&lt;/params&gt; &lt;br /&gt;        /// &lt;returns&gt;An object which can be used to wait for the request to complete and retrieve the result.&lt;/returns&gt; &lt;br /&gt;        public static IAsyncResult BeginShowMessage(ScreenManager sm, PlayerIndex? player, string msg) { &lt;br /&gt;          var result = new AsyncResult&lt;bool&gt;(); &lt;br /&gt; &lt;br /&gt;          var screen = new MessageBoxScreen(msg); &lt;br /&gt;          screen.Accepted += (src, args) =&amp;gt; { &lt;br /&gt;            result.isDone = true; &lt;br /&gt;            result.result = true; // User accepted the message box. &lt;br /&gt;            result.signal.Set(); &lt;br /&gt;          }; &lt;br /&gt;          screen.Cancelled += (src, args) =&amp;gt; { &lt;br /&gt;            result.isDone = true; &lt;br /&gt;            result.result = false; // User cancelled the message box. &lt;br /&gt;            result.signal.Set(); &lt;br /&gt;          }; &lt;br /&gt; &lt;br /&gt;          sm.AddScreen(screen, player); &lt;br /&gt; &lt;br /&gt;          return result; &lt;br /&gt;        } &lt;br /&gt; &lt;br /&gt;        /// &lt;summary&gt; &lt;br /&gt;        /// Wait for the user to complete interaction with a MessageBoxScreen opened with BeginShowMessage. &lt;br /&gt;        /// &lt;/summary&gt; &lt;br /&gt;        /// &lt;params name="r"&gt;The object returned by BeginShowMessage.&lt;/params&gt; &lt;br /&gt;        /// &lt;returns&gt;Whether the user accepted or cancelled the message screen.&lt;/returns&gt; &lt;br /&gt;        public static bool EndShowMessage(IAsyncResult r) { &lt;br /&gt;          var result = r as AsyncResult&lt;bool&gt;; &lt;br /&gt;          if (result == null) &lt;br /&gt;            throw new ArgumentException("Wrong type or null", "r"); &lt;br /&gt; &lt;br /&gt;          result.signal.WaitOne(); &lt;br /&gt;          result.Dispose(); &lt;br /&gt;          return result.result; &lt;br /&gt;        } &lt;br /&gt;&lt;/bool&gt;&lt;/bool&gt;&lt;/pre&gt;&lt;br /&gt;Note how BeginShowMessage and EndShowMessage return and take respectively an IAsyncResult. Unless users of these methods really want to take risks getting intimate with AsyncResult, there is no risk of tampering. And if they really want to work directly with the inner parts of AsyncResult, why prevent them to do so?&lt;br /&gt;&lt;br /&gt;I wonder, what's the point with "private" and "protected" anyway?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Thinking a bit more on the subject, I think another overused feature resides in non-virtual public methods (and fields). Anything public in the API of a class should belong to an interface, with the exception of constructors and construction helpers (which maybe should be internal to assemblies).&lt;br /&gt;&lt;br /&gt;I would however not advise to use abstract data types in all situations. Navigating in the call tree is a good way to learn a new code base, and typically abstract methods defeat this. One could say abstraction through interfaces is a form of obfuscation, as it effectively hides implementations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6957360869241768866?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6957360869241768866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6957360869241768866' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6957360869241768866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6957360869241768866'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/04/ill-whack-your-fingers-oriented.html' title='&quot;I&apos;ll Whack Your Fingers&quot;-Oriented Programming'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3454137982679667897</id><published>2011-03-04T07:50:00.000-08:00</published><updated>2011-03-05T08:37:18.702-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Asteroid Sharp Shooter: Post-mortem</title><content type='html'>&lt;span style="font-size: large;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://marketplace.xbox.com/en-US/Product/Asteroid-Sharpshooter/66acd000-77fe-1000-9115-d80258550797"&gt;Asteroid Sharpshooter&lt;/a&gt; is a game published on the Xbox LIVE Marketplace, under the independent games section.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/-hw0qGhSMKEQ/TXD6Mda7yGI/AAAAAAAAAkU/RZ8BVB_4dUo/s1600/ah-boxart-half.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/-hw0qGhSMKEQ/TXD6Mda7yGI/AAAAAAAAAkU/RZ8BVB_4dUo/s1600/ah-boxart-half.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It is written in F# and C#, using XNA Game Studio 3.1. The game falls in the category of 3d space shooters. Inspired by a classic, &lt;a href="http://en.wikipedia.org/wiki/Asteroids_%28video_game%29"&gt;Asteroids&lt;/a&gt;, the game puts the player in space, in a field filled with rocks. Some of these can be destroyed by shooting at them. The goal of the game is to shoot and destroy a number of rocks. To make things challenging, the controls of the ship are consistent with what you would expect from a ship drifting in space. There is no friction, and the ship does not necessarily point where it's headed. Controlling the ship to collect power-ups and approach asteroids to shoot requires skill. The higher difficulty levels feature enemies in the form of drones that track the player's ship and detonate themselves when they come close enough.&lt;br /&gt;&lt;br /&gt;In this article, I present my thoughts about the development process of the game and the reception of the game by players.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Development&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The game was written using Visual Studio in C# and in F#. C# is used for the higher levels of the software, which consist of menus, parts of the rendering, loading assets, loading and saving user progress.&lt;br /&gt;Menus use the game state management sample from the App Hub.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Using F#&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;F# is a good programming language in general, and contributed  positively to the development. Features such as discriminated unions and  pattern matching are lacking in C#.&lt;br /&gt;&lt;br /&gt;Although the game uses  multiple threads, it does not use async workflows (these are primarily  intended to ease the development of asynchronous code, but they also  have interesting properties for parallel programming, as shown in my &lt;a href="http://sharp-gamedev.blogspot.com/2008/09/tutorial-7-concurrency.html"&gt; earlier blog entries&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Some of F# features were at the time &lt;a href="http://sharp-gamedev.blogspot.com/2010/03/things-that-dont-work-on-xbox.html"&gt;not supported on Xbox&lt;/a&gt; and resulted in run-time errors: sprintf and async workflows. I haven't had the occasion to try async workflows with the current version of F#, but sprintf now works!&lt;br /&gt;&lt;br /&gt;Building the game was tricky before I managed &lt;a href="http://sharp-gamedev.blogspot.com/2010/06/how-to-build-f-library-for-xbox-360.html"&gt;to hack project files&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I  initially used the free versions of Visual Studio: the Express edition  for XNA Game Studio and C#, Visual Studio Shell for F#. This worked OK,  even for debugging, but wasn't as practical of using Visual Studio Pro,  which I ended up using at the end. You can use the free editions to try  and see if F# works for you, but for regular development, you will  probably want to use the Pro edition or higher.&lt;br /&gt;&lt;br /&gt;I was a bit  worried that using F# on the Xbox might not fully work, and might even  be impossible as new versions of XNA or F# are released. Although there have been problems, all could be &lt;a href="http://sharp-gamedev.blogspot.com/2010/11/xna-gs-40-f-20-xbox-360-love.html"&gt;resolved&lt;/a&gt;, and the mix  got better or more stable with every new release. Although F# is still  not officially supported on Xbox, the fact that Microsoft Research has  developed an &lt;a href="http://marketplace.xbox.com/en-US/Product/The-Path-of-Go/66acd000-77fe-1000-9115-d8025841099f"&gt;XBLA game&lt;/a&gt; that uses F# sounds positive.&lt;br /&gt;&lt;br /&gt;F# uses  reference types for most of its data types: lists, tuples, records, classes,  discriminated unions, function values, mutable cells (ref). This can  cause problems because of the&lt;a href="http://sharp-gamedev.blogspot.com/2011/02/why-we-need-better-garbage-collection.html"&gt; limitations of the current garbage  collector on Xbox&lt;/a&gt;. I decided to design my code so that garbage collections would have a low latency, and not care too much about how often they would occur. This worked well  enough. The game triggers a garbage collection every 6 frames, which  each last for 3.5ms. The remaining time was enough to update the physics  and render all objects, but a more complex game with more models and  more complex class hierarchies could have difficulties.&lt;br /&gt;&lt;br /&gt;F# &lt;a href="http://sharp-gamedev.blogspot.com/2009/07/breaking-up-classes-using-interfaces.html"&gt;does not allow circular dependencies&lt;/a&gt; between types unless they are declared in the same file and marked as mutually dependent. I was aware of this restriction, and it did not cause me any trouble. I started the project with all C# code in one project, and all F# code in another. Toward the end, I started moving reusable code into separate libraries. For my F# code, this was little more work than moving files to a new project and changing namespaces. The task was notably more difficult in C#, as the language supports circular dependencies within assembly bounds. Breaking apart an assembly will require the introduction of interfaces at the bounds. Although F# and C# do not differ on that point, the fact that F# forces you to work that way has benefits the day you want to split your code, in addition to all other benefits that non-circular designs have (better tool support, easier to understand...).&lt;br /&gt;&lt;br /&gt;I don't know of any way to declare pass-by-reference parameters in F#, the way you can in C# using the "ref" keyword. In the XNA framework, some methods use passing by reference to save time. Although it is possible to call such functions from F# code, I don't know of any way to declare new functions.&lt;br /&gt;There is however an F# way of avoiding copying large structs when calling functions: use inlining. Last time I checked, it was not fully reliable though, as the F# compiler tends to introduce lots of unnecessary variables in inlined code. Whether the .net CLR notices that and removes these variables isn't clear to me.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Project planning and tracking&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;I have used a free account on &lt;a href="http://www.fogcreek.com/fogbugz/"&gt;fogbugz&lt;/a&gt; to organize my work and keep track of bugs. Although it may seem to be overkill, it allowed me to look at what went wrong when writing this article, as I had a record of most of the bugs. It also simplifies working on a project part-time. During my day job I can focus on my job and forget about the project. When the week-end comes, I can pick up the project where I left it, and start new tasks which were planned but not started.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Obstacles encountered&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;Although the game state management sample was very helpful to get the menu system up and running in no time, it's not obvious at first how to integrate user interaction forced by the StorageDevice API. One needs to keep track whether a device is selected, whether the user is currently selecting one... The first solution that comes to mind, using Boolean variables isn't maintainable when the number of variables grows. For instance, the device selection screen had to keep track of whether the user was signed in, currently signing in, if a title-specific storage device was chosen, being chosen, whether a user-specific storage device was chosen, being chosen. Mix that with event handlers that may need to display alert boxes, and it becomes tricky. I used handlers to deal with storage disconnection and I/O operation notification.&lt;br /&gt;Even after writing my own version of EasyStorage in F#, cleaning up code, the Update() method of my game object still looked too complicated for its own good:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:c#"&gt;protected override void Update(GameTime gameTime)&lt;br /&gt;        {&lt;br /&gt;            base.Update(gameTime);&lt;br /&gt;&lt;br /&gt;            if (titleStorageLost == GuideStates.Requested)&lt;br /&gt;            {&lt;br /&gt;                if (!Guide.IsVisible) try&lt;br /&gt;                {&lt;br /&gt;                    Guide.BeginShowMessageBox("Storage device disconnected",&lt;br /&gt;                        "The storage device used for scores was disconnected. " +&lt;br /&gt;                        "Scores will not be saved unless a new device is selected. " +&lt;br /&gt;                        "Would you like to select a device now?",&lt;br /&gt;                        new string[] { "Yes", "No" }, 0, MessageBoxIcon.Alert,&lt;br /&gt;                        (result) =&amp;gt;&lt;br /&gt;                        {&lt;br /&gt;                            var choice = Guide.EndShowMessageBox(result);&lt;br /&gt;                            if (choice.HasValue &amp;amp;&amp;amp; choice.Value == 0)&lt;br /&gt;                                requestTitleStorage = true;&lt;br /&gt;                            titleStorageLost = GuideStates.None;&lt;br /&gt;                        },&lt;br /&gt;                        null);&lt;br /&gt;                    titleStorageLost = GuideStates.Pending;&lt;br /&gt;                }&lt;br /&gt;                catch (GuideAlreadyVisibleException) { }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (titleStorageLost == GuideStates.None &amp;amp;&amp;amp; requestTitleStorage)&lt;br /&gt;            {&lt;br /&gt;                storage.RequestTitleStorage();&lt;br /&gt;                requestTitleStorage = false;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (titleStorageLost == GuideStates.None &amp;amp;&amp;amp; !requestTitleStorage &amp;amp;&amp;amp; userStorageLost == GuideStates.Requested)&lt;br /&gt;            {&lt;br /&gt;                if (!Guide.IsVisible) try&lt;br /&gt;                {&lt;br /&gt;                    Guide.BeginShowMessageBox("Storage device disconnected",&lt;br /&gt;                        "The storage device used for player progress was disconnected. " +&lt;br /&gt;                        "Progress will not be saved unless a new device is selected. " +&lt;br /&gt;                        "Would you like to select a device now?",&lt;br /&gt;                        new string[] { "Yes", "No" }, 0, MessageBoxIcon.Alert,&lt;br /&gt;                        (result) =&amp;gt;&lt;br /&gt;                        {&lt;br /&gt;                            var choice = Guide.EndShowMessageBox(result);&lt;br /&gt;                            if (choice.HasValue &amp;amp;&amp;amp; choice.Value == 0)&lt;br /&gt;                                requestUserStorage = true;&lt;br /&gt;                            userStorageLost = GuideStates.None;&lt;br /&gt;                        },&lt;br /&gt;                        null);&lt;br /&gt;                    userStorageLost = GuideStates.Pending;&lt;br /&gt;                }&lt;br /&gt;                catch (GuideAlreadyVisibleException) { }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (titleStorageLost == GuideStates.None &amp;amp;&amp;amp; userStorageLost == GuideStates.None &amp;amp;&amp;amp; !requestTitleStorage &amp;amp;&amp;amp; requestUserStorage)&lt;br /&gt;            {&lt;br /&gt;                var screens = screenManager.GetScreens();&lt;br /&gt;                if (screens.Length &amp;gt; 0)&lt;br /&gt;                {&lt;br /&gt;                    var topScreen = screens[screens.Length - 1];&lt;br /&gt;                    if (topScreen.ControllingPlayer.HasValue)&lt;br /&gt;                        storage.RequestUserStorage(topScreen.ControllingPlayer.Value);&lt;br /&gt;                }&lt;br /&gt;                requestUserStorage = false;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Since then, I have developed a &lt;a href="http://sharp-gamedev.blogspot.com/2011/01/eventually-workflow.html"&gt;better way&lt;/a&gt; of solving that kind of problem. All this code now becomes:&lt;br /&gt;&lt;pre class="brush:f#"&gt;task {&lt;br /&gt;  do! storage.CheckPlayerStorage&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Shorter, isn't it? The point is that F# has features that make it possible to compose code using a notation similar to traditional function calls, yet the execution can differ from a traditional call. The idea is so neat that the normally conservative C# design team decided to add a &lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2010/10/28/asynchrony-in-c-5-part-one.aspx"&gt;variant&lt;/a&gt; of it to the next version of the language.&lt;br /&gt;&lt;br /&gt;Back to the post-mortem, another related problem is to deal with screen transitions. There are several approaches: Hard-coding, events and delegates.&lt;br /&gt;&lt;br /&gt;Using hard-coding, screen A creates and displays screen B when a certain action is performed.&lt;br /&gt;This requires the class for screen A to know about the class for screen B, and must have the data needed during instantiation of B at hand. I found this approach was not very flexible, and caused me some trouble when I added support for local multiplayer (which wasn't planned from start).&lt;br /&gt;&lt;br /&gt;The two other approaches, events and delegates make it easier to forward the data needed to instantiate new screens, as it's typically available in the class which registers the event handler, or creates the delegates which captures the data in question.&lt;br /&gt;&lt;br /&gt;All these approaches share the same problem: the transition code is spread out all over the place, making it hard to debug, modify and extend. Of the 50 bugs I registered in fogbugz, 13 involved screen transitions at some level. For a game programmer who is interested in getting the gameplay right, getting 26% extra bugs because of menus is a very frustrating, even if most of those bugs are easy to fix.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Art assets&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Asteroid models, ship models and textures were provided by &lt;a href="http://www.benoitroche.com/"&gt;Benoit Roche&lt;/a&gt;. The title and menu music is from &lt;a href="http://www.partnersinrhyme.com/"&gt;Partners in Rhyme&lt;/a&gt;, sounds from &lt;a href="http://www.soundsnap.com/"&gt;Soundsnap&lt;/a&gt;.&amp;nbsp; The game backgrounds and the box art were done by myself using The Gimp and a tutorial on &lt;a href="http://www.gimpusers.com/tutorials/starfield-tutorial.html"&gt;starfields&lt;/a&gt;. When doing sky boxes, it's a good idea to test them on a PC screen. I failed to notice on my TV that the sides of the box had light levels that did not match. Happily, a tester on the App Hub noticed that and reported the problem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;The community on App Hub...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;... was very helpful. Thanks to all of you fellow developers for your feedback and suggestions!&lt;br /&gt;&lt;br /&gt;Due to my earlier involvement in free software and Linux, I thought that sending your game to playtest early and often was a good thing. While it was, don't expect feedback for every release. Other developers will not test your game time and again every month. Getting comments from other is a motivation boost, but you should not rely on that. I think it's a good idea to send to playtest as soon as your gameplay is done, to see how well it's received. After that, sending updates every time won't get you much feedback. It may actually be better to wait until a new milestone is reached, e.g. menus are done, art is done, game is ready for evil-checklist testing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Reception of the game&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The mix between a classic 2d game and a 3d space shooter was not well received by the market. After five weeks, the game sold 143 copies with a conversion rate of 8.06%&lt;br /&gt;Few reviews were written, most of them judging the game as dull and hard to control. This is what &lt;a href="http://www.xboxindiegames.co.uk/review.html?reviewee=asteroidsharpshooter"&gt;xboxindiegames&lt;/a&gt; had to say about the game:&lt;br /&gt;&lt;blockquote&gt;You can't steer, you can't see, you can't aim and you can't shoot.  You can avoid this game, though...&amp;nbsp; &lt;/blockquote&gt;&lt;a href="http://pencil-shavings.net/pencil-shavings/yellowpages1.htm"&gt;The Yellow Pages&lt;/a&gt; from Pencil Shavings sounded more positive:&lt;br /&gt;&lt;blockquote&gt;Looks fantastic and plays well, just a little redundant [...]. Nice game, enjoyable, but lacking variety.&lt;/blockquote&gt;I also registered the game for Dream-Build-Play 2010, but the game did not make it to the best 20.&lt;br /&gt;The game is rated 3 stars of 5 in the American Xbox LIVE Marketplace, which I think is characteristic of well-done but uninspiring games.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Conclusions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Technically, the game was a success and showed the feasibility of using F#. It took me way too much time (about two years), though. I hope I will be able to increase the production rate for my upcoming games.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3454137982679667897?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3454137982679667897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3454137982679667897' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3454137982679667897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3454137982679667897'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/03/asteroid-sharpshooter-post-mortem.html' title='Asteroid Sharp Shooter: Post-mortem'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh5.googleusercontent.com/-hw0qGhSMKEQ/TXD6Mda7yGI/AAAAAAAAAkU/RZ8BVB_4dUo/s72-c/ah-boxart-half.jpg' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8136815220274843135</id><published>2011-02-27T03:34:00.000-08:00</published><updated>2011-02-27T03:34:22.000-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Replacing LIVE functionality in XNA 4.0</title><content type='html'>Although the XNA framework supports multiple platforms, including Xbox  and Windows on PC, there are parts that are not available on Windows PC.&lt;br /&gt;&lt;br /&gt;One such part is dedicated to interacting with Xbox LIVE, such as gamer profile information, permissions, avatars. (Actually, these parts are available to developers, but not to users). That can be a problem if you want to release your Xbox game to PC. Even if you don't intend a commercial release and only want to distribute your game to your friends and family, they typically don't want to install the full SDK just so that they can run your game.&lt;br /&gt;&lt;br /&gt;Before XNA Game Studio 4.0, if you wanted to support the PC platform, you had to write an abstraction layer over these restricted features, or sprinkle your code with #ifdef. There was no way you could replace the implementation of restricted features with your own as the default implementation was embedded into the same DLLs as non-restricted parts of XNA (and you don't want to reimplement these).&lt;br /&gt;&lt;br /&gt;The release of XNA Game Studio 4.0 saw a clean-up of the organization of all assemblies. All restricted features are now confined to specific DLLs, which you can replace with your own.&lt;br /&gt;&lt;br /&gt;I have started work on my own implementation. My level of ambition is not pretty low, I only intend to achieve the kind of coverage I need for my own code to compile and run. In any case, it's available on&lt;a href="https://bitbucket.org/johdex/xnautils/src/82452002612b/XnaReplacementWindows/"&gt; bitbucket&lt;/a&gt;, so feel free to grab it, modify and extend it to your liking.&lt;br /&gt;&lt;br /&gt;I have started with Microsoft.Xna.Framework.Storage, as this is what I use in the code I mentioned in a &lt;a href="http://sharp-gamedev.blogspot.com/2011/01/safe-io-on-xbox-360-in-f.html"&gt;previous post about safe IO on Xbox&lt;/a&gt;. Here are some random observations and small things I learned in the process.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References to record types can't be null&lt;/b&gt;. The XNA framework is primarily meant for C#, and it uses null (to the delight of generations of evil peer-reviewers). I initially used records for StorageDevice and StorageContainer, and I had to change to classes when I tried my replacement with existing game code. Even F# classes aren't null-friendly by default, you have to mark classes with a special attribute to change that:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;br /&gt;type StorageDevice =&lt;br /&gt;    class&lt;br /&gt;        val drive : DriveInfo&lt;br /&gt;        val path : string&lt;br /&gt;        new (d, p) = { drive = d; path = p }&lt;br /&gt;    end&amp;nbsp;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Separating methods from data in class declarations help avoid circular dependencies&lt;/b&gt;. StorageDevice depends on StorageContainer because a method of StorageDevice is used to create instances of StorageContainer. StorageContainer depends on StorageDevice because each StorageContainer is owned by a StorageDevice.&lt;br /&gt;It would seem there is a circular dependency, which in F# must be dealt with explicitly. A simple solution consists of declaring the types as mutually dependent (using "and" instead of "type" for the second type). Another one is to move the definition of StorageDevice.BeginOpenContainer and StorageDevice.EndOpenContainer after StorageContainer.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;br /&gt;type StorageDevice =&lt;br /&gt;    class&lt;br /&gt;        val drive : DriveInfo&lt;br /&gt;        val path : string&lt;br /&gt;        new (d, p) = { drive = d; path = p }&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[&amp;lt;AllowNullLiteral&amp;gt;]&lt;br /&gt;type StorageContainer =&lt;br /&gt;    class&lt;br /&gt;        val name : string&lt;br /&gt;        val device : StorageDevice&lt;br /&gt;        val mutable is_disposed : bool&lt;br /&gt;    &lt;br /&gt;        new(name, dev) = { name = name; device = dev; is_disposed = false }&lt;br /&gt;    end&lt;br /&gt;with interface IDisposable with&lt;br /&gt;        member this.Dispose() = this.is_disposed &amp;lt;- true&lt;br /&gt;&lt;br /&gt;type StorageDevice with&lt;br /&gt;    member this.BeginOpenContainer(displayName : string, cb : AsyncCallback, state : Object) =&lt;br /&gt;        let f = new Task&amp;lt;_&amp;gt;(StorageInternals.openContainer(this, displayName), state)&lt;br /&gt;&lt;br /&gt;        StorageInternals.doThenMaybeCallback(f, cb)&lt;br /&gt;&lt;br /&gt;        f :&amp;gt; IAsyncResult&lt;br /&gt;&lt;br /&gt;    member this.EndOpenContainer(result : IAsyncResult) =&lt;br /&gt;        let task = result :?&amp;gt; Task&amp;lt;StorageContainer&amp;gt;&lt;br /&gt;        task.Wait()&lt;br /&gt;        task.Result&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Not everything needs to be in a module&lt;/b&gt;. By default, each new F# source file starts with &lt;br /&gt;&lt;pre class="brush:f#"&gt;module Module1.fs&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can use "namespace" instead:&lt;br /&gt;&lt;pre class="brush:f#"&gt;namespace Microsoft.Xna.Framework.Storage&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you need F# functions at the root-level (i.e. outside a class or a method), you can start a module right in the middle of your source file:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type StorageContainer =&lt;br /&gt;    class&lt;br /&gt;        val name : string&lt;br /&gt;        val device : StorageDevice&lt;br /&gt;        val mutable is_disposed : bool&lt;br /&gt;    &lt;br /&gt;        new(name, dev) = { name = name; device = dev; is_disposed = false }&lt;br /&gt;    end&lt;br /&gt;with interface IDisposable with&lt;br /&gt;        member this.Dispose() = this.is_disposed &amp;lt;- true&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;module StorageInternals =&lt;br /&gt;    let checkConnected(dev : StorageDevice) =&lt;br /&gt;        if not dev.drive.IsReady then raise(StorageDeviceNotConnectedException())&lt;br /&gt;&lt;br /&gt;type StorageContainer with&lt;br /&gt;&lt;br /&gt;    member this.CreateDirectory(dir) =&lt;br /&gt;        StorageInternals.checkConnected(this.device)&lt;br /&gt;        let path = Path.Combine(this.device.path, this.name, dir)&lt;br /&gt;        Directory.CreateDirectory(path) |&amp;gt; ignore&amp;nbsp;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Windows.Forms.FolderBrowserDialog isn't very useful&lt;/b&gt;. I was initially using it to let the user select the StorageDevice and StorageContainer, but it turned out I can't use it in the main thread because it's modal, and I can't use in a separate thread because I can't. Actually, that's not true, I can use a separate thread if I create it myself using some special options. It the end, that's not what I did. I just rolled up my own browser using a TreeView.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://bitbucket.org/johdex/xnautils/src/82452002612b/XnaReplacementWindows/Dialogs.fs?embed=t"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How do I create an IAsyncResult&lt;/b&gt;? There may be many different solutions, but an easy one that work for me was to use a Task (they implement IAsyncResult).&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;let f = new Task&amp;lt;_&amp;gt;(StorageInternals.openContainer(this, displayName), state)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;F# Asyncs are nice for GUI&lt;/b&gt;. The following code shows the browser on the right thread (assuming you can get hold of the Threading.SynchronizationContext of the GUI thread), and disposes of the dialog nicely.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;let openContainer(dev : StorageDevice, name) _ =&lt;br /&gt;        let dialog = new FolderBrowser(sprintf "Select container directory [%s]" name, Some dev.path)&lt;br /&gt;        async {&lt;br /&gt;            try&lt;br /&gt;                do! Async.SwitchToContext(gui_context)&lt;br /&gt;                dialog.Show()&lt;br /&gt;                let! _ = Async.AwaitEvent(dialog.Closed)&lt;br /&gt;                return&lt;br /&gt;                    match dialog.Selected with&lt;br /&gt;                    | Some path -&amp;gt;&lt;br /&gt;                        if not(Directory.Exists(path)) then&lt;br /&gt;                            Directory.CreateDirectory(path) |&amp;gt; ignore&lt;br /&gt;                        new StorageContainer(name, dev)&lt;br /&gt;                    | None -&amp;gt;&lt;br /&gt;                        null&lt;br /&gt;            finally&lt;br /&gt;                dialog.Dispose()&lt;br /&gt;        }&lt;br /&gt;        |&amp;gt; Async.RunSynchronously&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Playing and testing with your library code is easy, just use an F# script&lt;/b&gt;. No need for an extra project building an executable.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://bitbucket.org/johdex/xnautils/src/82452002612b/XnaReplacementWindows/Script.fsx?embed=t"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;That's all for this article. Lots of small interesting details packed in little code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8136815220274843135?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8136815220274843135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8136815220274843135' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8136815220274843135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8136815220274843135'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/replacing-live-functionality-in-xna-40.html' title='Replacing LIVE functionality in XNA 4.0'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4464906873518778178</id><published>2011-02-26T04:20:00.000-08:00</published><updated>2011-02-27T02:34:47.650-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><category scheme='http://www.blogger.com/atom/ns#' term='gc'/><title type='text'>Why we need better garbage collection on the Xbox</title><content type='html'>George Clingerman started &lt;a href="http://forums.create.msdn.com/forums/p/76317/464136.aspx#464136"&gt;a discussion&lt;/a&gt; on the App Hub where he asks developers what they would like George and other MVPs to discuss with the XNA dev team.&lt;br /&gt;&lt;br /&gt;I took the chance to request that &lt;a href="http://forums.create.msdn.com/forums/p/76317/464222.aspx#464222"&gt;improvements be made to the garbage collector&lt;/a&gt; (GC for short) on Xbox. What's wrong with the current one, you may ask? Unlike GC on the PC platform, the Xbox GC is non-generational. A generational (also called ephemeral) GC distinguishes between newly allocated objects and older objects. Reclaiming memory early from "young" objects makes it possible to diminish the frequency of reclaiming memory from older objects, because many young objects are short-lived. This is important as reclaiming memory from older objects is an expensive operation.&lt;br /&gt;&lt;br /&gt;To work around this limitation, Shawn Hargreaves has written articles &lt;a href="http://blogs.msdn.com/shawnhar/archive/2007/07/02/twin-paths-to-garbage-collector-nirvana.aspx"&gt;on how to minimize or avoid&lt;/a&gt; altogether garbage collection during gameplay phases which must run at a constant 60 fps. To summarize, there are two ways: Make sure each collection is fast (the so-called low latency path) or avoid allocating memory to avoid triggering garbage collections.&lt;br /&gt;&lt;br /&gt;The good thing with the first approach is that you don't need to worry much about allocations that happen "behind your back", i.e. allocations that are introduced by the compiler or the core library. The bad thing is that you must avoid complex object graphs. Note that this includes even objects allocated outside of the performance-critical parts of your code, such as menu code, art assets...&lt;br /&gt;&lt;br /&gt;The second approach is by far the most popular. It works well with object-oriented designs which rely on mutability. This approach also has problems. Developers must avoid all kinds of allocation at all time during gameplay, which implies refraining from using many language constructs. This includes &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2007/07/09/delegates-events-and-garbage.aspx"&gt;events, delegates and lexical closures in C#&lt;/a&gt;, tuples and closures in F#.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;Having two options to avoid performance drops due to GC sounds nice until you realize you can't combine the two&lt;/b&gt;&lt;/u&gt;. You have to choose one or the other, but you can't mix the two. That's sad, because in practice an attractive design for games is to use OOP and mutability for menus and low-level &lt;a href="http://sharp-gamedev.blogspot.com/2010/03/thoughts-about-f-and-xbox-games.html"&gt;array-based computations&lt;/a&gt; for gameplay.&lt;br /&gt;&lt;br /&gt;And this is why we need better garbage-collection on the Xbox.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4464906873518778178?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4464906873518778178/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4464906873518778178' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4464906873518778178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4464906873518778178'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/why-we-need-better-garbage-collection.html' title='Why we need better garbage collection on the Xbox'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-46952069277841310</id><published>2011-02-12T11:51:00.001-08:00</published><updated>2011-02-12T11:51:52.789-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperative multitasking'/><title type='text'>Death by exception</title><content type='html'>The mini-OS I developed for cooperative multi-tasking did not support killing tasks at first. This limitation made it a bit tricky to implement a specific feature I wanted to include in the small game I am developing to demonstrate the library's features. The feature in question consists of sending the player back to the "log-in" screen when the player signs out.&lt;br /&gt;&lt;br /&gt;My first attempt simply checked if the player had signed out, and if that was the case, the current screen was exited as if the player had aborted. This was possible because every screen supports abortion. The problem with this approach is that all animations and sound effects associated to screen transitions would be played at once.&lt;br /&gt;&lt;br /&gt;To avoid that problem, I could have added a special abortion path where all these effects are not played, but it did not feel right.&lt;br /&gt;&lt;br /&gt;Another alternative is to "restart" the game, i.e. kill all tasks and let the top level reinitialize the game. Instant death is actually easy: it's a matter of not calling Scheduler.RunFor and discarding the scheduler, replacing it by a new empty one.&lt;br /&gt;&lt;br /&gt;There is a problem, though. The screen manager will still have references to the screens, only the tasks have been killed. This particular problem is easy solve by the addition of a RemoveAll method, but there is more to it. The real problem is that clean-up code in tasks is never executed.&lt;br /&gt;&lt;br /&gt;The definitive solution requires all clean-up code to be located in finally blocks, or in Dispose methods of IDisposable objects bound with "use" or "using". That's where all clean-up code should be anyway. The code below shows a new method in ScreenBase which makes it easy to add a screen, do something the remove the screen.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type ScreenManager(game, ui_content_provider : IUiContentProvider) =&lt;br /&gt;    ...&lt;br /&gt;    member this.AddDoRemove(s : Screen, t : Eventually&amp;lt;'T&amp;gt;) = task {&lt;br /&gt;        try&lt;br /&gt;            this.AddScreen(s)&lt;br /&gt;            return! t&lt;br /&gt;        finally&lt;br /&gt;            this.RemoveScreen(s)&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Once this condition is met, the process of killing can be implemented by throwing an exception. The environment is given a new field indicating whether killing is going on. All system calls check this field before and after yielding or sleeping, and raise a specific exception if needed.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;exception TaskKilled of obj&lt;br /&gt;&lt;br /&gt;type Environment(scheduler : Scheduler) =&lt;br /&gt;    // When killing all tasks, the data to embed in TaskKilled exceptions.&lt;br /&gt;    let killing_data : obj option ref = ref None&lt;br /&gt;&lt;br /&gt;    let checkAndKill = task {&lt;br /&gt;        match !killing_data with&lt;br /&gt;        | Some o -&amp;gt; raise(TaskKilled(o))&lt;br /&gt;        | None -&amp;gt; ()&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    member this.StartKillAll(data) =&lt;br /&gt;        killing_data := Some data&lt;br /&gt;        scheduler.WakeAll()&lt;br /&gt;&lt;br /&gt;    member this.StopKillAll() =&lt;br /&gt;        killing_data := None&lt;br /&gt;&lt;br /&gt;    member this.Wait dt = task {&lt;br /&gt;        do! checkAndKill&lt;br /&gt;        do! wait dt&lt;br /&gt;        do! checkAndKill&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Using an exception makes it possible to survive a killing attempt by catching the exception and discarding it. There are two ways to go at this point: Either refrain from doing such a thing (in which case one should never ever catch and discard all exceptions), or embrace the idea and use it for "targeted killing". The exception thrown during killing (TaskKilled) carries an object which can be used in any way programmers see fit. It can for instance be a predicate which when evaluated indicates if the exception should be rethrown or discarded. Beware though: Tasks wake up early from long sleeps when they are killed. If the task is meant to survive, it's up to the programmer to make sure the task "goes back to bed".&lt;br /&gt;&lt;br /&gt;The last piece in the puzzle is to detect sign-outs and react by killing and reinitializing the game. This process should not be enabled at all time though, it depends in what "top state" the game is. What I call "top state" here is an abstract view of the game state. See the code below for the complete list of states:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type TopState =&lt;br /&gt;    | Initializing&lt;br /&gt;    | AtPressStartScreen&lt;br /&gt;    | AnonPlayer&lt;br /&gt;    | Player of SignedInGamer&lt;br /&gt;    | KillingAllTasks&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;State AnonPlayer is active when a player is playing the game (i.e. has press "start" on the "press start screen") without being signed in.&lt;br /&gt;State Player corresponds to a signed-in player playing the game.&lt;br /&gt;&lt;br /&gt;A typical flow is Initializing -&amp;gt; AtPressStartScreen -&amp;gt; Player or AnonPlayer -&amp;gt; AtPressStartScreen...&lt;br /&gt;Another flow involving signing out: Initializing -&amp;gt; AtPressStartScreen -&amp;gt; Player or AnonPlayer-&amp;gt; KillingAllTasks -&amp;gt; Initializing -&amp;gt; ...&lt;br /&gt;&lt;br /&gt;The code below updates the state machine.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type TopState =&lt;br /&gt;    | Initializing&lt;br /&gt;    | AtPressStartScreen&lt;br /&gt;    | AnonPlayer&lt;br /&gt;    | Player of SignedInGamer&lt;br /&gt;    | KillingAllTasks&lt;br /&gt;with&lt;br /&gt;    member this.Update(transition) =&lt;br /&gt;        match this, transition with&lt;br /&gt;        | Initializing, InitDone -&amp;gt; AtPressStartScreen&lt;br /&gt;        | Initializing, _ -&amp;gt; invalidOp "Invalid transition from Initializing"&lt;br /&gt;&lt;br /&gt;        | AtPressStartScreen, AnonPressedStart -&amp;gt; AnonPlayer&lt;br /&gt;        | AtPressStartScreen, PlayerPressedStart(p) -&amp;gt; Player p&lt;br /&gt;        | AtPressStartScreen, _ -&amp;gt; invalidOp "Invalid transition from AtPressStartScreen"&lt;br /&gt;&lt;br /&gt;        | AnonPlayer, Back -&amp;gt; AtPressStartScreen&lt;br /&gt;        | AnonPlayer, _ -&amp;gt; invalidOp "Invalid transition from AnonPlayer"&lt;br /&gt;&lt;br /&gt;        | Player p, SignOut -&amp;gt; KillingAllTasks&lt;br /&gt;        | Player p, Back -&amp;gt; AtPressStartScreen&lt;br /&gt;        | Player p, _ -&amp;gt; invalidOp "Invalid transition from Player"&lt;br /&gt;&lt;br /&gt;        | KillingAllTasks, AllTasksKilled -&amp;gt; Initializing&lt;br /&gt;        | KillingAllTasks, _ -&amp;gt; invalidOp "Invalid transition from KillingAllTasks"&lt;br /&gt;&lt;br /&gt;and TopStateTransition =&lt;br /&gt;    | InitDone&lt;br /&gt;    | AnonPressedStart&lt;br /&gt;    | PlayerPressedStart of SignedInGamer&lt;br /&gt;    | SignOut&lt;br /&gt;    | AllTasksKilled&lt;br /&gt;    | Back&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;See how I used parallel pattern-matching? Whenever I have to write this kind of code in C# I find myself swearing silently...&lt;br /&gt;&lt;br /&gt;Finally, the piece of code doing the dirty business.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;// Initialization and killing of tasks.&lt;br /&gt;        // Killing happens when a signed in player signs out.&lt;br /&gt;        // Initialization happens during start-up and after killing.&lt;br /&gt;        match !top_state with&lt;br /&gt;        | Initializing -&amp;gt;&lt;br /&gt;            scheduler.AddTask(main_task)&lt;br /&gt;            top_state := (!top_state).Update(InitDone)&lt;br /&gt;        | Player p when not(Gamer.IsSignedIn(p.PlayerIndex)) -&amp;gt;&lt;br /&gt;            top_state := (!top_state).Update(SignOut)&lt;br /&gt;            sys.StartKillAll(null)&lt;br /&gt;        | KillingAllTasks when not(scheduler.HasLiveTasks) -&amp;gt;&lt;br /&gt;            sys.StopKillAll()&lt;br /&gt;            top_state := (!top_state).Update(AllTasksKilled)&lt;br /&gt;            // Ideally, screen removal is done in finally handlers, and&lt;br /&gt;            // killing should take care of removing all screens.&lt;br /&gt;            // Nevertheless, we remove all screens here to be on the safe side.&lt;br /&gt;            screen_manager.RemoveAllScreens()&lt;br /&gt;        | _ -&amp;gt; ()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-46952069277841310?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/46952069277841310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=46952069277841310' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/46952069277841310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/46952069277841310'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/death-by-exception.html' title='Death by exception'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-548825071111840573</id><published>2011-02-12T11:51:00.000-08:00</published><updated>2011-05-07T00:30:05.192-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperative multitasking'/><title type='text'>Game state management using cooperative multitasking</title><content type='html'>The &lt;a href="http://create.msdn.com/en-US/education/catalog/sample/game_state_management"&gt;game state management sample&lt;/a&gt; on the App Hub shows how to organize a game in screens. I strongly recommend all new-comers to game programming to study it, regardless of their amount of programming experience. Modern graphical non-game applications seldom follow this pattern, with the notable exception of step-by-step wizards.&lt;br /&gt;&lt;br /&gt;The overview of this sample states:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The sample implements a simple game flow with a main menu, an options  screen, some actual gameplay, and a pause menu. It displays a loading  screen between the menus and gameplay, and uses a popup message box to  confirm whether the user really wants to quit. &lt;br /&gt;The ScreenManager class is a reusable component that maintains a  stack of one or more GameScreen instances. It coordinates the  transitions from one screen to another, and takes care of routing user  input to whichever screen is on top of the stack. &lt;/blockquote&gt;&lt;br /&gt;A typical problem with this sample is that it is sometimes difficult to handle transitions from a screen to the next screen in the game flow.&lt;br /&gt;For me, it's easier to specify the flow of screens from a bird's view:&lt;br /&gt;&lt;blockquote&gt;The game starts with the press start screen, then the main menu is showed. Depending on the entry selected, the game may go into actual gameplay, show a credits screen...&lt;/blockquote&gt;When you implement your game, this bird view is not available by default. Instead, it's up to each screen to tell the screen manager which is the next screen to show when it's time for the first screen to remove itself. It's not unlike continuation-passing-style, in a way.&lt;br /&gt;&lt;br /&gt;It is possible to do the inter-screen wiring from the top using events and handlers, but I find that using events and handlers for workflows is a bit ugly. The introduction of async in C# 5 indicates I'm not alone thinking that way.&lt;br /&gt;&lt;br /&gt;To make things worse, providing the next screen to show with data it needs to initialize itself can get tricky if not carefully planned during the design phase. It also tends to cause "field overgrowth" in screen classes.&lt;br /&gt;&lt;br /&gt;For all these reasons, I've been looking for a nicer solution using Eventually workflows and cooperative multitasking.&lt;br /&gt;&lt;br /&gt;From the original game state management I have kept screens and the screen manager (on a conceptual level, implementation is new). These encapsulate state well, and I like the decomposition of a game into individual screens.&lt;br /&gt;&lt;br /&gt;In particular, screens each have their ContentManager and load specific content when added to the screen manager, and release assets when removed. Sharing a ContentManager and keeping assets in memory is of course still possible using conventional methods.&lt;br /&gt;&lt;br /&gt;The significant change is the removal of Update() and HandleInput() methods from screens. Instead, each screen has a number of Eventually computation expressions (which I also call tasks) which implement the logic of the screen.&lt;br /&gt;&lt;br /&gt;To give a more concrete picture of the whole thing, here are bits from the MenuScreen. For full code, see &lt;a href="https://bitbucket.org/johdex/xnautils/src/6f0b8977113d/XNAUtils/MenuScreen.fs#cl-25"&gt;github&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type MenuScreen&amp;lt;'I when 'I : equality&amp;gt;(&lt;br /&gt;   player : PlayerIndex,&lt;br /&gt;   sys : Environment,&lt;br /&gt;   items : ('I * string)[],&lt;br /&gt;   anim : AnimationParameters,&lt;br /&gt;   placement : PlacementParameters) =&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;'I is a type parameter used to distinguish between entries. For instance, this discriminated union can be used for the main menu of a typical game:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;type MainMenuEntries =&lt;br /&gt;    | Play&lt;br /&gt;    | Instructions&lt;br /&gt;    | Options&lt;br /&gt;    | Scores&lt;br /&gt;    | Credits&lt;br /&gt;    | BuyFullVersion&lt;br /&gt;    | Exit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Back to MenuScreen, each constructor argument has the following role:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;player is the index of the player who has control, i.e. the player who pressed "start" on the "press start screen"&lt;/li&gt;&lt;li&gt;sys is the object used to interact with the scheduler, which is used to spawn new tasks, wait, yield control...&lt;/li&gt;&lt;li&gt;items is a list of (menu entry - text) pairs&lt;/li&gt;&lt;li&gt;anim is a record whose fields control fade-in and fade-out effects&lt;/li&gt;&lt;li&gt;placement is another records controlling where the menu is rendered&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;inherit ScreenBase&lt;unit&gt;()&lt;br /&gt;&lt;br /&gt;    // A mutable cell holding the index of the entry currently selected.&lt;br /&gt;    let current = ref 0&lt;br /&gt;&lt;br /&gt;    // An object wrapping a number of variables controlling fading effects.&lt;br /&gt;    let animation = new Animations.MultipleFadeIn(sys, items.Length, anim.period, anim.shift)&lt;br /&gt;&lt;br /&gt;    // Keeps track of button presses on the gamepad of the player with control&lt;br /&gt;    let input = new InputChanges.InputChanges(player)&lt;br /&gt;&lt;br /&gt;    // Array keeping track of the state of visibility of each entry.&lt;br /&gt;    // Typically entries are visible, but some must be hidden or showed as gray&lt;br /&gt;    // depending on whether the user is running the full version of the game&lt;br /&gt;    // or the trial.&lt;br /&gt;    let visibility = items |&amp;gt; Array.map (fun _ -&amp;gt; Visible)&lt;br /&gt;&lt;br /&gt;    do if items.Length = 0 then invalidArg "items" "items may not be empty"&lt;br /&gt;&lt;/unit&gt;&lt;/pre&gt;&lt;br /&gt;In the full code functions dealing with menu entry visibility follow, I'm skipping them in this article.&lt;br /&gt;&lt;br /&gt;The really interesting part (IMHO) comes now:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;member this.Task = task {&lt;br /&gt;        this.SetDrawer(this.Drawer)&lt;br /&gt;&lt;br /&gt;        let animator = sys.Spawn(animation.Task)&lt;br /&gt;&lt;br /&gt;        let selected = ref false&lt;br /&gt;        let backed = ref false&lt;br /&gt;        while not (!selected || !backed) do&lt;br /&gt;            // If this screen is not active, i.e. it is not on top or the guide is visible, wait.&lt;br /&gt;            // We don't want to react to input that's not for us.&lt;br /&gt;            do! sys.WaitUntil(fun () -&amp;gt; this.IsOnTop)&lt;br /&gt;&lt;br /&gt;            input.Update()&lt;br /&gt;&lt;br /&gt;            if input.IsMenuDown() then moveDown()&lt;br /&gt;            elif input.IsMenuUp() then moveUp()&lt;br /&gt;            elif input.IsStartPressed() then selected := true&lt;br /&gt;            elif input.IsBackPressed() then backed := true&lt;br /&gt;&lt;br /&gt;            do! sys.WaitNextFrame()&lt;br /&gt;&lt;br /&gt;        animator.Kill()&lt;br /&gt;        do! sys.WaitUntil(fun() -&amp;gt; animator.IsDead)&lt;br /&gt;&lt;br /&gt;        return&lt;br /&gt;            if !selected then items.[!current] |&amp;gt; fst |&amp;gt; Some&lt;br /&gt;            else None&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you are not familiar with F#, it's worth pointing out that "!selected" means the value of mutable cell "selected", not the negation of the value of variable "selected". I keep getting confused by that when I read F# code even today.&lt;br /&gt;&lt;br /&gt;If you have read &lt;a href="http://sharp-gamedev.blogspot.com/2011/01/untying-game-update-loop.html"&gt;my earlier articles&lt;/a&gt; about the Eventually workflow and cooperative multi-tasking, it should be clear what this code does. Critics may point out that it does not differ much from the typical content of HandleInput in the C# game state management sample, and they would be right.&lt;br /&gt;A small but important difference resides in the last lines, composed of a return statement.&lt;br /&gt;&lt;br /&gt;Interacting with the rest of the program is greatly simplified, as shown by this code snippet:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;use menu =&lt;br /&gt;            new MenuScreen&amp;lt;_&amp;gt;(&lt;br /&gt;                controlling_player,&lt;br /&gt;                sys,&lt;br /&gt;                [| Play, "Play now"&lt;br /&gt;                   Instructions, "How to play"&lt;br /&gt;                   Options, "Options"&lt;br /&gt;                   Scores, "Scores"&lt;br /&gt;                   Credits, "More information"&lt;br /&gt;                   BuyFullVersion, "BuyFullVersion"&lt;br /&gt;                   Exit, "Exit" |],&lt;br /&gt;                menu_animation,&lt;br /&gt;                menu_placement&lt;br /&gt;            )&lt;br /&gt;&lt;br /&gt;        // Show the menu&lt;br /&gt;        screen_manager.AddScreen(menu)&lt;br /&gt;        // Execute the menu's code, and get the selected item as a result&lt;br /&gt;        let! action = menu.Task&lt;br /&gt;        // We are done with the menu, hide it.&lt;br /&gt;        screen_manager.RemoveScreen(menu)&lt;br /&gt;&lt;br /&gt;        // Deal with the selection in the menu.&lt;br /&gt;        match action with        &lt;br /&gt;        // Back to the board.&lt;br /&gt;        | Some Exit -&amp;gt;&lt;br /&gt;            exit_game := true&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you are like me, you may have experienced that dealing with seemingly trivial tasks such as showing and saving highscores after "game over" is more pain than it should be. It involves multiple screen transitions and asynchronous file I/O that must be spread over multiple update cycles.&lt;br /&gt;&lt;br /&gt;Here how it looks in F#:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:f#"&gt;// Deal with the selection in the menu.&lt;br /&gt;match action with        &lt;br /&gt;// Back to the board.&lt;br /&gt;| Some Exit -&amp;gt;&lt;br /&gt;    exit_game := true&lt;br /&gt;        &lt;br /&gt;// Start playing.&lt;br /&gt;| Some Play -&amp;gt;&lt;br /&gt;    // Create the screen showing the game.&lt;br /&gt;    use gameplay = new GameplayScreen(sys, controlling_player)&lt;br /&gt;&lt;br /&gt;    // Show the gameplay screen. Gameplay itself is in gameplay.Task&lt;br /&gt;    let! gameplay_result = screen_manager.AddDoRemove(gameplay, gameplay.Task)&lt;br /&gt;&lt;br /&gt;    // If the game wasn't aborted, and if a new high score was achieved,&lt;br /&gt;    // add it to the score table and show the table.&lt;br /&gt;    match gameplay_result with&lt;br /&gt;    | Aborted _ -&amp;gt; ()&lt;br /&gt;    | TooEarly (_, points) | TooLate (_, points) -&amp;gt;&lt;br /&gt;        use results = new ResultScreen(sys, controlling_player, gameplay_result)&lt;br /&gt;        do! screen_manager.AddDoRemove(results, results.Task)&lt;br /&gt;&lt;br /&gt;        let player_name =&lt;br /&gt;            match SignedInGamer.SignedInGamers.ItemOpt(controlling_player) with&lt;br /&gt;            | None -&amp;gt; "Unknown"&lt;br /&gt;            | Some player -&amp;gt; player.Gamertag&lt;br /&gt;&lt;br /&gt;        let is_hiscore = (!scores).AddScore(player_name, points)&lt;br /&gt;&lt;br /&gt;        if is_hiscore then&lt;br /&gt;            // save the scores.&lt;br /&gt;            if storage.TitleStorage.IsSome then&lt;br /&gt;                do! storage.CheckTitleStorage&lt;br /&gt;                let! result =&lt;br /&gt;                    storage.DoTitleStorage(&lt;br /&gt;                       score_container,&lt;br /&gt;                       saveXml score_filename !scores)&lt;br /&gt;&lt;br /&gt;                match result with&lt;br /&gt;                | Some(Some()) -&amp;gt; ()&lt;br /&gt;                | _ -&amp;gt; do! doOnGuide &amp;lt;| fun() -&amp;gt; error "Failed to save scores"&lt;br /&gt;            // Show the scores screen.&lt;br /&gt;            do! showScores&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There is a lot more to be said, but that's enough for a single article. I think that these code extracts show how F# can simplify the development of games. If you are a C# programmer used to think "functional programming is too complicated for what I need", I hope I have managed to introduce the idea there are clear benefits to be gained by introducing F# in your toolbox.&lt;br /&gt;&lt;br /&gt;This is still work in progress, you can follow it on &lt;a href="https://bitbucket.org/johdex/xnautils/src"&gt;bitbucket&lt;/a&gt;.&lt;br /&gt;You can also follow me on twitter, I am @deneuxj there. The full source code of a small game demonstrating task-based game state management is also available on github, under &lt;a href="https://bitbucket.org/johdex/xnautils/src/6f0b8977113d/Samples/CoopMultitaskingSample/"&gt;Samples/CoopMultiTasking&lt;/a&gt;.&lt;br /&gt;This game demonstrates the following features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A typical "press start screen -&amp;gt; menu -&amp;gt; game" flow&lt;/li&gt;&lt;li&gt;Safe IO using StorageDevice, used for best scores and user preferences&lt;/li&gt;&lt;li&gt;Throwing back to the "press start screen" when sign-outs occur&lt;/li&gt;&lt;li&gt;Screen transitions&lt;/li&gt;&lt;li&gt;Input handling and pausing (not complete at the time of writing)&lt;/li&gt;&lt;li&gt;Content loading and unloading&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-548825071111840573?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/548825071111840573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=548825071111840573' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/548825071111840573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/548825071111840573'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/game-state-management-using-cooperative.html' title='Game state management using cooperative multitasking'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6645043685684619538</id><published>2011-02-06T03:26:00.000-08:00</published><updated>2011-02-06T03:26:47.248-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='storage'/><title type='text'>Notes on safe use of StorageDevice in XNA</title><content type='html'>I recently found a bug in &lt;a href="https://bitbucket.org/johdex/xnautils/src/cae903c0c6bb/XNAUtils/StorageTasks.fs#cl-48"&gt;StorageTasks.fs&lt;/a&gt;, an exception that I did not expect can be thrown in some situations. I am therefore going over the code and checking if I'm handling all exceptions correctly.&lt;br /&gt;&lt;br /&gt;The bug I just fixed was an uncaught InvalidOperationException when attempting to open a StorageContainer after pulling the memory unit (which was picked as the storage device). The method that threw that exception was StorageDevice.EndOpenContainer. Sadly, the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.storage.storagedevice.endopencontainer.aspx?appId=Dev10IDEF1&amp;amp;l=EN-US&amp;amp;k=k%28MICROSOFT.XNA.FRAMEWORK.STORAGE%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK&amp;amp;k=VERSION=V4.0%22%29;k%28DevLang-FSHARP%29&amp;amp;rd=true"&gt;msdn documentation&lt;/a&gt; does not mention that.&lt;br /&gt;&lt;br /&gt;I thought I would use EasyStorage as a reference. Unfortunately, even EasyStorage isn't 100% correct. For instance, see &lt;a href="http://easystorage.codeplex.com/SourceControl/changeset/view/57440#1006587"&gt;SaveDevice.OpenContainer&lt;/a&gt;: It does not catch InvalidOperationException. Although unlikely, this can happen if the user disconnects the storage device after BeginOpenContainer and before EndOpenContainer.&lt;br /&gt;&lt;br /&gt;Anyway, I'll just go on and rely on testing to get it right... In the mean time, here are my findings regarding exceptions thrown by the StorageDevice API in XNA.&lt;br /&gt;&lt;br /&gt;StorageDevice.BeginShowSelector&lt;br /&gt;&lt;ul&gt;&lt;li&gt;GuideAlreadyVisibleException&lt;/li&gt;&lt;/ul&gt;StorageDevice.EndShowSelector&lt;br /&gt;&lt;ul&gt;&lt;li&gt;None known&lt;/li&gt;&lt;/ul&gt;StorageDevice.BeginOpenContainer&lt;br /&gt;&lt;ul&gt;&lt;li&gt; InvalidOperationException (from &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.storage.storagedevice.beginopencontainer.aspx?appId=Dev10IDEF1&amp;amp;l=EN-US&amp;amp;k=k%28MICROSOFT.XNA.FRAMEWORK.STORAGE%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK&amp;amp;k=VERSION=V4.0%22%29;k%28DevLang-FSHARP%29&amp;amp;rd=true"&gt;msdn&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;ArgumentNullException (from &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.storage.storagedevice.beginopencontainer.aspx?appId=Dev10IDEF1&amp;amp;l=EN-US&amp;amp;k=k%28MICROSOFT.XNA.FRAMEWORK.STORAGE%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK&amp;amp;k=VERSION=V4.0%22%29;k%28DevLang-FSHARP%29&amp;amp;rd=true"&gt;msdn&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;StorageDeviceNotConnectedException&lt;/li&gt;&lt;/ul&gt;StorageDevice.EndOpenContainer&lt;br /&gt;&lt;ul&gt;&lt;li&gt;InvalidOperationException&lt;/li&gt;&lt;li&gt;StorageDeviceNotConnectedException&lt;/li&gt;&lt;/ul&gt;StorageContainer.OpenFile&lt;br /&gt;&lt;ul&gt;&lt;li&gt;StorageDeviceNotConnectedException&lt;/li&gt;&lt;li&gt;FileNotFoundException&lt;/li&gt;&lt;/ul&gt;StorageContainer.CreateFile&lt;br /&gt;&lt;ul&gt;&lt;li&gt;StorageDeviceNotConnectedException&lt;/li&gt;&lt;li&gt;Possibly other exceptions, e.g. if no space is left on the device?&lt;/li&gt;&lt;/ul&gt;I have listed StorageDeviceNotConnectedException under most methods. Although it's never mentioned explicitly on msdn in the method documentation, it seems reasonable to expect it in any situation where the device might be accessed.&lt;br /&gt;&lt;br /&gt;There are other failure scenarios associated to Stream and serialization which I'm not listing here. In particular, XML de-serialization of F# types (discriminated unions, records, tuples, lists...) will fail at run-time due to these types being immutable and lacking a default constructor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6645043685684619538?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6645043685684619538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6645043685684619538' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6645043685684619538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6645043685684619538'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/notes-on-safe-use-of-storagedevice-in.html' title='Notes on safe use of StorageDevice in XNA'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6975042961580300628</id><published>2011-02-05T08:04:00.000-08:00</published><updated>2011-02-05T08:05:49.062-08:00</updated><title type='text'>Post-asteroid trauma</title><content type='html'>December and January have been hectic months for me.&lt;br /&gt;&lt;br /&gt;December saw the publishing of a number of templates facilitating the use of F# with XNA:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; For the Xbox 360: &lt;a href="http://visualstudiogallery.msdn.microsoft.com/e981f57c-c7e4-457c-a32b-38001a4dc860"&gt;library template&lt;/a&gt;, which has been downloaded 360 times. Does that mean there are 360 F# games coming to the Xbox? If you are working on a game, don't hesitate to let me know!&lt;/li&gt;&lt;li&gt;For the Windows Phone 7 platform: &lt;a href="http://visualstudiogallery.msdn.microsoft.com/4a71154f-c590-4370-9d0f-f5072d69996f"&gt;library &lt;/a&gt;and &lt;a href="http://visualstudiogallery.msdn.microsoft.com/9b9d51d9-8b54-4f5d-b563-9952259eb555"&gt;full application&lt;/a&gt;&amp;nbsp; templates. Although I am not personally involved in WP7 development, I would love to hear about ongoing projects too!&lt;/li&gt;&lt;/ul&gt;I am not done yet with project templates. I am planning to make a full game template for the Xbox 360, and update all existing templates with the script for &lt;a href="http://sharp-gamedev.blogspot.com/2010/12/interactive-game-development-with-fsi.html"&gt;interactive development&lt;/a&gt; using fsi.&lt;br /&gt;&lt;br /&gt;In January, the discovery of custom workflows and how they can dramatically increase the readability of one's code fascinated me. I think that's a feature that even functional programming sceptics should love.&lt;br /&gt;&lt;br /&gt;My game, Asteroid Sharpshooter passed peer review and became available on the &lt;a href="http://marketplace.xbox.com/en-US/Product/Asteroid-Sharpshooter/66acd000-77fe-1000-9115-d80258550797?SortBy=Title"&gt;Xbox LIVE Marketplace&lt;/a&gt;. I doubt it will make me rich, but for a first try, it's not too bad.&lt;br /&gt;&lt;br /&gt;What are February and the following months going to be like? First, I want to understand whether&lt;a href="http://stackoverflow.com/questions/4900451/is-the-lack-of-tail-call-optimization-an-obstacle-when-using-the-eventually-workf"&gt; custom workflows are safe to use in the absence of tail call elimination&lt;/a&gt;. I'm still a bit confused... If they are safe, as I suspect they are, I will go ahead and make an XNA game starter kit, similar to the XNA Game State Management sample. It will include file IO and menus based on the Eventually workflow and cooperative multi-tasking.&lt;br /&gt;&lt;br /&gt;At the end of February, Dream-Build-Play 2011 will open for registration, which will be the starting point for my next game.&lt;br /&gt;&lt;br /&gt;I will also try to be more active in the XNA community and let people know C# is not the only language available in their toolbox. To this effect, I have registered on twitter. I'm &lt;a href="http://www.twitter.com/deneuxj"&gt;deneuxj&lt;/a&gt; there. I'll be posting a few pre-paid codes for Asteroid Sharpshooter there, so stay tuned!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6975042961580300628?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6975042961580300628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6975042961580300628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6975042961580300628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6975042961580300628'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/post-asteroid-trauma.html' title='Post-asteroid trauma'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2170438632299109993</id><published>2011-02-03T11:45:00.000-08:00</published><updated>2011-02-03T11:45:50.186-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Is it possible to use F# to write and publish a game on the Xbox LIVE Marketplace?</title><content type='html'>&lt;a href="http://marketplace.xbox.com/en-US/Product/Asteroid-Sharpshooter/66acd000-77fe-1000-9115-d80258550797?SortBy=Title"&gt;Yes, it is.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2170438632299109993?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2170438632299109993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2170438632299109993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2170438632299109993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2170438632299109993'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/02/is-it-possible-to-use-f-to-write-and.html' title='Is it possible to use F# to write and publish a game on the Xbox LIVE Marketplace?'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3448925475461276660</id><published>2011-01-30T13:23:00.000-08:00</published><updated>2011-01-30T13:26:12.924-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='computation expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperative multitasking'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Safe IO on the Xbox 360 in F#</title><content type='html'>... or how computation expressions can help you write concise, clean and exception-safe code.&lt;br /&gt;&lt;br /&gt;The XNA framework offers a number of APIs to access files. The Storage API, described on &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.storage.aspx"&gt;MSDN&lt;/a&gt;, is a popular one.&lt;br /&gt;&lt;br /&gt;All seasoned XBLIG developers know that this API has a number of pitfalls that are not always easy to avoid. Here are those that come to my mind:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Files can only be accessed after getting access to a storage device, which requires interaction with the user as soon as more than one storage device (hard-disk, memory unit, usb stick...) is available. As all of the steps cannot be performed within a single iteration of the update-loop, this forces the programmer to spread the steps over multiple iterations.&lt;/li&gt;&lt;li&gt;Attempting to get a storage device while the guide is open results in an exception. The guide is a graphical interface to the console's "operating system" which is available at any time.&lt;/li&gt;&lt;li&gt;At most one storage container may be in use at any time (a storage container is a collection of files, it can be seen as a directory). &lt;/li&gt;&lt;li&gt;The user may at any time remove a storage device, which results in exceptions being thrown while accessing the device.&lt;/li&gt;&lt;li&gt;File access is quite slow. In order to keep the GUI responsive, games must perform IO asynchronously.&lt;/li&gt;&lt;/ol&gt;Attempting to use the XNA API as it is almost invariably leads to bugs. I would say storage-related crashes are among the top 3 reasons games fail peer review. &lt;a href="http://easystorage.codeplex.com/"&gt;EasyStorage&lt;/a&gt; is a popular C# component that simplifies safe IO in games. In this article, I describe an alternative component written in F#.&lt;br /&gt;&lt;br /&gt;Let us look at each pitfall and consider ways to avoid them.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem 1: Getting a storage device asynchronously&lt;/h2&gt;&lt;br /&gt;A simple popular solution consists of requesting the storage device, which is an asynchronous operation, and busy-wait until the operation completes when the user chooses a device.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let getUserStorageDevice player = task {&lt;br /&gt;    let! async_result = doOnGuide(fun() -&amp;gt; StorageDevice.BeginShowSelector(player, null, null))&lt;br /&gt;    do! waitUntil(fun() -&amp;gt; async_result.IsCompleted)&lt;br /&gt;    let device = StorageDevice.EndShowSelector(async_result)&lt;br /&gt;    return&lt;br /&gt;        if device = null then&lt;br /&gt;            None&lt;br /&gt;        else&lt;br /&gt;            Some device&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This function takes a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PlayerIndex&lt;/span&gt; and returns an Eventually computation expression (which I call a &lt;i&gt;task&lt;/i&gt;). &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;doOnGuide&lt;/span&gt; is another task which I describe shortly hereafter. Busy-waiting occurs in "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;do! waitUntil&lt;/span&gt;" on the third line.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem 2: Avoiding GuideAlreadyVisible exceptions&lt;/h2&gt;&lt;br /&gt;Whenever you want to open the guide to ask the user to choose a device, to show a message box, send a message to a friend, open the virtual keyboard, you must check whether Guide.IsVisible is false. Even if it is, you have to surround your call to the guide with a try...with block, as GuideAlreadyVisibleException may be thrown. It may surprise beginners, but so is the case, as I have experienced during peer review of Asteroid Sharpshooter.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let rec doOnGuide f = task {&lt;br /&gt;    do! waitUntil(fun() -&amp;gt; not Guide.IsVisible)&lt;br /&gt;    let! result = task {&lt;br /&gt;        try&lt;br /&gt;            return f()&lt;br /&gt;        with&lt;br /&gt;        | :? GuideAlreadyVisibleException -&amp;gt;&lt;br /&gt;            do! wait(0.5f)&lt;br /&gt;            let! eventually_some_bloody_result = doOnGuide f&lt;br /&gt;            return eventually_some_bloody_result&lt;br /&gt;    }&lt;br /&gt;    return result&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;doOnGuide&lt;/span&gt; is a recursive function which repeatedly busy-waits until Guide.IsVisible is false. Then it tries to execute the provided function &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;f&lt;/span&gt;. If GuideAlreadyVisibleException is thrown, it is caught, discarded, and doOnGuide calls itself again after waiting a short while. This additional wait for half a second is not strictly necessary, I put it there mostly because the idea of raising one exception per update cycle disturbed me a bit.&lt;br /&gt;&lt;br /&gt;I don't find this repeated get-rejected-and-retry particularly pleasing to the eye, but if you have seen it's "hacked-the-night-before-sending-to-peer-review" variant in C#, you'll probably find my version decently pretty.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem 3: At most one storage container opened at any time&lt;/h2&gt;&lt;br /&gt;The solution is again pretty simple in principle: keep track in a central place whether a storage container is already opened. If it is, busy-wait until it isn't.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type Storage() =&lt;br /&gt;    let is_busy = ref false&lt;br /&gt;    member this.DoTitleStorage(container_name, f) = task {&lt;br /&gt;            do! waitUntil(fun () -&amp;gt; not !is_busy)&lt;br /&gt;            try&lt;br /&gt;                is_busy := true&lt;br /&gt;&lt;br /&gt;                let! result = doInContainer device container_name f&lt;br /&gt;                return result&lt;br /&gt;            finally&lt;br /&gt;                is_busy := false&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Class &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Storage &lt;/span&gt;is the class that coordinates access to storage devices. Only parts of the class relevant to problem 3 are shown here.&lt;br /&gt;&lt;br /&gt;The first line of method &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DoTitleStorage&lt;/span&gt; busy-waits until &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;is_busy&lt;/span&gt; becomes false. When this happens, it goes ahead and immediately sets &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;is_busy&lt;/span&gt; to true again. Readers concerned about race conditions and multiple waiters proceeding into the critical section unaware of each other may rest reassured: multiple tasks are picked and executed one a time using cooperative multi-tasking. True concurrency and its pitfalls are out of the picture.&lt;br /&gt;&lt;br /&gt;Note the finesse about using finally to reset &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;is_busy&lt;/span&gt;. We are not quite sure of what &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;f&lt;/span&gt; will do in the container. Should it do something nasty and get surprised by an uncaught exception, the storage component won't be left in an unusable state. Doing proper clean-up and recovery in traditional asynchronous programming using events and callbacks can be difficult. Actually, the difficult part is to remember to do it when the code is turned "inside out".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem 4: Uncaring users yanking storage devices at inappropriate times&lt;/h2&gt;&lt;br /&gt;The only solution here is to sprinkle your code with&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; try...with&lt;/span&gt; and checks for &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;StorageDevice.IsConnected&lt;/span&gt;. Again, the availability of try...with in computation expressions makes it relatively painless in F#. See problem 2 above for a code example.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem 5: Asynchronous file operations&lt;/h2&gt;&lt;br /&gt;I haven't tackled this problem yet, mostly because I have only dealt with very small files so far (score tables and user settings). I will leave this for another post, if the need arises.&lt;br /&gt;The only point I wanted to mention is that programmers should be wary of simultaneous progression in the GUI and asynchronous IO. Typical tricky situations include users quitting the game while data is being saved, triggering new IO while previous IO operations are still ongoing. For these reasons, it is advisable to limit the responsiveness of the GUI to showing a "please wait" animation, and busy-waiting until IO finishes.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Wrap-up&lt;/h2&gt;That's all for now. Complete code is available in &lt;a href="https://bitbucket.org/johdex/xnautils/src/f830a7fe9a72/XNAUtils/StorageTasks.fs"&gt;XNAUtils&lt;/a&gt;. It's still work in progress, but it's already usable. It can be interesting to compare to &lt;a href="https://bitbucket.org/johdex/xnautils/src/f830a7fe9a72/XNAUtils/StorageComponentGamerServices.fs"&gt;an earlier attempt&lt;/a&gt; I did at dealing with the storage API, using state machines. The previous attempt is both longer in lines-of-code and harder to read. I think it's a lot easier to convince oneself or detect bugs in the newer version using Eventually computation expressions and cooperative multi-tasking.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3448925475461276660?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3448925475461276660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3448925475461276660' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3448925475461276660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3448925475461276660'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/01/safe-io-on-xbox-360-in-f.html' title='Safe IO on the Xbox 360 in F#'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6354193719792419721</id><published>2011-01-21T01:57:00.000-08:00</published><updated>2011-01-21T01:57:30.986-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xnautils'/><category scheme='http://www.blogger.com/atom/ns#' term='cooperative multitasking'/><title type='text'>Cooperative multitasking using the Eventually workflow</title><content type='html'>In cooperative multitasking at most one task executes at any time. In order for another task to execute, the task currently in control must explicitly pause itself. The scheduler keeps track of which task is executing, which tasks are ready to be executed and which are blocked or sleeping.&lt;br /&gt;&lt;br /&gt;This form of multitasking lacks concurrency, which makes it easy for multiple tasks to synchronize and communicate. On the downside, it is not suitable for improving performance of cpu-bound computations.&lt;br /&gt;&lt;br /&gt;I have implemented a cooperative-multitasking "operating system" consisting of a scheduler and a couple "system calls" which I believe will make it easier for me to develop the menu systems of my future games. In this article I describe the design and API of this light-weight operating system.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The scheduler&lt;/h2&gt;&lt;br /&gt;The scheduler is implemented in class &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Scheduler &lt;/span&gt;in CoopMultiTasking.fs, where these methods are available:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AddTask&lt;/span&gt;: A task is an &lt;tt&gt;Eventually&amp;lt;unit&amp;gt;&lt;/tt&gt; computation expression, and can be added to the scheduler using this method. The task won't execute until method RunFor is called. A task is removed from the scheduler after it completes.&lt;/unit&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;HasLiveTasks&lt;/span&gt; indicates if the scheduler has at least one task which hasn't completed.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RunFor&lt;/span&gt; executes all ready tasks for a specified amount of time. Typically, this should be 1/60 for a game running at 60 frames per second, but any value will do. It is for instance possible to "fast-forward" execution by passing durations that exceed the amount of real time that has passed. See "Simulated time vs real time" below for details.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;The system calls&lt;/h2&gt;&lt;br /&gt;Class &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Environment &lt;/span&gt;makes it possible for tasks to interact with the scheduler to control their execution and spawn sub-tasks.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Spawn&lt;/span&gt; allows a task to add a sub-task to the scheduler. The scheduler returns an instance of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;TaskController &lt;/span&gt;which can be used to instruct the sub-task to complete early and to wait for the sub-task to complete early. &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Spawn &lt;/span&gt;does not actually take a task, but a function which takes a reference to a Boolean and returns a task. The Boolean indicates when the task should kill itself. See "Killing sub-tasks" below form more information.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SpawnRepeat&lt;/span&gt; is a variant of Spawn which executes a sub-task in a loop. It returns a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;TaskController &lt;/span&gt;which can be used to interrupt the loop. Unlike Spawn, this method expects a task. The sub-task should be very short, as an iteration of the loop cannot be interrupted.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Wait&lt;/span&gt; causes the task to wait a specific duration. Note that this duration does not correspond to real time, but to durations as passed to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RunFor&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Yield&lt;/span&gt; causes the task to stop executing, but remain ready for execution. If another task is ready, the scheduler executes it, otherwise the task continues executing.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WaitNextFrame&lt;/span&gt; causes the task to stop executing until the next time the scheduler's RunFor is called.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WaitUntil&lt;/span&gt; takes a function with signature &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;unit -&amp;gt; bool&lt;/span&gt;. The task is paused until the function returns true. The function is first evaluated in the current frame without waiting, then once per call to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RunFor&lt;/span&gt;. Note that the first evaluation of the function is preceded by an implicit call to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Yield&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;Simulated time vs real time&lt;/h2&gt;&lt;br /&gt;The time inside this environment, which I call simulated time, does not correspond to real time. Simulated time passes every time RunFor is called by the amount of time specified to RunFor.&lt;br /&gt;&lt;br /&gt;Even if you always pass to RunFor the amount of real time that has passed, the amount of time tasks wait is not coupled to real time. This is due to RunFor never sleeping, even when all tasks are waiting. Instead, it directly advances the simulated time.&lt;br /&gt;&lt;br /&gt;Tasks which are waiting for durations exceeding the frame time wake up during the correct frame. Within a frame, tasks wake up in the correct order, in accordance to their amount of time left before waking up.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Killing sub-tasks&lt;/h2&gt;&lt;br /&gt;It is not possible to forcibly kill a sub-task. Instead, a notification mechanism using a reference to a Boolean cell is used. It is the responsibility of the sub-task to test this cell often enough that excessively long delays after requesting termination do not occur. I realize this may not be a popular design decision, as this forces one to sprinkle the code of tasks with checks for termination requests. The rationale behind this decision is that uncontrolled termination can leave an application in an incorrect state. I don't feel strongly about that point, though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6354193719792419721?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6354193719792419721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6354193719792419721' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6354193719792419721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6354193719792419721'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/01/cooperative-multitasking-using.html' title='Cooperative multitasking using the Eventually workflow'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6768279972356368277</id><published>2011-01-18T13:34:00.000-08:00</published><updated>2011-01-18T13:36:02.861-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computation expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='custom workflows'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><title type='text'>The Eventually workflow</title><content type='html'>The &lt;a href="http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597448"&gt;F# specification&lt;/a&gt; gives an example of custom workflow in its section on computation expressions. I have extended it as shown below:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type Eventually&amp;lt;'R&amp;gt; =&lt;br /&gt;    | Completed of 'R&lt;br /&gt;    | Blocked of float32 * (unit -&amp;gt; Eventually&amp;lt;'R&amp;gt;)&lt;br /&gt;    | BlockedNextFrame of (unit -&amp;gt; Eventually&amp;lt;'R&amp;gt;)&lt;br /&gt;    | Running of (unit -&amp;gt; Eventually&amp;lt;'R&amp;gt;)&lt;br /&gt;    | Yield of (unit -&amp;gt; Eventually&amp;lt;'R&amp;gt;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;An &lt;tt&gt;Eventually&lt;/tt&gt; computation can be in one of the following states:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;Completed&lt;/tt&gt;, in which case the state includes the result of the computation.&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Blocked&lt;/tt&gt;, when the computation is paused, and the state contains the amount of time remaining before it resumes.&lt;/li&gt;&lt;li&gt;&lt;tt&gt;BlockedNextFrame&lt;/tt&gt;, when the computation is paused for a short while, until the start of next frame. The meaning of "next frame" is up to the &lt;it&gt;scheduler&lt;/it&gt;, which is described in an upcoming article&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Running&lt;/tt&gt;, which indicates the computation is ready to proceed.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Yield&lt;/tt&gt;, when the computation is willing to pass control to another computation which is in state Running, if any. Otherwise, the computation is ready to proceed.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;All states but the first one, &lt;tt&gt;Completed&lt;/tt&gt; contain a function value which when executed produces a new state. It represents the work that the computation can perform "in one block" before returning control to the scheduler. When that happens, the scheduler updates the state of the computation.&lt;br /&gt;&lt;br /&gt;Although it is possible to build computations "manually" using this discriminated union, F# makes it possible to do so conveniently using a subset of F# extended with a few keywords, namely &lt;tt&gt;yield, yield!, return, return!, let!&lt;/tt&gt; and &lt;tt&gt;do!&lt;/tt&gt;. The meaning of these keywords is up to the designer of the custom workflow, but they have an expected behaviour which should be respected.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;yield&lt;/tt&gt; and &lt;tt&gt;yield!&lt;/tt&gt; are used to produce values in sequences. The second variant allows to insert sequences from other &lt;it&gt;sequence expressions&lt;/it&gt;. Here I use sequence expression as a synonym for "a computation expression used to produce sequences". Below is an interesting example (from the &lt;a href="http://en.wikibooks.org/wiki/F_Sharp_Programming/Sequences"&gt;F# Programming&lt;/a&gt; wikibook).  &lt;br /&gt;&lt;pre class="brush: f#"&gt;let allEvens = &lt;br /&gt;  let rec loop x = seq { yield x; yield! loop (x + 2) }&lt;br /&gt;  loop 0;;&lt;br /&gt;&lt;/pre&gt;&lt;tt&gt;loop&lt;/tt&gt; is a function which takes an integer &lt;tt&gt;x&lt;/tt&gt; and returns a sequence expression which when evaluated produces the integer, followed by the result of a recursive call to &lt;tt&gt;loop&lt;/tt&gt; using &lt;tt&gt;x+2&lt;/tt&gt;. In clear, this will produce x, x+2, x+2+2, x+2+2+2..., one value at a time. Note the difference between &lt;tt&gt;yield&lt;/tt&gt; and &lt;tt&gt;yield!&lt;/tt&gt;: the first produces a single value, the second produces the values of another sequence expression.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;let!&lt;/tt&gt; allows to "nest" computation expressions. In other words, a computation expression can "call" another computation expression. I'm being pretty vague here, so let's look at an example using asynchronous computations (also from the &lt;a href="http://en.wikibooks.org/wiki/F_Sharp_Programming/Async_Workflows"&gt;wikibook&lt;/a&gt;).  &lt;br /&gt;&lt;pre class="brush: f#"&gt;let extractLinksAsync html =&lt;br /&gt;    async {&lt;br /&gt;        return System.Text.RegularExpressions.Regex.Matches(html, @"http://\S+")&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;let downloadAndExtractLinks url =&lt;br /&gt;    async {&lt;br /&gt;        let webClient = new System.Net.WebClient()&lt;br /&gt;        let html = webClient.DownloadString(url : string)&lt;br /&gt;        let! links = extractLinksAsync html&lt;br /&gt;        return url, links.Count&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;tt&gt;return&lt;/tt&gt; and &lt;tt&gt;return!&lt;/tt&gt; are used for the final results of a computation expression. The example above uses &lt;tt&gt;return&lt;/tt&gt;. My guess is &lt;tt&gt;return!&lt;/tt&gt; should behave as &lt;br /&gt;&lt;pre class="brush: f#"&gt;let! x = ...&lt;br /&gt;return x&lt;br /&gt;&lt;/pre&gt;I am not quite sure if &lt;tt&gt;return&lt;/tt&gt; is meant to have imperative semantics, i.e. discarding the remainder of a computation when encountered. My attempts to use such C-like semantics have not succeeded yet.&lt;br /&gt;&lt;br /&gt;Going back to my library, XNAUtils, I have written a computation builder which is used to turn computation expressions (code between curly brackets) into state machines that can be executed in a controlled manner. The builder takes the form of a class with methods are called at selected places in a computation expression. A builder allows to override the meaning of certain keywords and specify the effect of the special keywords I listed above.  The code is in &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/XNAUtils/CoopMultiTasking.fs"&gt;CoopMultiTasking.fs&lt;/a&gt;  &lt;br /&gt;&lt;pre class="brush:f#"&gt;let rec bind k e =&lt;br /&gt;    match e with&lt;br /&gt;    | Completed r -&amp;gt;&lt;br /&gt;        Running(fun () -&amp;gt; k r)&lt;br /&gt;    | Running f -&amp;gt;&lt;br /&gt;        Running(fun () -&amp;gt; f() |&amp;gt; bind k)&lt;br /&gt;    | Blocked(dt, f) -&amp;gt;&lt;br /&gt;        Blocked(dt, fun () -&amp;gt; f() |&amp;gt; bind k)&lt;br /&gt;    | BlockedNextFrame f -&amp;gt;&lt;br /&gt;        BlockedNextFrame(fun () -&amp;gt; f() |&amp;gt; bind k)&lt;br /&gt;    | Yield f -&amp;gt;&lt;br /&gt;        Yield(fun () -&amp;gt; f() |&amp;gt; bind k)&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;type TaskBuilder() =&lt;br /&gt;    member x.Bind(e, f) = bind f e&lt;br /&gt;    member x.Return(r) = result r&lt;br /&gt;    member x.Combine(e1, e2) = combine e1 e2&lt;br /&gt;    member x.Delay(f) = delay f&lt;br /&gt;    member x.Zero() = result ()&lt;br /&gt;    member x.TryWith(e, handler) = tryWith e handler&lt;br /&gt;    member x.TryFinally(e, compensation) = tryFinally e compensation&lt;br /&gt;    member x.While(cond, body) = whileLoop cond body&lt;br /&gt;    member x.For(xs, body) = forLoop xs body&lt;br /&gt;    member x.Using(e, f) = using e f&lt;br /&gt;&lt;br /&gt;let task = TaskBuilder()&lt;br /&gt;&lt;/pre&gt;The module-level variable &lt;tt&gt;task&lt;/tt&gt; can be used to create instances of &lt;tt&gt;Eventually&lt;/tt&gt;. I have provided a few helpful tasks that can be used to wait a fixed amount of time, wait until next frame, give control to another task:  &lt;br /&gt;&lt;pre class="brush: f#"&gt;// Wait a fixed amount of time.&lt;br /&gt;let wait dt =&lt;br /&gt;    Blocked(dt, fun () -&amp;gt; Completed())&lt;br /&gt;&lt;br /&gt;// Wait until next frame, i.e. next call to Scheduler.RunFor&lt;br /&gt;let nextFrame () =&lt;br /&gt;    BlockedNextFrame(fun() -&amp;gt; Completed())&lt;br /&gt;&lt;br /&gt;// Stop executing, let some other task execute, if any is ready. Otherwise, we get control back.&lt;br /&gt;let nextTask () =&lt;br /&gt;    Yield(fun() -&amp;gt; Completed())&lt;br /&gt;&lt;br /&gt;// Wait until a specified condition is true.&lt;br /&gt;// nextTask is always called, then the condition is checked.&lt;br /&gt;// If it's false, we wait until next frame, check the condition,&lt;br /&gt;// call nextTask if it's not true, and so on...&lt;br /&gt;let waitUntil f = task {&lt;br /&gt;    let stop = ref false&lt;br /&gt;    while not !stop do&lt;br /&gt;        do! nextTask()&lt;br /&gt;        if f() then&lt;br /&gt;            stop := true&lt;br /&gt;        else&lt;br /&gt;            do! nextFrame()&lt;br /&gt;            stop := f()&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;tt&gt;waitUntil&lt;/tt&gt; uses a while loop, it could have used recursion too. I initially refrained from using recursion in all code meant to be executed on the Xbox 360, because tail calls are not available on this platform. On second thoughts, I don't think that's a problem, as the kind of recursion that would appear inside of tasks is of the loose kind. Recursive calls a interrupted by calls to &lt;tt&gt;nextTask&lt;/tt&gt; and &lt;tt&gt;nextFrame&lt;/tt&gt;, which should prevent the stack from overflowing.&lt;br /&gt;&lt;br /&gt;Although I have not had any use for synchronization between tasks yet, I have provided two functions to that effect:  &lt;br /&gt;&lt;pre class="brush: f#"&gt;// Lock, can be used for mutual exclusion.&lt;br /&gt;// Locks should not be shared across instances of Scheduler.&lt;br /&gt;type Lock() =&lt;br /&gt;    let mutable locked = false;&lt;br /&gt;&lt;br /&gt;    member this.Grab() =&lt;br /&gt;        task {&lt;br /&gt;            do! waitUntil (fun() -&amp;gt; not locked)&lt;br /&gt;            locked &amp;lt;- true&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    member this.Release() =&lt;br /&gt;        task {&lt;br /&gt;            locked &amp;lt;- false&lt;br /&gt;            do! nextTask()&lt;br /&gt;            ()&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;// A blocking channel which can be used for cross-task communication.&lt;br /&gt;// Note that sending blocks until the message is received.&lt;br /&gt;type BlockingChannel&amp;lt;'M&amp;gt;() =&lt;br /&gt;    let mutable content = None&lt;br /&gt;    let mutable flag_send = false&lt;br /&gt;    let mutable flag_receive = false&lt;br /&gt;&lt;br /&gt;    member this.Send(m : 'M) =&lt;br /&gt;        task {&lt;br /&gt;            do! waitUntil (fun () -&amp;gt; not flag_send)&lt;br /&gt;            content &amp;lt;- Some m&lt;br /&gt;            flag_send &amp;lt;- true&lt;br /&gt;            do! waitUntil (fun () -&amp;gt; flag_receive)&lt;br /&gt;            flag_send &amp;lt;- false&lt;br /&gt;            content &amp;lt;- None&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    member this.Receive() =&lt;br /&gt;        task {&lt;br /&gt;            do! waitUntil (fun () -&amp;gt; flag_send)&lt;br /&gt;            let ret = content.Value&lt;br /&gt;            flag_receive &amp;lt;- true&lt;br /&gt;            do! waitUntil (fun () -&amp;gt; not flag_send)&lt;br /&gt;            flag_receive &amp;lt;- false&lt;br /&gt;            return ret&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Cooperative multi-tasking makes synchronization between tasks easy, as there is no concurrency involved.&lt;br /&gt;&lt;br /&gt;That's all for this time, in the next article I will describe how multiple tasks are executed by a single scheduler.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6768279972356368277?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6768279972356368277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6768279972356368277' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6768279972356368277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6768279972356368277'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/01/eventually-workflow.html' title='The Eventually workflow'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-7069446442267656325</id><published>2011-01-13T13:04:00.000-08:00</published><updated>2011-01-13T13:04:22.430-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computation expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='custom workflows'/><title type='text'>How to spread a computation over multiple update cycles</title><content type='html'>Let us consider a simple example: We want to implement an animation effect which can be used for "press start screens", among other things. The animation can be decomposed into three phases:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Fade-in effect where the text "press start" appears from the void. To achieve that, the text is rendered with full transparency initially, then gradually goes to fully opaque. This effect should be short, e.g. half a second.&lt;/li&gt;&lt;li&gt;Blinking effect. The text is rendered alternating between fully transparent and opaque. We don't want to alternate between the two modes every frame, as that would be two fast. The text should be rendered opaque for half a second, then transparent (or not rendered at all) for half a second, and so on...&lt;/li&gt;&lt;li&gt;Fade-out effect, which is triggered when the player presses the start button. It's similar to the fade-in effect, but in reverse.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h2&gt;The game update loop&lt;/h2&gt;&lt;br /&gt;The XNA framework, just as most other frameworks, encourages the developer to build their game in a specific way. The main function, which is implemented by the framework, repeatedly calls a function Update provided by the developer, followed by a call to another function Draw, also provided by the user. The combine execution time of these two functions should not exceed the amount of time separating two frames, which is about 16ms for a game running at 60 frames per second.&lt;br /&gt;In this context, implementing computations that need to span over multiple frames is a bit tricky. Not very complicated, and all experienced game developers can do that during their sleep. Nevertheless, I always found that annoying enough that it has often stopped me from implementing a cool animation that would have made my application look so much more professional.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Imperative code&lt;/h2&gt;&lt;br /&gt;For a moment, let us forget about the game loop and write some simple imperative code.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let sleep time dt exit =&lt;br /&gt;    let t = ref 0.0f&lt;br /&gt;    let dt = int (dt * 1000.0f)&lt;br /&gt;    while !t &lt; time &amp;&amp; not !exit do&lt;br /&gt;        System.Threading.Thread.Sleep(dt)&lt;br /&gt;&lt;br /&gt;let fade_time = 0.5f   // half a second&lt;br /&gt;let blink_time = 0.25f&lt;br /&gt;&lt;br /&gt;let alpha = ref 0.0f&lt;br /&gt;let is_visible = ref true&lt;br /&gt;&lt;br /&gt;            &lt;br /&gt;let run dt goto_fade_out =&lt;br /&gt;    let t = ref 0.0f&lt;br /&gt;    while !t &lt; fade_time do&lt;br /&gt;        alpha := !alpha + dt / fade_time&lt;br /&gt;        t := !t + dt&lt;br /&gt;        sleep dt dt (ref false)&lt;br /&gt;&lt;br /&gt;    while not !goto_fade_out do&lt;br /&gt;        is_visible := true&lt;br /&gt;        sleep blink_time dt goto_fade_out&lt;br /&gt;        is_visible := false&lt;br /&gt;        sleep blink_time dt goto_fade_out&lt;br /&gt;&lt;br /&gt;    let t = ref 0.0f&lt;br /&gt;    while !t &lt; fade_time do&lt;br /&gt;        alpha := !alpha - dt / fade_time&lt;br /&gt;        t := !t + dt&lt;br /&gt;        sleep dt dt (ref false)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Implementation using a state machine&lt;/h2&gt;Back to reality (where the game update loop rules), one way to break a computation over multiple update cycles is to use a state machine. Transitions are taken every cycle. Our state machine could have four states: FadeIn, BlinkOn, BlinkOff, FadeOut. It would have the following transitions: FadeIn to FadeIn, FadeIn to BlinkOn, BlinkOn to BlinkOff, BlinkOff to BlinkOn, BlinkOn to FadeOut, BlinkOff to FadeOut.While in FadeIn and FadeOut, the state machine maintains a single float representing the degree of transparency of the text.This can be implemented in F# using discriminated unions, as shown below.&lt;pre class="brush: f#"&gt;type States =&lt;br /&gt;    | FadeIn of float32        // 0.0 -&gt; 1.0&lt;br /&gt;    | Blink of bool * float32  // On/Off, Time left before transition&lt;br /&gt;    | FadeOut of float32       // 1.0 -&gt; 0.0&lt;br /&gt;&lt;br /&gt;let fade_time = 0.5f   // half a second&lt;br /&gt;let blink_time = 0.25f&lt;br /&gt;&lt;br /&gt;let initial = FadeIn 0.0f&lt;br /&gt;&lt;br /&gt;let update dt goto_fade_out state =&lt;br /&gt;    match state with&lt;br /&gt;    | FadeIn k -&gt;&lt;br /&gt;        let delta_k = dt / fade_time&lt;br /&gt;        let k = k + delta_k&lt;br /&gt;        if k &gt; 1.0f then&lt;br /&gt;            Blink (true, blink_time)&lt;br /&gt;        else&lt;br /&gt;            FadeIn k&lt;br /&gt;&lt;br /&gt;    | Blink (b, t) -&gt;&lt;br /&gt;        if goto_fade_out then&lt;br /&gt;            FadeOut 1.0f&lt;br /&gt;        else if t &lt;= dt then&lt;br /&gt;            Blink (not b, blink_time)&lt;br /&gt;        else&lt;br /&gt;            Blink (b, t - dt)&lt;br /&gt;&lt;br /&gt;    | FadeOut k -&gt;&lt;br /&gt;        let delta_k = dt / fade_time&lt;br /&gt;        let k = max (k - delta_k) 0.0f&lt;br /&gt;        FadeOut k&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Implementation using continuations&lt;/h2&gt;To an imperative programmer, functional programmers can seem a bit special. They like to do things in a complicated, twisted way. The method I will now show may appear unnecessarily complex, but it has its benefits, as we shall see.&lt;pre class="brush: f#"&gt;type States =&lt;br /&gt;    | Transparent of float32 * (bool * float32 -&gt; States)&lt;br /&gt;    | Blinking of bool * (bool * float32 -&gt; States)&lt;br /&gt;&lt;br /&gt;let fade_time = 0.5f   // half a second&lt;br /&gt;let blink_time = 0.25f&lt;br /&gt;&lt;br /&gt;let rec updateFadeIn alpha (_, dt) =&lt;br /&gt;    let delta_alpha = dt / fade_time&lt;br /&gt;    let alpha = alpha + delta_alpha&lt;br /&gt;    if alpha &gt; 1.0f then&lt;br /&gt;        Blinking (true, updateBlinking true blink_time)&lt;br /&gt;    else &lt;br /&gt;        Transparent (alpha, updateFadeIn alpha)&lt;br /&gt;&lt;br /&gt;and updateBlinking is_visible remaining (goto_fade_out, dt) =&lt;br /&gt;    if goto_fade_out then&lt;br /&gt;        Transparent (1.0f, updateFadeOut 1.0f)&lt;br /&gt;    else if remaining &gt;= dt then&lt;br /&gt;        Blinking (is_visible, updateBlinking is_visible (remaining - dt))&lt;br /&gt;    else&lt;br /&gt;        Blinking (not is_visible, updateBlinking (not is_visible) remaining)&lt;br /&gt;&lt;br /&gt;and updateFadeOut alpha (_, dt) =&lt;br /&gt;    let delta_alpha = dt / fade_time&lt;br /&gt;    let alpha = max (alpha - delta_alpha) 0.0f&lt;br /&gt;    Transparent (alpha, updateFadeOut alpha)&lt;br /&gt;&lt;br /&gt;let initial =&lt;br /&gt;    Transparent (0.0f, updateFadeIn 0.0f)&lt;br /&gt;&lt;br /&gt;let update state x =&lt;br /&gt;    match state with&lt;br /&gt;    | Transparent (_, cont) | Blinking (_, cont) -&gt; cont x&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;What I did here was move the guts of &lt;tt&gt;update&lt;/tt&gt; into the state itself. A state now includes a function which when called returns a new state (which itself includes a function which when called... you get the idea).&lt;h2&gt;Strengths and weaknesses of each approach&lt;/h2&gt;&lt;br&gt;The first method I exposed looks nice and easy to understand, but it won't work as it is. The problem is that it retains full control of the execution. There is not &lt;tt&gt;update&lt;/tt&gt; function which can be called every cycle to update the state.&lt;/br&gt;&lt;br&gt;A solution consists of executing this code on a separate thread, but that brings problems of its own. Access to shared data between the main thread which does the rendering and the update thread is one of them, another is stopping/continuing the update thread.&lt;/br&gt;&lt;br&gt;The second method has only one problem, it becomes hard to read and maintain when the number of states grows. It's perfectly viable for simple animations, but it can't be used for the top level of the application (which can itself be seen as some sort of animation, the complex and interactive kind).&lt;/br&gt;&lt;br&gt;Statistics show that the third method will cause 95% of the population of programmers to get headaches. You'll it's actually very close to the second method, once you get the idea. I'm sure motivated programmers can train themselves to master this technique, but in this context, it's pointless.&lt;/br&gt;&lt;br&gt;The only reason I showed the third technique is to introduce features of F# called &lt;em&gt;computation expressions&lt;/em&gt; and &lt;em&gt;custom workflows&lt;/em&gt;. These features make it possible to write code using an extended subset of F# usual syntax and have it processed and executed in a manner controlled by the programmer. Understanding continuations is required in order to implement new custom workflows, but it's not necessary to take advantage of existing workflows.&lt;/br&gt;&lt;br&gt;These features are described in the &lt;a href="http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597448"&gt;F# specification&lt;/a&gt;. There is also a chapter in the &lt;a href="http://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions"&gt;F# wikibook&lt;/a&gt;. Tomas Petricek has some articles (&lt;a href="http://tomasp.net/articles/imperative-i-return.aspx"&gt;1&lt;/a&gt; &lt;a href="http://tomasp.net/blog/imperative-ii-break.aspx"&gt;2&lt;/a&gt;) on his blog.&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-7069446442267656325?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/7069446442267656325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=7069446442267656325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7069446442267656325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7069446442267656325'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/01/how-to-spread-computation-over-multiple.html' title='How to spread a computation over multiple update cycles'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4270584294074051707</id><published>2011-01-09T12:23:00.000-08:00</published><updated>2011-01-09T12:23:24.731-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Untying the game update loop</title><content type='html'>In a video game, what do the menu system, an AI agent and an animated HUD component have in common? They are all a pain in the neck to implement over the game update loop.&lt;br /&gt;&lt;br /&gt;The difficulty arises from the gap between the concept and the code implementing it. For instance, a menu system is pretty simple to specify:&lt;br /&gt;1. Identify the controller which is used to control the game,&lt;br /&gt;2. Show the main menu&lt;br /&gt;3. Wait for the user to select an entry&lt;br /&gt;4. Depending on the entry, remove the menu and show another screen, which may be another menu, or the game itself.&lt;br /&gt;&lt;br /&gt;The game update loop requires that we split up these few steps into tiny little chunks that fit in 16ms time slices. This requires the programmer to introduce variables to keep track of where the program currently is and where it's headed:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type GameState =&lt;br /&gt;| PressStartFadeIn of ...&lt;br /&gt;| PressStartWaitButtonPress of ...&lt;br /&gt;| PressStartFadeOut of ...&lt;br /&gt;| MenuFadeIn of ...&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;let update(gt : GameTime) =&lt;br /&gt;  state &amp;lt;-&lt;br /&gt;    match state with&lt;br /&gt;    | PressStartFadeIn ...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;The problem with this approach is that the workflow which was so obvious in the specification is now hidden in a state machine. This approach using state machines is common when implementing simple AI agents and animations.&lt;br /&gt;When dealing with the menu system, another objected-oriented approach is often preferred, with a class per screen type. Transitions from one screen to another are implemented using events and handlers, or hard-coded into the screens themselves. For instance, the press start screen takes care of creating and showing the menu screen when it hides itself.  In any case, figuring out the order in which screens come and go by reading the code is not trivial.&lt;br /&gt;&lt;br /&gt;Ideally, one would like to program the steps using that sort of code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;while not exit_requested do&lt;br /&gt;  let press_start_screen = new PressStartScreen()&lt;br /&gt;  press_start_screen.Show()&lt;br /&gt;  let player = press_start_screen.GetPlayer()&lt;br /&gt;  press_start_screen.Hide()&lt;br /&gt;&lt;br /&gt;  let menu_screen = new MenuScreen()&lt;br /&gt;  menu_screen.Show()&lt;br /&gt;  let entry = menu_screen.GetEntry()&lt;br /&gt;  menu_screen.Remove();&lt;br /&gt;  match entry with&lt;br /&gt;  | Play -&amp;gt; play(); showScores()&lt;br /&gt;  | Scores -&amp;gt; showScores()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Happily, F# makes this possible thanks to so-called computation expressions. I am not going into details in one single post, so for now I will simply refer you to the code I have written. It's all in XNAUtils my library for development of games for the Xbox 360.&lt;br /&gt;I have developed a &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/XNAUtils/CoopMultiTasking.fs#cl-3"&gt;custom workflow&lt;/a&gt; and its associated builder &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/XNAUtils/CoopMultiTasking.fs#cl-78"&gt;TaskBuilder&lt;/a&gt;.  There is a class which takes care of executing a set of tasks in type &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/XNAUtils/CoopMultiTasking.fs#cl-169"&gt;Scheduler&lt;/a&gt;.  Here are some &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/XNAUtils/Animations.fs"&gt;animations&lt;/a&gt; demonstrating how it's used.  Another example, from the &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/XNAUtils/PressStartScreen.fs#cl-17"&gt;PressStartScreen&lt;/a&gt;: &lt;br /&gt;&lt;pre class="brush: f#"&gt;// This task is chopped in blocks and each block is executed by the scheduler each frame (see Main.Update())&lt;br /&gt;    let press_start_task = task {&lt;br /&gt;        // subtask that makes the "press start" text blink. Executes concurrently&lt;br /&gt;        let blinker =&lt;br /&gt;            sys.Spawn(anim.Task)&lt;br /&gt;&lt;br /&gt;        // Task to check if a button is pressed. Sets player when that happens.&lt;br /&gt;        let player : PlayerIndex option ref = ref None&lt;br /&gt;        while (!player).IsNone do&lt;br /&gt;            for p in all_players do&lt;br /&gt;                let state = GamePad.GetState(p)&lt;br /&gt;                if state.IsConnected&lt;br /&gt;                    &amp;amp;&amp;amp; (state.Buttons.Start = ButtonState.Pressed&lt;br /&gt;                        || state.Buttons.A = ButtonState.Pressed) then&lt;br /&gt;                    player := Some p&lt;br /&gt;            do! nextFrame()&lt;br /&gt;&lt;br /&gt;        // Stop blinking&lt;br /&gt;        blinker.Kill()&lt;br /&gt;    &lt;br /&gt;        // To be nice, wait until the blinker is done.&lt;br /&gt;        // Depending on the blinking period, this could take long as we only check for the kill flag once per blink.&lt;br /&gt;        do! sys.WaitUntil(fun () -&amp;gt; blinker.IsDead)&lt;br /&gt;&lt;br /&gt;        // Return the index of the player that pressed start.&lt;br /&gt;        return&lt;br /&gt;            match !player with&lt;br /&gt;            | Some p -&amp;gt; p&lt;br /&gt;            | None -&amp;gt; failwith "Unreachable"&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;All of this is put together in a &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/Samples/CoopMultitaskingSample/"&gt;sample application&lt;/a&gt;. Be sure to take a look at the &lt;a href="https://bitbucket.org/johdex/xnautils/src/4de7ad38b16e/Samples/CoopMultitaskingSample/Lib/Main.fs"&gt;main code&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4270584294074051707?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4270584294074051707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4270584294074051707' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4270584294074051707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4270584294074051707'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2011/01/untying-game-update-loop.html' title='Untying the game update loop'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3356524028564457267</id><published>2010-12-28T05:01:00.000-08:00</published><updated>2010-12-28T09:16:39.041-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='wp7'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Project templates for F# games on Windows Phone 7 using XNA</title><content type='html'>The recent presentation of the Windows Phone 7 platform and its marketplace by Microsoft has attracted a lot of attention. The success of the iPhone and its App store has opened new markets to independent developers.&lt;br /&gt;&lt;br /&gt;Both .NET and F# are considered very attractive development platforms, and some have shown interest for a set of project templates allowing the use of F# for developing applications for Windows Phone 7.&lt;br /&gt;&lt;br /&gt;Taking advantage of the experience I gained building a project template for F# + XNA for Xbox 360, I have created two new templates for F# + XNA for WP7.&lt;br /&gt;&lt;br /&gt;They are now available on the Visual Studio Gallery:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/9b9d51d9-8b54-4f5d-b563-9952259eb555"&gt;F# + C# Game For Windows Phone (XNA)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/4a71154f-c590-4370-9d0f-f5072d69996f"&gt;F# Library for Windows Phone (XNA)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I must also mention the earlier templates by Dan Mohl, which target WP7 through Silverlight:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/17454c58-c1d9-4640-afe1-7943db13891e"&gt;F# and C# Win Phone App (Silverlight)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/52928c6e-f77f-4ebd-a2f9-9815111bfa33"&gt;F# and C# Win Phone List App (Silverlight)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/1e70ea3a-c564-4199-8915-b651a0035bbe"&gt;F# and C# Win Phone Panorama&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I am now considering to work on the following templates:&lt;br /&gt;- PC hosted game&lt;br /&gt;- PC XNA+winforms app&lt;br /&gt;- PC lib (with the script I mentioned in &lt;a href="http://sharp-gamedev.blogspot.com/2010/12/interactive-game-development-with-fsi.html"&gt;Interactive Game Development with XNA and FSI&lt;/a&gt;)&lt;br /&gt;- Xbox360 hosted game&lt;br /&gt;&lt;br /&gt;Please let me know which template you think would be most valuable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3356524028564457267?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3356524028564457267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3356524028564457267' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3356524028564457267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3356524028564457267'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/12/project-templates-for-f-games-on.html' title='Project templates for F# games on Windows Phone 7 using XNA'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2756499150784393080</id><published>2010-12-26T11:01:00.000-08:00</published><updated>2010-12-26T11:01:58.966-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fsi'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Interactive game development with FSI and XNA</title><content type='html'>I recently looked at a presentation by Don Syme about the future of F# and type providers. The entire demo was conducted using F# interactive and a Windows Forms.&lt;br /&gt;&lt;br /&gt;The same can be done for XNA. First, you need to get the code sample that shows how to embed XNA into a Windows Forms control. It's available &lt;a href="http://create.msdn.com/en-US/education/catalog/sample/winforms_series_1"&gt;in the education catalog&lt;/a&gt; on the App hub.&lt;br /&gt;&lt;br /&gt;Then, you need to wrap the control into a form, and add some functionality to easily couple plug in an F# function.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;#r @"D:\Documents\WinForms\WinFormsGraphicsDevice\bin\Release\WinFormsGraphicsDevice.exe"&lt;br /&gt;&lt;br /&gt;#I @"C:\Program Files\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86"&lt;br /&gt;#r "Microsoft.Xna.Framework.Graphics.dll"&lt;br /&gt;#r "Microsoft.Xna.Framework.dll"&lt;br /&gt;#r "Microsoft.Xna.Framework.Game.dll"&lt;br /&gt;&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;open Microsoft.Xna.Framework&lt;br /&gt;&lt;br /&gt;type XnaControl() =&lt;br /&gt;    inherit WinFormsGraphicsDevice.GraphicsDeviceControl()&lt;br /&gt;&lt;br /&gt;    let mutable drawer = fun (dt : GameTime) -&gt; ()&lt;br /&gt;    let watch = new System.Diagnostics.Stopwatch()&lt;br /&gt;    let mutable last_time = watch.Elapsed&lt;br /&gt;&lt;br /&gt;    member this.Drawer&lt;br /&gt;        with get ()  = drawer&lt;br /&gt;        and  set (v) = drawer &lt;- v&lt;br /&gt;        &lt;br /&gt;    override this.Initialize() =&lt;br /&gt;        watch.Start()&lt;br /&gt;        last_time &lt;- watch.Elapsed&lt;br /&gt;&lt;br /&gt;    override this.Draw() =&lt;br /&gt;        let diff = watch.Elapsed - last_time&lt;br /&gt;        last_time &lt;- watch.Elapsed&lt;br /&gt;        GameTime(diff, watch.Elapsed)&lt;br /&gt;        |&gt; drawer&lt;br /&gt;&lt;br /&gt;type XnaForm() =&lt;br /&gt;    inherit Form()&lt;br /&gt;&lt;br /&gt;    let ctrl = new XnaControl()&lt;br /&gt;    let animationHandler = new System.EventHandler(fun _ _ -&gt; ctrl.Invalidate())&lt;br /&gt;    do&lt;br /&gt;        ctrl.Dock &lt;- DockStyle.Fill&lt;br /&gt;        base.Controls.Add(ctrl)&lt;br /&gt;&lt;br /&gt;    member this.XnaControl = ctrl&lt;br /&gt;&lt;br /&gt;    member this.EnableAnimation() =&lt;br /&gt;        Application.Idle.AddHandler(animationHandler)&lt;br /&gt;&lt;br /&gt;    member this.DisableAnimation() =&lt;br /&gt;        Application.Idle.RemoveHandler(animationHandler)&lt;br /&gt;&lt;/pre&gt;This is how I use it:&lt;pre class="brush: f#"&gt;let form = new XnaForm()&lt;br /&gt;form.Show()&lt;br /&gt;let content = new Content.ContentManager(form.XnaControl.Services)&lt;br /&gt;content.RootDirectory &lt;- @"D:\Documents\WorldConquest\ContentLibrary\bin\x86\Debug\Content"&lt;br /&gt;&lt;br /&gt;let units : Graphics.Texture2D = content.Load("units")&lt;br /&gt;&lt;br /&gt;let batch = new Graphics.SpriteBatch(form.XnaControl.GraphicsDevice)&lt;br /&gt;&lt;br /&gt;let draw _ =&lt;br /&gt;    try&lt;br /&gt;        batch.Begin()&lt;br /&gt;        batch.Draw(units, Vector2.Zero, Color.White)&lt;br /&gt;    finally&lt;br /&gt;        batch.End()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;form.XnaControl.Drawer &lt;- draw&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You'll probably want to load some content (fonts, textures...) otherwise you won't be able to draw much. I don't have any nice way to build content interactively yet. For now, this is what I have to do:&lt;br /&gt;1. Add a C# XNA game library&lt;br /&gt;2. Add an XNA content project&lt;br /&gt;3. Reference the content project from the library created in step 1, and configure the library to use the "Reach" API. This is done from the project's properties.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2756499150784393080?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2756499150784393080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2756499150784393080' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2756499150784393080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2756499150784393080'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/12/interactive-game-development-with-fsi.html' title='Interactive game development with FSI and XNA'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6751936569254611877</id><published>2010-12-24T08:15:00.000-08:00</published><updated>2010-12-24T08:15:15.334-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>How to make a visual studio project template</title><content type='html'>Here is the simple 14-step procedure to build a template for F# projects targeting exotic platforms.&lt;br /&gt;&lt;br /&gt;Mixing F# and XNA's dna:&lt;br /&gt;&lt;br /&gt;0. Get a build of the F# core library for the exotic platform.&lt;br /&gt;&lt;br /&gt;1. Create a new C# XNA library project&lt;br /&gt;&lt;br /&gt;2. Create a new F# library project&lt;br /&gt;&lt;br /&gt;3. Create a directory "Dependencies" in the F# library.&lt;br /&gt;   Put the custom-built F# core dll files there.&lt;br /&gt;   Add these files to the project.&lt;br /&gt;&lt;br /&gt;4. Merge the XNA "dna" from the C# XNA library project file (with extension .csproj) into the F# library project (with extension .fsproj)&lt;br /&gt;   This includes:&lt;br /&gt;   a) Fixing platforms (remove "Any CPU", add the XNA platform)&lt;br /&gt;   b) Fixing configurations (the common one, as well as the release and debug ones too)&lt;br /&gt;   c) Adding all references to XNA dlls (simple copy-paste from the XNA csproj file)&lt;br /&gt;   d) Importing the XNA targets file (after the F# targets file)&lt;br /&gt;   c) and d) are easy, a) and b) is mostly text merging, using the csproj file whenever there are conflicts.&lt;br /&gt;   &lt;br /&gt;5. Fix references in the .fsproj file.&lt;br /&gt;   a) Replace or add the reference to FSharp.Core.dll, using a hint path pointing at "Dependencies".&lt;br /&gt;   b) Check that any reference to "mscorlib.dll" has no HintPath element.&lt;br /&gt;   &lt;br /&gt;6. Save your work, commit it if you are using revision control (advised)&lt;br /&gt;&lt;br /&gt;7. Try to build the project. If you are lucky it will be successful. Look at the command line in the output window to check that the right version of FSharp.Core.dll was used (the one in Dependencies).&lt;br /&gt;&lt;br /&gt;8. Clean the project&lt;br /&gt;&lt;br /&gt;9. Choose "Export template" in the file menu. Don't install the template in Visual Studio.&lt;br /&gt;   If you mistakenly installed it, you can remove it by deleting the zip file from "My Documents\Visual Studio 2010\Templates\Projects".&lt;br /&gt;&lt;br /&gt;10. You will get a zip file under "My Exported Templates"&lt;br /&gt;&lt;br /&gt;11. Open the zip file, copy __TemplateIcon and MyTemplate files into the F# library project.&lt;br /&gt;&lt;br /&gt;12. Edit MyTemplate to add the following lines under &lt;TemplateContent&gt;&lt;Project&gt;.&lt;br /&gt;&lt;pre&gt;     &amp;lt;Folder Name="Dependencies" TargetFolderName="Dependencies"&gt;&lt;br /&gt;        &amp;lt;ProjectItem ReplaceParameters="false" TargetFileName="FSharp.Core.dll"&gt;FSharp.Core.dll&amp;lt;/ProjectItem&gt;&lt;br /&gt;        &amp;lt;ProjectItem ReplaceParameters="false" TargetFileName="FSharp.Core.xml"&gt;FSharp.Core.xml&amp;lt;/ProjectItem&gt;&lt;br /&gt;        &amp;lt;ProjectItem ReplaceParameters="false" TargetFileName="FSharp.Core.optdata"&gt;FSharp.Core.optdata&amp;lt;/ProjectItem&gt;&lt;br /&gt;        &amp;lt;ProjectItem ReplaceParameters="false" TargetFileName="FSharp.Core.sigdata"&gt;FSharp.Core.sigdata&amp;lt;/ProjectItem&gt;&lt;br /&gt;     &amp;lt;/Folder&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;13. Remove the bin/ and obj/ directories, if any.  &lt;br /&gt;&lt;br /&gt;14. Zip the content of the F# library project directory (not the directory itself!). You now have a project template file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6751936569254611877?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6751936569254611877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6751936569254611877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6751936569254611877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6751936569254611877'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/12/how-to-make-visual-studio-project.html' title='How to make a visual studio project template'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8155758051340259705</id><published>2010-12-11T08:53:00.000-08:00</published><updated>2010-12-14T14:06:31.082-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>On the performance of F# on the Xbox 360</title><content type='html'>I recently mentioned on the App Hub (the gathering place for indies targeting Windows Phone 7 and the Xbox 360) that I was using F#. Someone asked what programming in F# was like.&lt;br /&gt;&lt;br /&gt;Obviously, I enjoy it very much, and I sincerely hope that other XNA game programmers will decide to give F# a place in their development tools.&lt;br /&gt;&lt;br /&gt;I bet there are programmers out there who wonder if all these nice features that F# supports don't come at too high a cost when it comes to performance. I managed to write a fairly computationally-intensive game for the Xbox 360 in F#, so obviously writing a game in F# is feasible. However, the question remains whether I could have done a significantly better job using C#? &lt;br /&gt;&lt;br /&gt;In an attempt to answer this question, I am comparing in this article the performance of four implementations of an octree: Two in F# and two in C#.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem area&lt;/h2&gt;&lt;br /&gt;An octree is a data structure often used in 3d games for collision detection. There are different ways to design and implement an octree and its associated algorithms, depending on one's requirements. In my case, the requirements are, in increasing order of importance:&lt;br /&gt;&lt;br /&gt;1. Fast querying. Building the octree should be reasonably fast, but need not be as fast as querying. Typically, octrees are built once (possibly at compile time) and queried every frame.&lt;br /&gt;2. Generic. The implementation should be suitable for use with spheres, boxes, triangles, rays...&lt;br /&gt;3. Maintainable source code. Note that this requirement has higher importance than efficiency. As an independent developer, I am not trying to compete with the big guns in number of polygons and objects. Moreover, my time available for programming games is very limited, and I don't want to get stuck with an implementation that may be fast now, but hard to maintain.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Data structure&lt;/h2&gt;&lt;br /&gt;With this in mind, I came up with the following design for the data structure in F#:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type Node&amp;lt;'TS&amp;gt; =&lt;br /&gt;    { bbox : BoundingBox&lt;br /&gt;      data : Data&amp;lt;'TS&amp;gt; }&lt;br /&gt;and Data&amp;lt;'TS&amp;gt; =&lt;br /&gt;    | Leaf of int * 'TS          // sequence length, sequence of items&lt;br /&gt;    | Inner of Node&amp;lt;'TS&amp;gt; array   // Array of 8 items exactly&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Six lines, all in all. Each node has a bounding box covering all volumes contained in this node and its descendants. Each node is either an internal node, in which case it has references to its 8 children, or a leaf, and it has references to the shapes it contains. The type TS denotes a sequence of shapes.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Construction&lt;/h2&gt;&lt;br /&gt;The function below is used to insert an item into a node of a tree (or into one of its descendants). In the case where the item to insert overlaps the boundaries of the bounding boxes, it will be inserted into multiple leaves. Some implementations avoid this by splitting shapes, but that's too advanced for my needs.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let rec insert max_count max_depth intersect node item depth =&lt;br /&gt;    assert (&lt;br /&gt;       intersect node.bbox item&lt;br /&gt;    )&lt;br /&gt;    &lt;br /&gt;    match node.data with&lt;br /&gt;    | Leaf(count, items) when (depth &amp;gt;= max_depth || count &amp;lt; max_count) -&amp;gt;&lt;br /&gt;        { node with data = Leaf(count + 1, item :: items) }&lt;br /&gt;    | Leaf(count, items) -&amp;gt;&lt;br /&gt;        let node' = split intersect node&lt;br /&gt;        insert max_count max_depth intersect node' item (depth + 1)&lt;br /&gt;    | Inner(children) -&amp;gt;&lt;br /&gt;        { node with&lt;br /&gt;            data = Inner(&lt;br /&gt;                    children&lt;br /&gt;                    |&amp;gt; Array.map (fun child_node -&amp;gt;&lt;br /&gt;                            if intersect child_node.bbox item&lt;br /&gt;                            then insert max_count max_depth intersect child_node item (depth + 1)&lt;br /&gt;                            else child_node&lt;br /&gt;                        )&lt;br /&gt;                    )&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The function above has quite a few arguments, but the first three are typically constant. One can therefore define an additional function using currying:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let myInsert = insert 20 5 myIntersectionPredicate&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Using myInsert, the tired programmer is saved the effort of repeatedly passing the first three parameters.&lt;br /&gt;&lt;br /&gt;Note that the function is limited to nodes which are of the type Node&amp;lt;'T list&amp;gt;. The Node type is immutable, and in this setting, F# lists are fairly efficient. An alternative would have been to use mutable nodes and resizeable arrays, an approach I picked for the implementations in C#.&lt;br /&gt;&lt;br /&gt;There is another function named "split" which I am not showing in this article. Given a leaf node, it produces an inner node and 8 children with equivalent content.&lt;br /&gt;&lt;br /&gt;My early measurements showed that lists might not be the most appropriate data structure to use once the octree is built. Arrays can be iterated over more efficiently. The function below translates an octree "under construction" into a "query-able fast octree".&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let rec freeze (node : Node&amp;lt;'T list&amp;gt;) : Node&amp;lt;'T[]&amp;gt; =&lt;br /&gt;    match node.data with&lt;br /&gt;    | Leaf (count, ts) -&amp;gt; { bbox = node.bbox ; data = Leaf (count, Array.ofList ts) }&lt;br /&gt;    | Inner (children) -&amp;gt; { bbox = node.bbox ; data = Inner (children |&amp;gt; Array.map freeze) }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Querying&lt;/h2&gt;&lt;br /&gt;Checking for overlap of items contained in the octree with another item is done using a recursive function, which goes into the relevant leaves, thus avoiding unnecessary item-to-item intersection checks.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let checkIntersection intersectBbox intersectSomeItem node =&lt;br /&gt;    let rec work node =&lt;br /&gt;        intersectBbox node.bbox&lt;br /&gt;        &amp;amp;&amp;amp;&lt;br /&gt;        match node.data with&lt;br /&gt;        | Leaf(_, items) -&amp;gt;&lt;br /&gt;            intersectSomeItem items&lt;br /&gt;        | Inner(children) -&amp;gt;&lt;br /&gt;            children |&amp;gt; Array.exists work&lt;br /&gt;        &lt;br /&gt;    work node&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Something that might be puzzling about this function is that it seems it lacks an "item" parameter. Actually, it's hidden in the "intersectBbox" and "intersectSomeItem" predicates. Those are typically constructed using closures that capture the item of interest, as shown below:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let intersectBBox2 (spheres : BoundingSphere[]) (i : int) =&lt;br /&gt;    let sph = spheres.[i]&lt;br /&gt;&lt;br /&gt;    fun (box : BoundingBox) -&amp;gt;&lt;br /&gt;        box.Intersects(sph)&lt;br /&gt;&lt;br /&gt;let intersectBSphere (spheres1 : BoundingSphere[]) (spheres2 : BoundingSphere[]) (i1 : int) =&lt;br /&gt;    let sph = spheres1.[i1]&lt;br /&gt;&lt;br /&gt;    fun i2s -&amp;gt;&lt;br /&gt;        i2s&lt;br /&gt;        |&amp;gt; Array.exists (fun i2 -&amp;gt; sph.Intersects(spheres2.[i2]))&lt;br /&gt;&lt;br /&gt;let checkIntersection_BoundingSpheres spheres_octree spheres2 node item =&lt;br /&gt;    checkIntersection (intersectBBox2 spheres2 item) (intersectBSphere spheres2 spheres_octree item) node&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Alternative implementations&lt;/h2&gt;&lt;br /&gt;The code showed above originates from an implementation which I labelled "Virtual". It makes heavy use of function values. Calls to the functions behind these function values are called "virtual calls", and are often slower than direct calls.&lt;br /&gt;&lt;br /&gt;F# has a feature which other .NET languages lack, namely inlining. Inlining can be used to avoid virtual calls, which in theory allows to achieve the speed of direct calls without losing genericity. Moreover, it can enable compilation-time optimizations that are not available to the JIT at run-time. The down-side is that they increase the size of the generated code. Inlining can also lead to slower code when used inappropriately. I wrote a variant which uses inlining labelled "Inline". It uses the following replacement for Array.exists:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let inline exists (pred : 'T -&amp;gt; bool) (xs : 'T[]) : bool =&lt;br /&gt;    let mutable i = 0&lt;br /&gt;    while i &amp;lt; xs.Length &amp;amp;&amp;amp; not (pred xs.[i]) do&lt;br /&gt;        i &amp;lt;- i + 1&lt;br /&gt;    i &amp;lt; xs.Length&lt;br /&gt;&lt;/pre&gt;The implementation of "insert" in this variant is also inlined, but "checkIntersection" isn't. Time measurements show that inlining clearly is beneficial in this case.&lt;br /&gt;&lt;br /&gt;How do these implementations in F# fare compared to implementations in C#? I wrote two variants in C#. The first one is inspired from the F# code and maintains its level of genericity. It uses delegates where F# uses function values, and LINQ where F# uses functions from the Array and List modules.  The second C# variant ("Specific") is based on the first one with genericity removed, thus allowing the removal of delegates (direct method calls are used instead). Hand-made loops (using foreach and for) are used instead of LINQ.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Benchmark&lt;/h2&gt;&lt;br /&gt;Three different octrees are used with different levels of space density. The number of shapes they contain are identical, but the size of each shapes is different. The larger the shapes, the denser the space.  Three sets of external shapes are created, also with varying levels of density.  The timings measure on the one hand the creation of each octree, the total amount of time to query each octree using each set of external shape. The queries are repeated in order to give significant run times, and avoid wide variation due to GC interruptions on the Xbox 360.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Results&lt;/h2&gt;&lt;br /&gt;Results vary depending on the specific sets of shapes, and vary from a run to the other. The results I'm listing here are qualitatively representative of the runs I made.   &lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt; &lt;td&gt;&lt;br /&gt;For the PC platform:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Virtual sparse: 0.016 / 1.185&lt;br /&gt;Virtual: 0.011 / 1.136&lt;br /&gt;Virtual dense: 0.096 / 1.029&lt;br /&gt;&lt;br /&gt;Inline sparse: 0.016 / 0.777&lt;br /&gt;Inline: 0.011 / 0.743&lt;br /&gt;Inline dense: 0.093 / 0.651&lt;br /&gt;&lt;br /&gt;Delegate sparse: 0.009 / 1.194&lt;br /&gt;Delegate: 0.007 / 1.150&lt;br /&gt;Delegate dense: 0.045 / 0.941&lt;br /&gt;&lt;br /&gt;Specific sparse: 0.007 / 0.913&lt;br /&gt;Specific: 0.007 / 0.890&lt;br /&gt;Specific dense: 0.043 / 0.759 &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt; &lt;td&gt;&lt;br /&gt;For the Xbox platform:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Virtual sparse: 0.170 / 1.062&lt;br /&gt;Virtual: 0.194 / 0.972&lt;br /&gt;Virtual dense: 2.193 / 1.800&lt;br /&gt;&lt;br /&gt;Inline sparse: 0.117 / 0.574&lt;br /&gt;Inline: 0.146 / 0.558&lt;br /&gt;Inline dense: 2.082 / 0.677&lt;br /&gt;&lt;br /&gt;Delegate sparse: 0.082 / 1.605&lt;br /&gt;Delegate: 0.098 / 1.543&lt;br /&gt;Delegate dense: 0.752 / 2.172&lt;br /&gt;&lt;br /&gt;Specific sparse: 0.068 / 0.568&lt;br /&gt;Specific: 0.094 / 0.542&lt;br /&gt;Specific dense: 0.656 / 0.423 &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The pairs of numbers are the time to build and the time to query, in seconds.  The datasets for the PC platform are much larger than those for the Xbox 360 platform. With identically sized datasets, the PC times were too low to be significant.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Observations&lt;/h2&gt;&lt;br /&gt;The time to build is always smaller for the C# implementation. This is not surprising, as I'm comparing two different algorithms, one using mutable structures (in the C# implementation), the other using immutable data structures requiring significantly more short-lived objects.&lt;br /&gt;&lt;br /&gt;Using inlining improves the performance of the F# implementation, regardless of the platform.  The generic C# implementation is the slowest, regardless of the platform. It's not showed here, but earlier measurements on the Xbox 360 showed that the problem was in LINQ.&lt;br /&gt;&lt;br /&gt;The performance profile of F# on the Xbox 360 is not the same as on the PC. The F# does remarkably well on the PC, the inline implementation being the fastest. On the Xbox 360, the non-generic versions wins, but the F# versions holds its ground pretty well.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Conclusions&lt;/h2&gt;&lt;br /&gt;As far as I am concerned, F# is more than good enough when it comes to performance, compared to C#.&lt;br /&gt;&lt;br /&gt;This does not mean that F# is better than C#, though. I spent my optimising efforts on the F# implementations, I can imagine a proficient C# programmer could do better than my variants in this language.&lt;br /&gt;&lt;br /&gt;By the way, I used Red Gate's Reflector to analyse the code generated by the F# compiler and optimise it. I also used a profiler (Jet Brain's dotTrace Performance 4.0), but its measurements on my PC were not a good indication of the performance on the Xbox 360.&lt;br /&gt;&lt;br /&gt;All source code is available on &lt;a href="http://bitbucket.org/johdex/octreebenchmark/downloads"&gt;bitbucket&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Update: 2010 dec 14&lt;/h2&gt;&lt;br /&gt;I have updated the C# and F# implementations to match each other more closely:&lt;br /&gt;- The C# implementation now uses List&lt;t&gt; during construction of the octree, and arrays during querying. Apparently, iterating over an array is faster than iterating over List&amp;lt;t&amp;gt;.&lt;br /&gt;- The F# implementation now uses mutable ResizeArray&amp;lt;t&amp;gt; (the F# synonym for List&amp;lt;t&amp;gt;, which I find more appropriate as the term "list" is coupled to "linked list" in my mind). Unlike the C# implementations, new nodes are still created when splitting leaves.&lt;br /&gt;&lt;br /&gt;Updated results follow:&lt;br /&gt;&lt;br /&gt;On the Xbox 360:&lt;br /&gt;&lt;br /&gt;&lt;/t&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Batch&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;Build time (s)&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;Query time (s)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Virtual sparse&lt;/td&gt;&lt;td&gt;0,155&lt;/td&gt;&lt;td&gt;0,954&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Virtual normal&lt;/td&gt;&lt;td&gt;0,247&lt;/td&gt;&lt;td&gt;0,873&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Virtual dense&lt;/td&gt;&lt;td&gt;1,331&lt;/td&gt;&lt;td&gt;1,472&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Inline sparse&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,110&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,548&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Inline normal&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,199&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,480&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Inline dense&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;1,202&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,497&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Delegate sparse&lt;/td&gt;&lt;td&gt;0,084&lt;/td&gt;&lt;td&gt;1,629&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Delegate normal&lt;/td&gt;&lt;td&gt;0,165&lt;/td&gt;&lt;td&gt;1,537&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Delegate dense&lt;/td&gt;&lt;td&gt;0,927&lt;/td&gt;&lt;td&gt;2,406&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Specific sparse&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,068&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,503&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Specific normal&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,149&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,404&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Specific dense&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,855&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,405&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;On the PC:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Batch&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;Build time (s)&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;Query time (s)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Virtual sparse&lt;/td&gt;&lt;td&gt;0,016&lt;/td&gt;&lt;td&gt;1,179&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Virtual normal&lt;/td&gt;&lt;td&gt;0,017&lt;/td&gt;&lt;td&gt;0,994&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Virtual dense&lt;/td&gt;&lt;td&gt;0,084&lt;/td&gt;&lt;td&gt;1,038&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Inline sparse&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,014&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,809&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Inline normal&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,016&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,671&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Inline dense&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,082&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,685&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Delegate sparse&lt;/td&gt;&lt;td&gt;0,010&lt;/td&gt;&lt;td&gt;1,199&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Delegate normal&lt;/td&gt;&lt;td&gt;0,011&lt;/td&gt;&lt;td&gt;0,954&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Delegate dense&lt;/td&gt;&lt;td&gt;0,053&lt;/td&gt;&lt;td&gt;0,955&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Specific sparse&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,007&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,802&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Specific normal&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,011&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,680&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="background-color: #444444;"&gt;Specific dense&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,055&lt;/td&gt;&lt;td style="background-color: #444444;"&gt;0,685&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;From these updated results, one can observe the following points:&lt;br /&gt;- When it comes to querying, on the PC, the optimized F# and C# implementations (called Inline and Specific) are now running at more-or-less identical speeds. The non-optimized implementations are also very similar.&lt;br /&gt;- On the Xbox 360, the C# optimized version is the fastest one, with the F# optimized close behind. The F# non-optimized version is noticeable faster than the C# non-optimized one. I think this is all due to the inefficiency of LINQ on the Xbox 360.&lt;br /&gt;- Regarding build times, the F# versions are now closer to the C# versions, but still significantly slower. Although not a problem in practice (octrees are typically not re-built every frame), I wonder why.&lt;br /&gt;&lt;br /&gt;The main conclusion from the first version of this article still holds: The performance of F# roughly matches that of C#.&lt;br /&gt;&lt;br /&gt;I personally think that when it comes to beauty, the optimized F# version beats the C# version, but that's just my opinion :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8155758051340259705?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8155758051340259705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8155758051340259705' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8155758051340259705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8155758051340259705'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/12/on-performance-of-f-on-xbox-360.html' title='On the performance of F# on the Xbox 360'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4134023466945654159</id><published>2010-12-06T13:18:00.000-08:00</published><updated>2010-12-06T13:29:10.497-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>New trailer</title><content type='html'>My game for the Xbox 360 has been renamed to "Asteroid Sharp Shooter".&lt;br /&gt;&lt;br /&gt;They say "Ignorance is bliss", and they are right. After uploading a freshly made trailer for my game, I did a search on "Asteroid Hunter" on youtube. In the results, an indie game for mobile phones (Android and iPhone) turned up. It's dated from July 2010. Its author hasn't contacted me and as far as I know, probably does not know about me. I decided to rename my game nevertheless. I must say I don't like the new name as much, but "c'est la vie".&lt;br /&gt;&lt;br /&gt;Anyway, here is the new trailer!&lt;br /&gt;&lt;br /&gt;&lt;object height="385" width="640"&gt;&lt;param name="movie" value="http://www.youtube.com/v/sZ_BBrnp8ZY?fs=1&amp;amp;hl=sv_SE"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/sZ_BBrnp8ZY?fs=1&amp;amp;hl=sv_SE" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: xx-small;"&gt;The music for the trailer is "Remnants of Yesterday" by "SynthR", under &lt;a href="http://creativecommons.org/licenses/by-sa/2.5/"&gt;cc-by-sa 2.5&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: xx-small;"&gt;My video is also protected by a Creative Commons license, namely &lt;a href="http://creativecommons.org/licenses/by-sa/3.0/"&gt;cc-by-sa 3.0&lt;/a&gt;.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4134023466945654159?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4134023466945654159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4134023466945654159' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4134023466945654159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4134023466945654159'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/12/new-trailer.html' title='New trailer'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2945375019288027017</id><published>2010-11-27T09:21:00.000-08:00</published><updated>2010-11-27T09:24:16.624-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>XNA GS 4.0 + F# 2.0 + Xbox 360 = love !</title><content type='html'>Those of you who read the &lt;a href="http://sharp-gamedev.blogspot.com/2010/11/xna-gs-40-f-20-xbox-360-no-love.html"&gt;previous entry&lt;/a&gt; could notice in the comments that it did not take long for Don Syme, the designer of F#, to offer to help resolve the issue.&lt;br /&gt;&lt;br /&gt;Less than a week later I had a new version of the FSharp core library tailored for the Xbox 360 in my mailbox. To the F# OSS team (Don Syme, Laurent Le Brun and Tomas Petricek): big thanks to all of you!&lt;br /&gt;&lt;br /&gt;What took a bit more time was to build a Visual Studio 2010 template for projects using the new F# core library. Thanks a lot to Dan Mohl for his help. He is the author of templates for F# + Silverlight + WP7 projects, which are available on the Visual Studio gallery.&lt;br /&gt;&lt;br /&gt;It's the first time I make a Visual Studio extension package, I hope I got it right. It's available on the &lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/e981f57c-c7e4-457c-a32b-38001a4dc860"&gt;Visual Studio gallery&lt;/a&gt;. If you try it out, please let me know if it worked for you (or if it did not).&lt;br /&gt;&lt;br /&gt;A small but important note: In the project properties, the build tab has "generate tail calls" &lt;b&gt;unchecked&lt;/b&gt;, both in Release and Debug builds. That's the way it is meant to be. If checked, your game will crash with an InvalidProgramException.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2945375019288027017?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2945375019288027017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2945375019288027017' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2945375019288027017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2945375019288027017'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/11/xna-gs-40-f-20-xbox-360-love.html' title='XNA GS 4.0 + F# 2.0 + Xbox 360 = love !'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5046001485865347912</id><published>2010-11-15T07:57:00.000-08:00</published><updated>2010-12-23T05:14:08.440-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>XNA GS 4.0 + F# 2.0 + Xbox 360 = no love (yet...)</title><content type='html'>I have good news and bad news.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Update&lt;/h2&gt;Actually, it's all good news, see &lt;a href="http://sharp-gamedev.blogspot.com/2010/11/xna-gs-40-f-20-xbox-360-love.html"&gt;the next post&lt;/a&gt;.&lt;br /&gt;I considered erasing this article, but finally decided against it, as it shows how fast and helpful the people behind F# are.&lt;br /&gt;&lt;br /&gt;So, just to clarify things: &lt;b&gt;It is possible to write games for the Xbox 360 in F# using Visual Studio 2010 and XNA Games Studio 4.0&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A word of caution: I don't want to give the impression that F# is officially supported by the XNA team at Microsoft. It isn't. As far as technical matters go, it works, and that's all I need as far as I'm concerned.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;End of update&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Good news first&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;1. I have posted Visual Studio templates, both for PC and the Xbox. I have only tested the Xbox one so far. Located on bitbucket, see &lt;a href="http://bitbucket.org/johdex/fsxnalibtemplate"&gt;http://bitbucket.org/johdex/fsxnalibtemplate&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. I have posted an example on how to use XNAUtils, it's included in the repository under "Samples". Hosted on &lt;a href="http://bitbucket.org/johdex/xnautils/wiki/Home"&gt;bitbucket&lt;/a&gt; too.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bad news&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;1. The templates are a bit rough around the edges still. Not so easy to install, in particular. I should probably upload them to the template repository so that they are accessible from with Visual Studio. However, I have other cats to whip at the moment, see below (I could have said bigger fish to fry ;)&lt;br /&gt;&lt;br /&gt;2. When you attempt to run the example, you will get an "InvalidProgramException", which I suppose means the IL code generated by the F# compiler cannot be handled by the new XNA framework. I had been using XNA GS 3.1 and F# 1.9.9.9 (dating from may 2010, I believe). I don't know where the problem lies, XNA GS 4.0 or F# 2.0.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;There is hope!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The source code for the F# compiler and the core library are now available on Codeplex. If the problem is indeed some hard-to-digest IL instruction, it should be fixable.&lt;br /&gt;&lt;br /&gt;(Small note: The source code for the F# compiler has been available for some time now, but building was not a walk in the park. Now there are instructions, and the result can be legally used and distributed).&lt;br /&gt;&lt;br /&gt;The next steps for me is to confirm my guesses, produce minimal reproduction cases, hope Microsoft will do something about it. That's quite a long shot though. As far as I know, there is no official support from Microsoft for languages other than C# in XNA.&lt;br /&gt;&lt;br /&gt;Anyway, I'll see if I can get to grips with the source code of compiler and the core library and solve these issues.&lt;br /&gt;&lt;br /&gt;By the way, I guess similar issues may exist on the Windows Phone 7 platform.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;In the mean time...&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;XNA and F# can be used together for the PC platform. Don't let this post scare you from trying F# + XNA.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5046001485865347912?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5046001485865347912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5046001485865347912' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5046001485865347912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5046001485865347912'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/11/xna-gs-40-f-20-xbox-360-no-love.html' title='XNA GS 4.0 + F# 2.0 + Xbox 360 = no love (yet...)'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5786685422203177157</id><published>2010-11-13T03:00:00.000-08:00</published><updated>2010-11-15T08:26:34.261-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>XNAUtils released under the Apache 2.0 license</title><content type='html'>I have just created a public repository on bitbucket containing various reusable F# modules that I developed for Asteroid Hunter.&lt;br /&gt;&lt;br /&gt;It's all there: &lt;a href="https://bitbucket.org/johdex/xnautils/"&gt;https://bitbucket.org/johdex/xnautils/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I had a quick look over the code, it's all pretty clean and short, but it lacks documentation and examples on how to use it.&lt;br /&gt;&lt;br /&gt;I ported the code and project files to XNA 4.0 and F# 2.0, but I have not tested the binaries. Chances are, they do not work yet.&lt;br /&gt;&lt;br /&gt;Nevertheless, I hope it will be useful to others out here, and help more Xbox games to be written in F#.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE (Nov 25):&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Asteroid Hunter was written for XNA Game Studio 3.1 using F# 1.9.9.9 (from may 2010). As I describe it in further details in the &lt;a href="http://sharp-gamedev.blogspot.com/2010/11/xna-gs-40-f-20-xbox-360-no-love.html"&gt;next post&lt;/a&gt;, the latest versions of XNA Game Studio and F# are not compatible.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5786685422203177157?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5786685422203177157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5786685422203177157' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5786685422203177157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5786685422203177157'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/11/xnautils-released-under-apache-20.html' title='XNAUtils released under the Apache 2.0 license'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-1648753676095411155</id><published>2010-11-12T12:57:00.000-08:00</published><updated>2010-11-13T08:35:52.430-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>Asteroid Hunter box art</title><content type='html'>I'm working on Asteroid Hunter at a very steady pace: Every week, I do half of all the work that's left to do.&lt;br /&gt;&lt;br /&gt;At this point, I had just enough motivation left to do the virtual box art which will appear on the Xbox marketplace when/if the game passes peer review.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_nDGpBaX7_xg/TN2prYPInRI/AAAAAAAAAj4/SLLccguYHKU/s1600/ah-boxart.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/_nDGpBaX7_xg/TN2prYPInRI/AAAAAAAAAj4/SLLccguYHKU/s320/ah-boxart.jpg" width="266" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Realized with Wings 3D, POVRAY and GIMP 2.&lt;br /&gt;&lt;br /&gt;By the way, I have now submitted the game to peer review. If you are a member of the XNA Creator's Club, please consider reviewing the game. You are more than welcome to fail it if you find something wrong :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-1648753676095411155?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/1648753676095411155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=1648753676095411155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1648753676095411155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1648753676095411155'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/11/asteroid-hunter-box-art.html' title='Asteroid Hunter box art'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nDGpBaX7_xg/TN2prYPInRI/AAAAAAAAAj4/SLLccguYHKU/s72-c/ah-boxart.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8343151729108248017</id><published>2010-10-01T02:10:00.000-07:00</published><updated>2010-11-12T12:58:46.999-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Final development stages of Asteroid Hunter</title><content type='html'>Things are a bit slow on the XNA development front on my side these days. I have stopped adding features to Asteroid Hunter, and am now in the process of getting the last feedback from testers before submitting the game to peer review. There are also a couple of art pieces that aren't ready yet, such as the box art and the introduction screen.&lt;br /&gt;&lt;br /&gt;I thought I would post a couple screen shots from the game running on Xbox.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_nDGpBaX7_xg/TKWgorxMO0I/AAAAAAAAAjo/bA-bzyGU4w0/s1600/AsteroidHunter+2010-09-19-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="179" src="http://2.bp.blogspot.com/_nDGpBaX7_xg/TKWgorxMO0I/AAAAAAAAAjo/bA-bzyGU4w0/s320/AsteroidHunter+2010-09-19-1.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This first screenshot shows off an asteroid from short range, with Jupiter in the background. Professional and amateur astronomers might notice that the stars in the view don't match any known part the galaxy. Those were made by myself, using random noise and this &lt;a href="http://www.gimpusers.com/tutorials/starfield-tutorial.html"&gt;tutorial&lt;/a&gt;. The asteroid model was made by an artist I am working with. I'm very happy with the looks, much better than anything I could have made.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_nDGpBaX7_xg/TKWgp5VwhUI/AAAAAAAAAjs/d6L1yz9oEF8/s1600/AsteroidHunter+2010-09-19-2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="179" src="http://1.bp.blogspot.com/_nDGpBaX7_xg/TKWgp5VwhUI/AAAAAAAAAjs/d6L1yz9oEF8/s320/AsteroidHunter+2010-09-19-2.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The goal of the game is pretty simple: shoot a number of asteroids, then move on to the next level. Repeat until your ship is destroyed in a collision with an asteroid or other nasty stuff that hides in asteroid fields.&lt;br /&gt;Not all asteroids are destructible, which forces the player to look for those that can be destroyed. As nothing looks more like an asteroid than another asteroid, spotting destructible asteroids can be challenging (or boringly difficult, according to testers).&lt;br /&gt;To counter this problem, I added a scanner to the game. When activated, destructible asteroids are visible in shiny green color, other asteroids are darker. The image above illustrates this.&lt;br /&gt;Notice also the radar in the lower right. It provides another way to track destructible asteroids.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_nDGpBaX7_xg/TKWgtmMLkQI/AAAAAAAAAjw/T4Pk0DZJol4/s1600/AsteroidHunter+2010-09-19-3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="179" src="http://4.bp.blogspot.com/_nDGpBaX7_xg/TKWgtmMLkQI/AAAAAAAAAjw/T4Pk0DZJol4/s320/AsteroidHunter+2010-09-19-3.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The image above shows some of the nasty stuff that hides in asteroid fields that I mentioned earlier. A missile is flying towards the player's ship. To help spot missiles (spotting small things in space is a task many find difficult, it seems), a square-shaped marker is drawn around them.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_nDGpBaX7_xg/TKWgu7Eqy5I/AAAAAAAAAj0/uQtIRiyqjM4/s1600/AsteroidHunter+2010-09-19-4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="179" src="http://3.bp.blogspot.com/_nDGpBaX7_xg/TKWgu7Eqy5I/AAAAAAAAAj0/uQtIRiyqjM4/s320/AsteroidHunter+2010-09-19-4.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This last image is self-explanatory. What it doesn't show is static and motion blur effects. I found those cool and easy to implement, but not very practical to have during while playing. I think they fit pretty well in the game over screen.&lt;br /&gt;&lt;br /&gt;The game also features local multiplayer on splitscreen, in coop mode or deathmatch.&lt;br /&gt;I hope to make it available on the Xbox Live Indie Games section for 80 MS points before the end of the year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8343151729108248017?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8343151729108248017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8343151729108248017' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8343151729108248017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8343151729108248017'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/10/final-development-stages-of-asteroid.html' title='Final development stages of Asteroid Hunter'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nDGpBaX7_xg/TKWgorxMO0I/AAAAAAAAAjo/bA-bzyGU4w0/s72-c/AsteroidHunter+2010-09-19-1.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4589488416071639672</id><published>2010-06-06T01:26:00.000-07:00</published><updated>2010-06-06T02:03:14.343-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>How to  build an F# library for the Xbox 360 using msbuild</title><content type='html'>In &lt;a href="http://sharp-gamedev.blogspot.com/2009/12/using-f-libraries-in-xna-games-for-xbox.html"&gt;earlier post&lt;/a&gt; I described the difficulties of building F# libraries that will run on the Xbox 360.&lt;br /&gt;I have been thinking all along that this was a bug in the integration of F# in Visual Studio, but I realized yesterday that it may be otherwise. Out of curiosity, I investigated how customization of msbuild works.&lt;br /&gt;If you create a C# XNA project and open the csproj file, you should see these lines at the end:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;&amp;lt;Import Project=&amp;quot;$(MSBuildBinPath)\Microsoft.CSharp.targets&amp;quot; /&amp;gt;&lt;br /&gt;  &amp;lt;Import Project=&amp;quot;$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.targets&amp;quot; /&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;If you go ahead and open Microsoft.Xna.GameStudio.Common.targets (located in C:\Program Files\MSBuild\Microsoft\Xna Game Studio\v3.1\), you will find some code dedicated to resolving assembly references:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;&amp;lt;!--&lt;br /&gt;        The SearchPaths property is set to find assemblies in the following order:&lt;br /&gt;&lt;br /&gt;            (1) Files from current project - indicated by {CandidateAssemblyFiles}&lt;br /&gt;            (2) $(ReferencePath) - the reference path property, which comes from the .USER file.&lt;br /&gt;            (3) The hintpath from the referenced item itself, indicated by {HintPathFromItem}.&lt;br /&gt;            (4) The directory of MSBuild's &amp;quot;target&amp;quot; runtime from GetFrameworkPath.&lt;br /&gt;                The &amp;quot;target&amp;quot; runtime folder is the folder of the runtime that MSBuild is a part of.&lt;br /&gt;            (5) Registered assembly folders, indicated by {Registry:*,*,*}&lt;br /&gt;            (6) Legacy registered assembly folders, indicated by {AssemblyFolders}&lt;br /&gt;            (7) Look in the application's output folder (like bin\debug)&lt;br /&gt;            (8) Resolve to the GAC.&lt;br /&gt;            (9) Treat the reference's Include as if it were a real file name.&lt;br /&gt;        --&amp;gt;&lt;br /&gt;    &amp;lt;AssemblySearchPaths Condition=&amp;quot; '$(XnaPlatform)' != 'Windows' &amp;quot;&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I don't quite understand exactly what happens in these targets files, but it seems the XNA dev team had to do some magic to have assembly resolution work.&lt;br /&gt;From there, I got the idea to import the XNA targets files in an F# project and see if it works. I tried that, mixing a C# XNA library project file with an F# library project. Guess what? It worked!&lt;br /&gt;&lt;br /&gt;To summarize, here are the steps to build and F# XNA library project:&lt;br /&gt;1. Make a copy of your F# library project, naming it "Xbox 360 Copy of my project.fsproj"&lt;br /&gt;2. Find the section which sets the default platform, change it from AnyCPU to Xbox 360:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;&amp;lt;Configuration Condition=&amp;quot; '$(Configuration)' == '' &amp;quot;&amp;gt;Debug&amp;lt;/Configuration&amp;gt;&lt;br /&gt;-    &amp;lt;Platform Condition=&amp;quot; '$(Platform)' == '' &amp;quot;&amp;gt;AnyCPU&amp;lt;/Platform&amp;gt;&lt;br /&gt;+    &amp;lt;Platform Condition=&amp;quot; '$(Platform)' == '' &amp;quot;&amp;gt;Xbox 360&amp;lt;/Platform&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;3. Under the target framework version, add some specific XNA properties:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;&amp;lt;TargetFrameworkVersion&amp;gt;v3.5&amp;lt;/TargetFrameworkVersion&amp;gt;&lt;br /&gt;+    &amp;lt;XnaFrameworkVersion&amp;gt;v3.1&amp;lt;/XnaFrameworkVersion&amp;gt;&lt;br /&gt;+    &amp;lt;XnaPlatform&amp;gt;Xbox 360&amp;lt;/XnaPlatform&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;4. Find the two sections controlling the project settings depending on the configuration and platform. Change AnyCPU to Xbox 360, change the output directory, add some constants:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;-  &amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' &amp;quot;&amp;gt;&lt;br /&gt;+  &amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|Xbox 360' &amp;quot;&amp;gt;&lt;br /&gt;     &amp;lt;DebugSymbols&amp;gt;true&amp;lt;/DebugSymbols&amp;gt;&lt;br /&gt;     &amp;lt;DebugType&amp;gt;full&amp;lt;/DebugType&amp;gt;&lt;br /&gt;     &amp;lt;Optimize&amp;gt;false&amp;lt;/Optimize&amp;gt;&lt;br /&gt;     &amp;lt;Tailcalls&amp;gt;false&amp;lt;/Tailcalls&amp;gt;&lt;br /&gt;     &amp;lt;OutputPath&amp;gt;bin\Debug\&amp;lt;/OutputPath&amp;gt;&lt;br /&gt;-    &amp;lt;DefineConstants&amp;gt;DEBUG;TRACE&amp;lt;/DefineConstants&amp;gt;&lt;br /&gt;+    &amp;lt;DefineConstants&amp;gt;DEBUG;TRACE;XBOX;XBOX360&amp;lt;/DefineConstants&amp;gt;&lt;br /&gt;     &amp;lt;WarningLevel&amp;gt;3&amp;lt;/WarningLevel&amp;gt;&lt;br /&gt;   &amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;-  &amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Release|AnyCPU' &amp;quot;&amp;gt;&lt;br /&gt;+  &amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Release|Xbox 360' &amp;quot;&amp;gt;&lt;br /&gt;     &amp;lt;DebugType&amp;gt;pdbonly&amp;lt;/DebugType&amp;gt;&lt;br /&gt;     &amp;lt;Optimize&amp;gt;true&amp;lt;/Optimize&amp;gt;&lt;br /&gt;     &amp;lt;Tailcalls&amp;gt;true&amp;lt;/Tailcalls&amp;gt;&lt;br /&gt;-    &amp;lt;OutputPath&amp;gt;bin\Release\&amp;lt;/OutputPath&amp;gt;&lt;br /&gt;-    &amp;lt;DefineConstants&amp;gt;TRACE&amp;lt;/DefineConstants&amp;gt;&lt;br /&gt;+    &amp;lt;OutputPath&amp;gt;bin\Xbox 360\Release\&amp;lt;/OutputPath&amp;gt;&lt;br /&gt;+    &amp;lt;DefineConstants&amp;gt;TRACE;XBOX;XBOX360&amp;lt;/DefineConstants&amp;gt;&lt;br /&gt;     &amp;lt;WarningLevel&amp;gt;3&amp;lt;/WarningLevel&amp;gt;&lt;br /&gt;   &amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;5. Remove the sections dedicated to the x86 platform.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;-  &amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|x86' &amp;quot;&amp;gt;&lt;br /&gt;-    &amp;lt;DebugSymbols&amp;gt;true&amp;lt;/DebugSymbols&amp;gt;&lt;br /&gt;-    &amp;lt;DebugType&amp;gt;full&amp;lt;/DebugType&amp;gt;&lt;br /&gt;-    &amp;lt;Optimize&amp;gt;false&amp;lt;/Optimize&amp;gt;&lt;br /&gt;-    &amp;lt;Tailcalls&amp;gt;false&amp;lt;/Tailcalls&amp;gt;&lt;br /&gt;-    &amp;lt;OutputPath&amp;gt;bin\Debug\&amp;lt;/OutputPath&amp;gt;&lt;br /&gt;-    &amp;lt;DefineConstants&amp;gt;DEBUG;TRACE&amp;lt;/DefineConstants&amp;gt;&lt;br /&gt;-    &amp;lt;WarningLevel&amp;gt;3&amp;lt;/WarningLevel&amp;gt;&lt;br /&gt;-    &amp;lt;PlatformTarget&amp;gt;x86&amp;lt;/PlatformTarget&amp;gt;&lt;br /&gt;-  &amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;-  &amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Release|x86' &amp;quot;&amp;gt;&lt;br /&gt;-    &amp;lt;DebugType&amp;gt;pdbonly&amp;lt;/DebugType&amp;gt;&lt;br /&gt;-    &amp;lt;Optimize&amp;gt;true&amp;lt;/Optimize&amp;gt;&lt;br /&gt;-    &amp;lt;Tailcalls&amp;gt;true&amp;lt;/Tailcalls&amp;gt;&lt;br /&gt;-    &amp;lt;OutputPath&amp;gt;bin\Release\&amp;lt;/OutputPath&amp;gt;&lt;br /&gt;-    &amp;lt;DefineConstants&amp;gt;TRACE&amp;lt;/DefineConstants&amp;gt;&lt;br /&gt;-    &amp;lt;WarningLevel&amp;gt;3&amp;lt;/WarningLevel&amp;gt;&lt;br /&gt;-    &amp;lt;PlatformTarget&amp;gt;x86&amp;lt;/PlatformTarget&amp;gt;&lt;br /&gt;-  &amp;lt;/PropertyGroup&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;6. Add some XNA-specific stuff (no idea what it does, not sure if it's needed):&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;+  &amp;lt;ItemGroup&amp;gt;&lt;br /&gt;+    &amp;lt;BootstrapperPackage Include=&amp;quot;Microsoft.Net.Framework.2.0&amp;quot;&amp;gt;&lt;br /&gt;+      &amp;lt;Visible&amp;gt;False&amp;lt;/Visible&amp;gt;&lt;br /&gt;+      &amp;lt;ProductName&amp;gt;.NET Framework 2.0 %28x86%29&amp;lt;/ProductName&amp;gt;&lt;br /&gt;+      &amp;lt;Install&amp;gt;false&amp;lt;/Install&amp;gt;&lt;br /&gt;+    &amp;lt;/BootstrapperPackage&amp;gt;&lt;br /&gt;+    &amp;lt;BootstrapperPackage Include=&amp;quot;Microsoft.Net.Framework.3.0&amp;quot;&amp;gt;&lt;br /&gt;+      &amp;lt;Visible&amp;gt;False&amp;lt;/Visible&amp;gt;&lt;br /&gt;+      &amp;lt;ProductName&amp;gt;.NET Framework 3.0 %28x86%29&amp;lt;/ProductName&amp;gt;&lt;br /&gt;+      &amp;lt;Install&amp;gt;false&amp;lt;/Install&amp;gt;&lt;br /&gt;+    &amp;lt;/BootstrapperPackage&amp;gt;&lt;br /&gt;+    &amp;lt;BootstrapperPackage Include=&amp;quot;Microsoft.Net.Framework.3.5&amp;quot;&amp;gt;&lt;br /&gt;+      &amp;lt;Visible&amp;gt;False&amp;lt;/Visible&amp;gt;&lt;br /&gt;+      &amp;lt;ProductName&amp;gt;.NET Framework 3.5&amp;lt;/ProductName&amp;gt;&lt;br /&gt;+      &amp;lt;Install&amp;gt;true&amp;lt;/Install&amp;gt;&lt;br /&gt;+    &amp;lt;/BootstrapperPackage&amp;gt;&lt;br /&gt;+    &amp;lt;BootstrapperPackage Include=&amp;quot;Microsoft.Windows.Installer.3.1&amp;quot;&amp;gt;&lt;br /&gt;+      &amp;lt;Visible&amp;gt;False&amp;lt;/Visible&amp;gt;&lt;br /&gt;+      &amp;lt;ProductName&amp;gt;Windows Installer 3.1&amp;lt;/ProductName&amp;gt;&lt;br /&gt;+      &amp;lt;Install&amp;gt;true&amp;lt;/Install&amp;gt;&lt;br /&gt;+    &amp;lt;/BootstrapperPackage&amp;gt;&lt;br /&gt;+    &amp;lt;BootstrapperPackage Include=&amp;quot;Microsoft.Xna.Framework.3.1&amp;quot;&amp;gt;&lt;br /&gt;+      &amp;lt;Visible&amp;gt;False&amp;lt;/Visible&amp;gt;&lt;br /&gt;+      &amp;lt;ProductName&amp;gt;Microsoft XNA Framework Redistributable 3.1&amp;lt;/ProductName&amp;gt;&lt;br /&gt;+      &amp;lt;Install&amp;gt;true&amp;lt;/Install&amp;gt;&lt;br /&gt;+    &amp;lt;/BootstrapperPackage&amp;gt;&lt;br /&gt;+  &amp;lt;/ItemGroup&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;7. Fix references:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;&amp;lt;ItemGroup&amp;gt;&lt;br /&gt;     &amp;lt;Reference Include=&amp;quot;Microsoft.Xna.Framework&amp;quot;&amp;gt;&lt;br /&gt;-      &amp;lt;HintPath&amp;gt;..\..\..\..\..\..\..\..\..\Program Files\Microsoft XNA\XNA Game Studio\v3.1\References\Windows\x86\Microsoft.Xna.Framework.dll&amp;lt;/HintPath&amp;gt;&lt;br /&gt;+      &amp;lt;Private&amp;gt;False&amp;lt;/Private&amp;gt;&lt;br /&gt;     &amp;lt;/Reference&amp;gt;&lt;br /&gt;     &amp;lt;Reference Include=&amp;quot;Microsoft.Xna.Framework.Game&amp;quot;&amp;gt;&lt;br /&gt;-      &amp;lt;HintPath&amp;gt;..\..\..\..\..\..\..\..\..\Program Files\Microsoft XNA\XNA Game Studio\v3.1\References\Windows\x86\Microsoft.Xna.Framework.Game.dll&amp;lt;/HintPath&amp;gt;&lt;br /&gt;+      &amp;lt;Private&amp;gt;False&amp;lt;/Private&amp;gt;&lt;br /&gt;     &amp;lt;/Reference&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;8. Insert the C# and XNA target files, &lt;span style="font-weight:bold;"&gt;before &lt;/span&gt;the F# targets file:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;+  &amp;lt;Import Project=&amp;quot;$(MSBuildBinPath)\Microsoft.CSharp.targets&amp;quot; /&amp;gt;&lt;br /&gt;+  &amp;lt;Import Project=&amp;quot;$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.targets&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;Import Project=&amp;quot;$(MSBuildExtensionsPath32)\FSharp\1.0\Microsoft.FSharp.Targets&amp;quot; /&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;You are almost there. You now have a project file you can open in Visual Studio. From there, you can add a reference to the correct FSharp.Core assembly (the one for .Net CF 2.0)&lt;br /&gt;&lt;br /&gt;That should be it. There are a few more things that need to be fixed, such as project GUIDs, but Visual Studio will happily do that for you, all you have to do is open the fsproj file with Visual Studio.&lt;br /&gt;&lt;br /&gt;When building, remember to choose "Xbox 360" as the platform in the build settings.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4589488416071639672?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4589488416071639672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4589488416071639672' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4589488416071639672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4589488416071639672'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/06/how-to-build-f-library-for-xbox-360.html' title='How to  build an F# library for the Xbox 360 using msbuild'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4363388291949203901</id><published>2010-05-15T00:16:00.000-07:00</published><updated>2010-11-28T04:52:10.303-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='storage'/><title type='text'>Discriminated unions: a powerful tool for implenting state machines</title><content type='html'>When writing a game using XNA Game Studio, the programmer quickly faces the problem of dealing with persistent data. Typically, a game will need files to store high-scores, game progress, user settings...&lt;br /&gt;On the PC platform, the programmer has two ways of dealing with file I/O: synchronously, which is OK for dealing with small amounts of data, or asynchronously, which is used to avoid leaving the user with an unresponsive application when large files (or large numbers of small files) are read or written.&lt;br /&gt;On the Xbox, the only available option is the asynchronous one. Another odd side of XNA on the Xbox is the fact that programmers cannot decide on which storage device files should be located. If the Xbox on which the game is running has memory cards plugged in, the user must be asked which device (hard disk or memory card) he/she wishes to use.&lt;br /&gt;In other words, performing I/O on the Xbox requires to go through several steps, and all these steps must be spread out over multiple iterations of the game update loop.&lt;br /&gt;&lt;br /&gt;This is one of these situations where state machines are very handy. Considering the file I/O example mentioned above, I have designed a state machine with the following states:&lt;br /&gt;&lt;br /&gt;- Ready&lt;br /&gt;- Start requesting user storage&lt;br /&gt;- Requesting user storage&lt;br /&gt;- Start sign in&lt;br /&gt;- Signing in&lt;br /&gt;- Start requesting global storage&lt;br /&gt;- Requesting global storage&lt;br /&gt;- Doing I/O&lt;br /&gt;- Failed I/O&lt;br /&gt;- Successful I/O&lt;br /&gt;&lt;br /&gt;User storage is used to store user-specific files, e.g. user preferences. Global storage is used for scores.&lt;br /&gt;Some of these states have specific data. For instance, requesting user storage requires an user id.&lt;br /&gt;&lt;br /&gt;In C#, state machines can be a bit cumbersome to implement. Typically, one would use an object containing an enum for the state, and all fields needed for each state.&lt;br /&gt;This last part annoys me a bit, as it hides the relation between states and their data. With time, it's easy to lose track of this connection.&lt;br /&gt;&lt;br /&gt;In F#, I see two ways of implementing state machines. The more elaborate way uses a custom workflow and an algorithmic representation of the state machine. Actually, presenting workflows as an implementation technique for state machines is a bit clumsy, as it's really the other way around. I'll stop here for now with custom workflows, more on this subject in a later post.&lt;br /&gt;The simpler way for someone who is not too familiar with functional languages and monads consists of using a discriminated union.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type State =&lt;br /&gt;| StartReqTitleStorage&lt;br /&gt;| RequestingTitleStorage&lt;br /&gt;| StartSignIn of PlayerIndex&lt;br /&gt;| SigningIn of PlayerIndex&lt;br /&gt;| NotSignedInInfo&lt;br /&gt;| StartReqUserStorage of PlayerIndex&lt;br /&gt;| RequestingUserStorage&lt;br /&gt;| DoingIO&lt;br /&gt;| FailedIO of (unit -&gt; unit)&lt;br /&gt;| SuccessfulIO of (unit -&gt; unit)&lt;br /&gt;| Ready&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then comes the data type for the storage component.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type Data =&lt;br /&gt;{ state : State&lt;br /&gt;titleStorage : StorageDevice option&lt;br /&gt;userStorage : StorageDevice option }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As an example of a non-trivial operation, here is the code to request user-specific storage.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let requestUserStorage (p : PlayerIndex) data =&lt;br /&gt;match data.state with&lt;br /&gt;| Ready when Gamer.SignedInGamers.[p] = null -&gt; { data with state = StartReqUserStorage(p) }&lt;br /&gt;| Ready                                      -&gt; { data with state = StartSignIn(p) }&lt;br /&gt;| _     -&gt; raise (new InvalidOperationException())&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I particularly like the way pattern matching and the "when clause" combine nicely to express the fact that a user must be signed in before user-specific storage can be requested.&lt;br /&gt;Note also how the programmer is forced to handle the erroneous case of calling requestUserStorage when the storage component is not ready.&lt;br /&gt;&lt;br /&gt;This style of implementation using immutable data and functions would not feel very C#-ish for someone using this code from C#. This is easily solved by wrapping all the code in a class:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type StorageComponent(game) =&lt;br /&gt;inherit GameComponent(game)&lt;br /&gt;&lt;br /&gt;let data = ref { state = Ready ; titleStorage = None ; userStorage = None }&lt;br /&gt;&lt;br /&gt;let getDoSet f =&lt;br /&gt;data := f !data&lt;br /&gt;&lt;br /&gt;member x.RequestUserStorage(p : PlayerIndex) =&lt;br /&gt;getDoSet (requestUserStorage p)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For the curious, getDoSet is a helper function I introduced to hide some locking mechanism. The implementation shown here is not the one I actually use. I left it here just because I love to pass functions around ;)&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://bitbucket.org/johdex/xnautils/src/a58b18326f5d/XNAUtils/StorageComponent.fs"&gt;full code&lt;/a&gt; is available on bitbucket, as a part of &lt;a href="http://bitbucket.org/johdex/xnautils/wiki/Home"&gt;XNAUtils&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4363388291949203901?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4363388291949203901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4363388291949203901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4363388291949203901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4363388291949203901'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/05/discriminated-unions-powerful-tool-for.html' title='Discriminated unions: a powerful tool for implenting state machines'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-423441419286734287</id><published>2010-03-26T14:06:00.000-07:00</published><updated>2010-03-26T14:45:20.587-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Things that don't work on Xbox</title><content type='html'>Although it is possible to write F# code that runs on the Xbox 360 using XNA Game Studio, not everything works.&lt;br /&gt;&lt;br /&gt;There are API problems, probably due to the fact that the F# core assembly I am using is built for the compact framework. Although the .NET framework on the Xbox 360 is based on the compact framework, there are obviously significant differences.&lt;br /&gt;I hope I will be able to take a look at this when Microsoft releases the source code of the F# code library in an easily compilable form (the F# team has said that they intended to release the F# compiler and libraries under an Open Source license when it reaches a stable state).&lt;br /&gt;&lt;br /&gt;For instance a call to sprintf (for debugging purposes) resulted in an exception, due to a missing method, it seems.&lt;br /&gt;&lt;br /&gt;Similarly, attempts to use async workflows also fail. This is really a shame, as it means you are on your own when it comes to concurrent applications. For instance, the map_parallel function I used in &lt;a href="http://sharp-gamedev.blogspot.com/2008/09/tutorial-7-concurrency.html"&gt;tutorial 7&lt;/a&gt; raises an exception.&lt;br /&gt;&lt;br /&gt;In addition to binary compatibility issues specific to F#, there are also generic practical issues.&lt;br /&gt;&lt;br /&gt;After implementing my own version of Async.Parallel, I realized it probably would not be much help, as the overhead of multi-threading is a bit too much for the time intervals of computations which must run in a 60th of a second (16.7 ms). Using parallel_map resulted in a factor two performance drop, in my case. For those interested, here is the code I was using (no guarantee of correctness of any kind!):&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;let map_parallel (func : 'T0 -&gt; 'T1) (data : 'T0[]) : 'T1[] =&lt;br /&gt;    let results = Array.zeroCreate data.Length&lt;br /&gt;    let num_threads = 4&lt;br /&gt;    let ranges = Array.init num_threads (fun i -&gt; i * data.Length / num_threads, (i + 1) * data.Length / num_threads - 1)&lt;br /&gt;&lt;br /&gt;    let count = ref num_threads&lt;br /&gt;    let notify = new System.Threading.AutoResetEvent(false)&lt;br /&gt;    &lt;br /&gt;    for (start, stop) in ranges do&lt;br /&gt;        System.Threading.ThreadPool.QueueUserWorkItem (&lt;br /&gt;            fun _ -&gt;&lt;br /&gt;                try&lt;br /&gt;                    for i in start..stop do&lt;br /&gt;                        results.[i] &lt;- func data.[i]&lt;br /&gt;                finally&lt;br /&gt;                    let n = System.Threading.Interlocked.Decrement count&lt;br /&gt;                    if n = 0 then&lt;br /&gt;                        System.Threading.Thread.MemoryBarrier()&lt;br /&gt;                        notify.Set() |&gt; ignore&lt;br /&gt;        )&lt;br /&gt;        |&gt; ignore&lt;br /&gt;    &lt;br /&gt;    notify.WaitOne() |&gt; ignore&lt;br /&gt;    results&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What works well is to dispatch rendering and updating on two threads. The rendering thread must remain on the "main" thread, the updating thread can run on a separate thread.&lt;br /&gt;&lt;br /&gt;Is F# worth the trouble on Xbox? I would say it is. Compared to C#, the language has good support for manipulating arrays, an "inline" keyword that comes very handy when writing generic code that must run fast. This makes it a good language for computation-heavy applications (of which simulation-oriented games are).&lt;br /&gt;&lt;br /&gt;Another area where the language should shine is in high-level UI code. I have thoughts about using custom workflows to conveniently map operations spanning over multiple frames on the game update loop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-423441419286734287?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/423441419286734287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=423441419286734287' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/423441419286734287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/423441419286734287'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/03/things-that-dont-work-on-xbox.html' title='Things that don&apos;t work on Xbox'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6106014038532927583</id><published>2010-03-04T10:40:00.000-08:00</published><updated>2010-03-26T14:05:09.174-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xbox'/><title type='text'>Array-oriented programming</title><content type='html'>I have been working for quite some time now on Asteroid Hunter. This has not left me much time for exploration and experimentation with F#, but there is quite a bit a learned during the process anyway.&lt;br /&gt;&lt;br /&gt;One of the biggest technical challenges of developing games for the Xbox platform using XNA Game Studio is probably how to keep garbage collection from eating too much performance.&lt;br /&gt;&lt;br /&gt;The classical way which I think all developers are using is to preallocate your objects, and recycle them during gameplay. As a complement, one can also use structs instead of classes, as structs do not require garbage collection. The goal here is to never allocate new space, as every megabyte allocated triggers a new garbage collection. Depending on the number of objects the heap contains, a garbage collection can take from a few milliseconds to fractions of seconds, the latter being unacceptable for a game refreshing the screen 60 times per second.&lt;br /&gt;&lt;br /&gt;There is another way, and I know no one who uses it. In this approach, it's ok to allocate a lot of memory space, as long as it's used by few objects. In other words, an array of value types, such as floats or structs, is cheap to allocate.&lt;br /&gt;&lt;br /&gt;In a first version of the game, I used records to model asteroids, and stored these records in immutable arrays. This approach quickly showed its limits. I modified the code to use arrays of structs, also immutable. It was better, but this method incurred very high copying costs, as changing one field, for instance the position, required to copy the entire struct (composed of a couple more vectors for the speed, orientation, angular velocity...).&lt;br /&gt;&lt;br /&gt;In the current version, I no longer have a datatype representing a single asteroid. Instead, I use multiple arrays of vectors, one array for the positions, one array for the speeds, etc. I rely heavily on higher order functions in the Array module, such as Array.map, Array.map2 and Array.mapi.&lt;br /&gt;&lt;br /&gt;The code below illustrates the kind of programming style I am describing above. Take it with a nip of salt, it was written in quite a rush, and the Dream Build Play deadline left me little (as in "none at all") time for code cleanup.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;type AsteroidArrays =&lt;br /&gt;    { pos : Vector3[] ;&lt;br /&gt;      speed : Vector3[] ;&lt;br /&gt;      wspeed : Vector3[] ;&lt;br /&gt;      wpos : Quaternion[] ;&lt;br /&gt;      bsph : BoundingSphere[] ;&lt;br /&gt;      heat_level : float32[] ;&lt;br /&gt;      mass : float32[] ;&lt;br /&gt;      radius : float32[] ;&lt;br /&gt;      rank : int[] ;        // -1 means dead.&lt;br /&gt;      heat_rate : float32[] ;&lt;br /&gt;      color : Vector3[] }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let integrate (V : Vector3) (dt : float32) (impulses : Pair&lt;int, Vector3 &gt; list) (arr : AsteroidArrays) =&lt;br /&gt;    let speed = Array.copy arr.speed&lt;br /&gt;    for impulse in impulses do&lt;br /&gt;        let idx = impulse.fst&lt;br /&gt;        let impulse = impulse.snd&lt;br /&gt;        speed.[idx] &lt;- speed.[idx] + impulse&lt;br /&gt;        &lt;br /&gt;    let pos =&lt;br /&gt;        Array.map2 (fun pos speed -&gt; pos + dt * speed |&gt; WarpCoord.warp V) arr.pos speed&lt;br /&gt;&lt;br /&gt;    let rot =&lt;br /&gt;        Array.map (fun wspeed -&gt; new Quaternion(dt * wspeed, 0.0f)) arr.wspeed&lt;br /&gt;&lt;br /&gt;    let wpos =&lt;br /&gt;        Array.map2 (fun wpos rot -&gt;&lt;br /&gt;                let x = wpos + Quaternion.Multiply(rot * wpos, 0.5f)&lt;br /&gt;                x.Normalize()&lt;br /&gt;                x)&lt;br /&gt;            arr.wpos&lt;br /&gt;            rot&lt;br /&gt;&lt;br /&gt;    let bsph =&lt;br /&gt;        Array.map2 (fun pos radius -&gt; new BoundingSphere(pos, radius)) arr.pos arr.radius&lt;br /&gt;                    &lt;br /&gt;    { arr with&lt;br /&gt;        pos = pos ;&lt;br /&gt;        speed = speed ;&lt;br /&gt;        wpos = wpos ;&lt;br /&gt;        bsph = bsph }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When I dived into redesigning my asteroids from arrays of structs to a record of arrays, I was nervous I would never make it in time. When all you have is four days work, you don't want to spend two days on a redesign. Happily, it took less than four hours, which positively surprised me. The F# mode in Visual Studio may lack most of the refactoring tools available in C#, yet rewriting code goes a lot faster than I would have expected.&lt;br /&gt;&lt;br /&gt;This immutable approach does not perform too badly compared to the mutable way, as all values typically need to be touched anyway. I haven't actually done any measurements, but I don't expect the immutable approach to be worse than twice as slow as in-place modifications.&lt;br /&gt;&lt;br /&gt;I don't know if memory fragmentation could be a problem. The arrays in question are small enough that they are allocated on the regular heap (as opposed to the large object heap), and the remote performance monitor reports zero compactions. Moreover, all my arrays have fixed sizes, which should keep fragmentation at bay.&lt;br /&gt;&lt;br /&gt;If you read some of my earlier posts in this blog, you might have guessed that I have my doubts about object-oriented programming. As far as performance-critical parts of the code are concerned, I am now convinced that one should stay away from objects, be it in the form of structs or classes. Whether one can get away with immutable arrays or not (as opposed to mutable arrays) probably depends on how much performance is needed.&lt;br /&gt;&lt;br /&gt;That will be all for now, I am planning to write about concurrency and generic space-partitioning in my next posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6106014038532927583?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6106014038532927583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6106014038532927583' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6106014038532927583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6106014038532927583'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/03/thoughts-about-f-and-xbox-games.html' title='Array-oriented programming'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5188976623015446954</id><published>2010-03-04T10:31:00.000-08:00</published><updated>2010-11-12T13:01:01.080-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>Asteroid Hunter submitted to Dream Build Play</title><content type='html'>Asteroid Hunter, the 3d variant of "Asteroids" written in F#, is participating in &lt;a href="http://www.dreambuildplay.com"&gt;Dream Build Play&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The game features 12 levels of increasing difficulty. In addition to the solo mode, you can also play against up to 3 of your friends on split screen.&lt;br /&gt;&lt;br /&gt;&lt;object width="640" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/RY2FycdRn2o&amp;hl=sv_SE&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/RY2FycdRn2o&amp;hl=sv_SE&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;I am hoping to publish the game on the XBox Live Indie Games channel later this spring.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5188976623015446954?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5188976623015446954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5188976623015446954' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5188976623015446954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5188976623015446954'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/03/asteroid-hunter-submitted-to-dream.html' title='Asteroid Hunter submitted to Dream Build Play'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-7873414041572302728</id><published>2010-01-04T12:07:00.000-08:00</published><updated>2010-11-12T13:01:26.148-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>Asteroid Hunter, 3rd play test</title><content type='html'>I've been busy with Asteroid Hunter during the Christmas break.&lt;br /&gt;&lt;br /&gt;The result is visible in this video:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/gn2MeqyiL3U&amp;hl=sv_SE&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/gn2MeqyiL3U&amp;hl=sv_SE&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;If you are a premium member of the XNA Creator's Club, feel free to play test the game and leave me your impressions &lt;a href="http://forums.xna.com/forums/t/38052.aspx"&gt;there&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The next version will also be available on PC to the general public.&lt;br /&gt;&lt;br /&gt;From the technical point of view, the nicest new feature is probably an AI capable of steering ships and missiles toward moving targets, avoiding asteroids in the process.&lt;br /&gt;&lt;br /&gt;The program also feels a bit more like an actual game now, with scores, explosions, levels of difficulty, powerups to pick up... There is obviously a lot of polishing left to do, though. I'm leaving that to the end.&lt;br /&gt;&lt;br /&gt;It was surprising how easy it was to pick up the coding where I left it this summer, even though I hardly touched the code this autumn.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-7873414041572302728?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/7873414041572302728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=7873414041572302728' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7873414041572302728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7873414041572302728'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2010/01/asteroid-hunter-3rd-play-test.html' title='Asteroid Hunter, 3rd play test'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-1594072516650711556</id><published>2009-12-13T08:58:00.000-08:00</published><updated>2009-12-13T11:25:39.186-08:00</updated><title type='text'>Inheritance nightmares</title><content type='html'>I was first exposed to object-oriented programming when learning C++. I am now starting to realize how confusing that has been. In particular, inheritance in C++ is often used and abused to implement various kinds of relationships between classes. I am writing "abused", because the only legitimate use of inheritance is for IS-A relationships. Other relationships such as HAS-A and IS-IMPLEMENTED-IN-TERMS-OF should not use inheritance. In these cases composition is preferable. It is therefore important to be able to differentiate between the different kinds of relationships.&lt;br /&gt;&lt;br /&gt;However understanding IS-A relationships is not as easy it might seem. To illustrate the problem, the case of squares and rectangles is sometimes used.&lt;br /&gt;&lt;br /&gt;All squares are also rectangles, and it seems natural that a class "Square" should be related to a class "Rectangle": Square IS-A Rectangle.&lt;br /&gt;&lt;br /&gt;In C#, this could be written:&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;class Rectangle&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Square : Rectangle&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now that we have our class hierarchy, let us start adding methods and fields:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;class Rectangle&lt;br /&gt;{&lt;br /&gt;    float length;&lt;br /&gt;    float width;&lt;br /&gt;&lt;br /&gt;    public Rectangle(float l, float w)&lt;br /&gt;    {&lt;br /&gt;        length = l;&lt;br /&gt;        width  = w;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public float GetLength() { return length; }&lt;br /&gt;    public float GetWidth()  { return width; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So far, no problem. Things get tricky when we want to add setter methods:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;class Rectangle&lt;br /&gt;{&lt;br /&gt;    float length;&lt;br /&gt;    float width;&lt;br /&gt;    ...&lt;br /&gt;    public void SetLength(float l) { length = l; }&lt;br /&gt;    public void SetWidth(float w)  { width  = w; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Square : Rectangle&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    public void SetSize(float s) { SetLength(s); SetWidth(s); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem is that Square inherits SetLength and SetWidth, which makes it possible to have squares with non-matching lengths and widths. A non-satisfactory solution consists of overriding SetLength and SetWidth in Square:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;class Rectangle&lt;br /&gt;{&lt;br /&gt;    float length;&lt;br /&gt;    float width;&lt;br /&gt;    ...&lt;br /&gt;    public virtual void SetLength(float l) { length = l; }&lt;br /&gt;    public virtual void SetWidth(float w)  { width  = w; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Square : Rectangle&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    public override void SetLength(float s) { base.SetLength(s); base.SetWidth(s); }&lt;br /&gt;    public override void SetWidth(float s)  { base.SetLength(s); base.SetWidth(s); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This solution is not satisfactory because users of Rectangle may expect that it should be possible to set widths and lengths independently.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;void SetWidthAndLength(Rectangle rect)&lt;br /&gt;{&lt;br /&gt;    rect.SetWidth(1.0);&lt;br /&gt;    rect.SetLength(2.0);&lt;br /&gt;    Debug.Assert(rect.GetWidth() == 1.0);&lt;br /&gt;    Debug.Assert(rect.GetLength() == 2.0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These assertions fail when SetWidthAndLength is passed an instance of Square. Many articles go on by stating that Rectangle and Square are in fact not IS-A related, although the initial intuition told otherwise. This is usually the point where the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov Substitution Principle&lt;/a&gt; is introduced. While understanding this principle is certainly a good thing for anyone learning about object-oriented programming, one of the biggest selling points of object-oriented design is that it is supposed to be intuitive.&lt;br /&gt;&lt;br /&gt;After all, all squares are rectangles, aren't they? Indeed, this is true of immutable squares and rectangles. Remove the setters, and all problems disappear. The substitution principle falls in line with what intuition tells us.&lt;br /&gt;&lt;br /&gt;Going a bit further, let us consider a function which transforms squares.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;Square TransformSquare(Square square, SquareScaling scale)&lt;br /&gt;{&lt;br /&gt;    float scaleFactor = ...;&lt;br /&gt;    return scale.Do(square, scaleFactor);&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we have at hand a library which provides translation and rotation operations on rectangles, we are very close to being able to use these with "Transform". All we need is to write a bit of code to turn rectangles which have identical lengths and widths into squares:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;class RectangleUniformScalingAdapter : SquareScaling&lt;br /&gt;{&lt;br /&gt;    RectangleUniformScaling adaptee;&lt;br /&gt;    ...&lt;br /&gt;    public override Square Do(Square square, float factor)&lt;br /&gt;    {&lt;br /&gt;        Rectangle tmp = adaptee.Do(square, factor, factor);&lt;br /&gt;        Debug.Assert(tmp.GetLength() == tmp.GetWidth());&lt;br /&gt;        return new Square(tmp.GetLength());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On the other hand, if we are provided a function working on rectangles, a library providing transformations on squares would not be very valuable.&lt;br /&gt;&lt;br /&gt;In other words, we could say that RectangleUniformScaling IS-(almost)-A SquareScaling. Note how the IS-A relationship is reversed.&lt;br /&gt;&lt;br /&gt;If different parts of the interfaces of Rectangle and Square do not agree on the direction of the relationship, we have a problem.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;class Rectangle&lt;br /&gt;{&lt;br /&gt;    float width;&lt;br /&gt;    float length;&lt;br /&gt;&lt;br /&gt;    public virtual float GetWidth() { /* Easy to implement */ }&lt;br /&gt;    // Uniform scaling&lt;br /&gt;    public virtual void Scale(float scale) { /* could use Square.Scale() */ }&lt;br /&gt;    public virtual void Scale(float scaleWidth, scaleLength) {...}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Square&lt;br /&gt;{&lt;br /&gt;    public virtual float GetWidth() {/* could use Rectangle.GetWidth() */ }&lt;br /&gt;    public virtual void Scale(float scale) { /* Easy to implement */ }&lt;br /&gt;    public virtual void Scale(float scaleWidth, scaleLength) { /* Impossible to implement */ }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Who should inherit from who?&lt;br /&gt;&lt;br /&gt;At this point, readers interested in F# and functional programming languages might wonder what all this has got to do with F#. I think that the common mix of mutability and inheritance is not a very strong basis for good software design. I never really realized that until I took a look at functional programming and immutability.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-1594072516650711556?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/1594072516650711556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=1594072516650711556' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1594072516650711556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/1594072516650711556'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/12/inheritance-nightmares.html' title='Inheritance nightmares'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3932160303391922207</id><published>2009-12-06T10:23:00.001-08:00</published><updated>2009-12-13T08:27:42.637-08:00</updated><title type='text'>A bit of F# in your C#</title><content type='html'>At work, I'm using way more C# than F#.&lt;br /&gt;&lt;br /&gt;I have however noticed that functional programming concepts from F# have found their way into my C# code. The first sign of this is when LINQ extension methods start appearing where foreach loops used to be.&lt;br /&gt;&lt;br /&gt;F# has a higher-order function called "fold" which can be used for collecting information from a sequence into a single object. A common use is for summing, but it can also be used for extracting one item from the sequence. For instance, it can be used for finding the minimal item according to a specific ordering.&lt;br /&gt;&lt;br /&gt;This is a problem Jon Skeet has tackled in a blog from 2005 entitled &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2005/10/02/a-short-case-study-in-linq-efficiency.aspx"&gt;A short case study in LINQ efficiency&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For instance, given a sequence of pairs of string*number denoting names and ages of people, find the youngest person. Note that we are not only interested in finding the age of the person, we want both the name and the age.&lt;br /&gt;&lt;br /&gt;Here is a solution in F# which uses "fold".&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;let people = [("me", 32.0); ("someoneelse", 75.0)];;&lt;br /&gt;let cmp a b =&lt;br /&gt;    match a, b with&lt;br /&gt;    | Some (_, a1), (_, a2) when a1 &amp;lt;= a2 -&amp;gt; a&lt;br /&gt;    | _ -&amp;gt; Some b;;&lt;br /&gt;&lt;br /&gt;let youngest = List.fold cmp None people;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Function "fold" iterates over each item in the list. For each item, it invokes a function to which it passes the item together with a value called the accumulator. The function returns the new value for the accumulator.&lt;br /&gt;&lt;br /&gt;In the example above, the type of the accumulator is "Some person or None", where "None" denotes "no one".&lt;br /&gt;&lt;br /&gt;Function cmp simply compares an accumulator with a person, and returns the person if the accumulator is "None", the youngest of the person and the accumulator otherwise.&lt;br /&gt;&lt;br /&gt;This solution, when translated to C# 4.0, gives an elegant and efficient solution. I wonder why Jon Skeet did not mention it. If he missed it, he's not alone, a search on Google for how to implement one's own LINQ extension method shows many articles using precisely this problem as illustration.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;var people = new Tuple&amp;lt;string, double&amp;gt;[] {&lt;br /&gt;    Tuple.Create("me", 32.0),&lt;br /&gt;    Tuple.Create("someoneelse", 75.0) };&lt;br /&gt;&lt;br /&gt;var youngest =&lt;br /&gt;    people.Aggregate(null as Tuple&amp;lt;string, double&amp;gt;,&lt;br /&gt;                     (youngestSoFar, v) =&amp;gt;&lt;br /&gt;                     (youngestSoFar != null &amp;&amp; youngestSoFar.Item2 &amp;lt;= v.Item2) ?&lt;br /&gt;                         youngestSoFar : v);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I haven't done any time measurements, but this solution should iterate over the array of people no more than once, and might even be just as efficient as the method using foreach.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3932160303391922207?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3932160303391922207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3932160303391922207' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3932160303391922207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3932160303391922207'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/12/bit-of-f-in-your-c.html' title='A bit of F# in your C#'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-7134090442308552841</id><published>2009-12-06T03:37:00.001-08:00</published><updated>2009-12-06T11:45:27.563-08:00</updated><title type='text'>F# on the Xbox 360</title><content type='html'>This article describes how to build an XNA Game Studio application using an F# library in such a way that it can be run on the Xbox 360. It applies to the current version of F#, 1.9.7.8&lt;br /&gt;&lt;br /&gt;A method was first described in &lt;a href="http://grammerjack.spaces.live.com/blog/cns!F2629C772A178A7C!158.entry"&gt;this blog&lt;/a&gt; by Jack Palevich. Most of his blog post still applies, except for step 2.&lt;br /&gt;&lt;br /&gt;In order for an .net assembly to be usable on the Xbox 360, it must be linked against dlls for the Xbox 360, which can be found in &amp;lt;Program Files directory&amp;gt;\Microsoft XNA\XNA Game Studio\v3.1\References\Xbox360.&lt;br /&gt;&lt;br /&gt;In particular, it must be linked against mscorlib.dll for the Xbox 360, which is the difficult part.&lt;br /&gt;&lt;br /&gt;By default, when you create an F# library in Visual Studio, it is linked against FSharp.Core.dll, which references mscorlib for the PC.&lt;br /&gt;&lt;br /&gt;In order to avoid conflicts between versions of mscorlib, one must build an F# library targeted at the Compact Framework 2.0, which is what the XNA .net framework is built upon.&lt;br /&gt;&lt;br /&gt;The problem is that neither Visual Studio nor msbuild support this for F# libraries. The only solution is to compile the F# library using the F# compiler directly:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;"C:\Program Files\FSharp-1.9.7.8\bin\fsc.exe"&lt;br /&gt;   -o:obj\Release\XBox360.dll&lt;br /&gt;   --standalone --noframework --define:TRACE --optimize+ --tailcalls+&lt;br /&gt;   -r:"C:\Program Files\FSharp-1.9.7.8\CompactFramework\2.0\bin\FSharp.Core.dll"&lt;br /&gt;   -r:"C:\Program Files\Microsoft XNA\XNA Game Studio\v3.1\References\Xbox360\Microsoft.Xna.Framework.dll"&lt;br /&gt;   -r:"C:\Program Files\Microsoft XNA\XNA Game Studio\v3.1\References\Xbox360\mscorlib.dll"&lt;br /&gt;   -r:"C:\Program Files\Microsoft XNA\XNA Game Studio\v3.1\References\Xbox360\System.Core.dll"&lt;br /&gt;   -r:"C:\Program Files\Microsoft XNA\XNA Game Studio\v3.1\References\Xbox360\System.dll"&lt;br /&gt;   --target:library --warn:3 --warnaserror:76 --fullpaths --flaterrors&lt;br /&gt;   &amp;lt;your F# source files here&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Beside specifying the correct XNA assemblies using "-r:", this command line also does the following:&lt;br /&gt;&lt;br /&gt;- Enables optimization using --optimize+ and --tailcalls+&lt;br /&gt;- Embeds the F# core library in the assembly, using --standalone&lt;br /&gt;&lt;br /&gt;Not very pretty, and hopefully future versions of F# and its integration into Visual Studio will remove the need to call fsc.exe explicitly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-7134090442308552841?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/7134090442308552841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=7134090442308552841' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7134090442308552841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7134090442308552841'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/12/using-f-libraries-in-xna-games-for-xbox.html' title='F# on the Xbox 360'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8247940662971020663</id><published>2009-07-14T08:51:00.001-07:00</published><updated>2010-11-12T13:01:57.267-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>Asteroids 3d strikes back</title><content type='html'>I got back to working on my asteroids clone, written in F# using the XNA framework.&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/NaCQtQrGIVw&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/NaCQtQrGIVw&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8247940662971020663?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8247940662971020663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8247940662971020663' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8247940662971020663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8247940662971020663'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/07/asteroids-3d-strikes-back.html' title='Asteroids 3d strikes back'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5649326065368690563</id><published>2009-07-08T09:49:00.000-07:00</published><updated>2010-11-12T13:18:34.992-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Interfaces made convenient by type constraints</title><content type='html'>If my previous entry convinced you to make extensive use of interfaces, you may have encountered a problem, namely that calling methods implementing interfaces requires casting:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let link = new Link("link", config, ...)&lt;br /&gt;// We want to write:&lt;br /&gt;link.Send(data)&lt;br /&gt;// But that does not compile. Instead, we must write:&lt;br /&gt;(link :&gt; ILinkOutput).Send(data)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The bad news are that there is no work around. The good news is that this situation does not happen too often in practice, as the creator of a link is in general not the user. New instances are often forwarded to other objects or functions, which will see them as ILinkOutput, thus not requiring a cast:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let register (p : ISender) (l : ILinkOutput) =&lt;br /&gt;    p.AddOutputLink(l)    // OK: p is an ISender, no need for explicit cast&lt;br /&gt;    l.ConnectInputTo(p)   // OK: l is an ILinkOutput, no need for explici cast&lt;br /&gt;&lt;br /&gt;let link = new Link(...)&lt;br /&gt;let process = new Process(...)&lt;br /&gt;register process link       // OK: process and link automatically upcasted&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, what happens if we have a function taking a process and which needs to use two of its interfaces? There are two obvious solutions, which are not so pretty.&lt;br /&gt;&lt;br /&gt;Ugly-ish:&lt;br /&gt;&lt;pre class="brush: f#"&gt;let register (p1 : ISender) (l : Link) (p2 : IReceiver) =&lt;br /&gt;    p1.AddOutputLink(l) // Nice&lt;br /&gt;    p2.AddInputLink(l)  // Nice&lt;br /&gt;    (l :&gt; ILinkOutput).ConnectInputTo(p1)   // Not so nice&lt;br /&gt;    (l :&gt; ILinkInput).ConnectOutputTo(p2)   // Not so nice&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Uglier:&lt;br /&gt;&lt;pre class="brush: f#"&gt;let register (p1 : ISender) (l1 : ILinkOutput) (l2 : ILinkOutput) (p2 : IReceiver) =&lt;br /&gt;    p1.AddOutputLink(l) // Nice&lt;br /&gt;    p2.AddInputLink(l)  // Nice&lt;br /&gt;    l1.ConnectInputTo(p1)   // Nice (is it?)&lt;br /&gt;    l2.ConnectOutputTo(p2)   // Nice (is it?)&lt;br /&gt;&lt;br /&gt;// Set up two processes communicating with each other.&lt;br /&gt;// As links are uni-directional, use two links.&lt;br /&gt;let p1 = new Process(...)&lt;br /&gt;let p2 = new Process(...)&lt;br /&gt;let link_p1_p2 = new Link(...)&lt;br /&gt;let link_p2_p1 = new Link(...)&lt;br /&gt;&lt;br /&gt;// p1 -&gt; p2&lt;br /&gt;register p1 link_p1_p2 link_p2_p1 p2  // Oops!!!&lt;br /&gt;// p2 -&gt; p1&lt;br /&gt;register p2 link_p2_p1 link_p1_p2 p1  // Oops!!!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So many 1s and 2s... We really meant to write:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;// p1 -&gt; p2&lt;br /&gt;register p1 link_p1_p2 link_p1_p2 p2 &lt;br /&gt;// p2 -&gt; p1&lt;br /&gt;register p2 link_p2_p1 link_p2_p1 p1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The correct solution uses generics and type constraints:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;let register&lt;br /&gt;    (p1 : ISender)&lt;br /&gt;    (l : 'L&lt;br /&gt;        when 'L :&gt; ILinkInput&lt;br /&gt;        and  'L :&gt; ILinkOutput)&lt;br /&gt;    (p2 : IReceiver) =&lt;br /&gt;&lt;br /&gt;    p1.AddOutputLink(l)&lt;br /&gt;    p2.AddInputLink(l)&lt;br /&gt;    l.ConnectInputTo(p1)&lt;br /&gt;    l.ConnectOutputTo(p2)&lt;br /&gt;&lt;br /&gt;// Set up two processes communicating with each other.&lt;br /&gt;// As links are uni-directional, use two links.&lt;br /&gt;let p1 = new Process(...)&lt;br /&gt;let p2 = new Process(...)&lt;br /&gt;let link_p1_p2 = new Link(...)&lt;br /&gt;let link_p2_p1 = new Link(...)&lt;br /&gt;&lt;br /&gt;// p1 -&gt; p2&lt;br /&gt;register p1 link_p1_p2 p2&lt;br /&gt;// p2 -&gt; p1&lt;br /&gt;register p2 link_p2_p1 p1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Another use of type constraints is for cases when you want to pass lists of ISenders to a function.&lt;br /&gt;&lt;br /&gt;Problem:&lt;br /&gt;&lt;pre class="brush: f#"&gt;let sendAll (ps : ISender list) data =&lt;br /&gt;    ps&lt;br /&gt;    |&gt; List.iter (fun p -&gt; p.Send(data))&lt;br /&gt;&lt;br /&gt;let p1 = new Process(...)&lt;br /&gt;let p2 = new Process(...)&lt;br /&gt;&lt;br /&gt;sendAll [ (p1 :&gt; ISender) ; (p2 :&gt; ISender) ] data  // Blah!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Solution:&lt;br /&gt;&lt;pre class="brush: f#"&gt;let sendAll (ps : 'S list when 'S :&gt; ISender) data =&lt;br /&gt;    ps&lt;br /&gt;    |&gt; List.iter (fun p -&gt; p.Send(data))&lt;br /&gt;&lt;br /&gt;let p1 = new Process(...)&lt;br /&gt;let p2 = new Process(...)&lt;br /&gt;&lt;br /&gt;sendAll [ p1; p2 ] data&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which can also be written:&lt;br /&gt;&lt;pre class="brush: f#"&gt;let sendAll (ps : #ISender list) data =&lt;br /&gt;    ps&lt;br /&gt;    |&gt; List.iter (fun p -&gt; p.Send(data))&lt;br /&gt;&lt;br /&gt;let p1 = new Process(...)&lt;br /&gt;let p2 = new Process(...)&lt;br /&gt;&lt;br /&gt;sendAll [ p1; p2 ] data&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5649326065368690563?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5649326065368690563/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5649326065368690563' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5649326065368690563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5649326065368690563'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/07/interfaces-made-convenient-by-type.html' title='Interfaces made convenient by type constraints'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2784980420112129720</id><published>2009-07-08T08:23:00.000-07:00</published><updated>2010-11-12T13:18:34.992-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Breaking up classes using interfaces</title><content type='html'>When I started writing F# programs whose code span over multiple files, I was surprised to see that the &lt;a href="http://cs.hubfs.net/forums/thread/11222.aspx"&gt;order&lt;/a&gt; of compilation of these files matters. If the code in file B.fs refers to types or functions in A.fs, then A.fs must be compiled before B.fs.&lt;br /&gt;&lt;br /&gt;Now, what happens if A.fs and B.fs depend on each other? In this case, you have a &lt;a href="http://www.sturmnet.org/blog/2008/05/20/f-compiler-considered-too-linear"&gt;problem&lt;/a&gt;. The easy fix is to merge the two files, but this solution does not scale well. Another solution is to break code into smaller pieces, building small "islands" of circular dependencies, which can each be moved into their own file. Easily said, but not so easily said.&lt;br /&gt;&lt;br /&gt;Consider an application involving processes and links. Processes can be executed, and can communicate with each other using unidirectional links.&lt;br /&gt;&lt;br /&gt;The code might look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;type Process(name, config, ...) =&lt;br /&gt;    // Construction&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    // Methods&lt;br /&gt;    //  Connection to links&lt;br /&gt;    member x.AddInputLink(link : Link) = ...&lt;br /&gt;    member x.AddOutputLink(link : Link) = ...&lt;br /&gt;&lt;br /&gt;    //  Control execution&lt;br /&gt;    member x.ExecuteInSomeWay(args) = ...&lt;br /&gt;    member x.ExecuteInSomeOtherWay(args) = ...&lt;br /&gt;    member x.CheckIsReady() = ...&lt;br /&gt;    member x.MarkAsReady() = ...&lt;br /&gt;&lt;br /&gt;    //  Debugging, and other stuff...&lt;br /&gt;    member x.ToggleDebugging(b) = ...&lt;br /&gt;    member x.SetDebugOutput(o) = ...&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;and type Link(name, config, ...) =&lt;br /&gt;    // Construction&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    // Methods&lt;br /&gt;    //  Connection to processes&lt;br /&gt;    member x.ConnectOutputTo(p : Process) = ...&lt;br /&gt;    member x.ConnectInputTo(p : Process) = ...&lt;br /&gt;&lt;br /&gt;    //  Read/Write data&lt;br /&gt;    member x.Send(data) = ...&lt;br /&gt;    member x.Receive() = ...&lt;br /&gt;&lt;br /&gt;    //  Debugging ...&lt;br /&gt;    member x.ToggleDebugging(b) = ...&lt;br /&gt;    member x.SetDebugOutput(o) = ...&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As Process and Link are mutually dependent, their code must be all in one file. That may seem OK at first, but things will become harder to manage as more code is added over time.&lt;br /&gt;&lt;br /&gt;A first solution is to introduce interfaces for Process and Link, simply duplicating all their method signatures, and replace all occurrences of classes Process and Link by their interfaces. The interfaces can be moved to a separate file, which should be shorter, as it contains no code. Classes Process and Link can now each live in separate files.&lt;br /&gt;&lt;br /&gt;Interfaces.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;type IProcess =&lt;br /&gt;    //  Connection to links&lt;br /&gt;    abstract AddInputLink : ILink -&gt; ...&lt;br /&gt;    abstract AddOutputLink : ILink -&gt; ...&lt;br /&gt;&lt;br /&gt;    //  Control execution&lt;br /&gt;    abstract ExecuteInSomeWay : Args -&gt; ...&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    //  Debugging, and other stuff...&lt;br /&gt;    member x.ToggleDebugging : bool -&gt; unit&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;and type ILink =&lt;br /&gt;    //  Connection to processes&lt;br /&gt;    abstract ConnectOutputTo Process -&gt; unit&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Process.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;open Interfaces&lt;br /&gt;&lt;br /&gt;type Process(name, config, ...) =&lt;br /&gt;    // Construction&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    // Interface implementations&lt;br /&gt;    interface IProcess with&lt;br /&gt;        member x.ExecuteInSomeWay(args) = ...&lt;br /&gt;    ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Link.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;open Interfaces&lt;br /&gt;&lt;br /&gt;type Link(name, config, ...) =&lt;br /&gt;    // Construction&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    // Interface implementation&lt;br /&gt;    interface ILink with&lt;br /&gt;        member x.ConnectOutputTo(p : IProcess) = ...&lt;br /&gt;    ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Still, Interfaces.fs may be excessively long, and we may end up in a situation where all interfaces are defined in one large file. Not very pleasant.&lt;br /&gt;&lt;br /&gt;The next step consists of breaking up the interfaces. The debugging-related methods obviously belong to a IDebugable interface, which need not be concerned with the details of processes and links.&lt;br /&gt;&lt;br /&gt;A process which is connected to the input side of a link has no need to have access to the methods taking care and transferring data from the link to the process, which indicates that ILink could be split in e.g. IInputLink and IOutputLink.&lt;br /&gt;&lt;br /&gt;There is another case of excessive method exposure. Links do not control the execution of processes, that's the task of the scheduler. The final decomposition may look as shown below.&lt;br /&gt;&lt;br /&gt;IActivable.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;type IActivable =&lt;br /&gt;    abstract CheckIsReady : unit -&gt; bool&lt;br /&gt;    abstract MarkAsReady : bool -&gt; unit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;IExecutable.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;type IExecutable =&lt;br /&gt;    abstract ExecuteInSomeWay : Args -&gt; ...&lt;br /&gt;    abstract ExecuteInSomeOtherWay : Args -&gt; ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;InputInterfaces.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;type IReceiver =&lt;br /&gt;    abstract AddInputLink : ILinkInput -&gt; unit&lt;br /&gt;&lt;br /&gt;and type ILinkInput =&lt;br /&gt;    abstract Receive : unit -&gt; Data&lt;br /&gt;    abstract ConnectOutputTo : IReceiver -&gt; unit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;OutputInterfaces.fs:&lt;br /&gt;&lt;pre class="brush: f#"&gt;type ISender =&lt;br /&gt;    abstract AddOutputLink : ILinkOutput&lt;br /&gt;&lt;br /&gt;and type ILinkOutput =&lt;br /&gt;    abstract Send : Data -&gt; unit&lt;br /&gt;    abstract ConnectInputTo : ISender -&gt; unit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The techniques shown here are by no means specific to F#, and are part of the "proper programming" techniques every object-oriented programmer should know and use. Before using F#, I almost exclusively used interfaces for polymorphism, on "as-needed" basis. The fact is, interfaces are also useful for modular programming.&lt;br /&gt;&lt;br /&gt;Decomposing programs into interfaces and implementation helps writing reusable, readable code. It does have a cost, though, as it requires more typing. As long as keyboards remain cheaper than brains, the benefits should outweigh the costs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2784980420112129720?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2784980420112129720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2784980420112129720' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2784980420112129720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2784980420112129720'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/07/breaking-up-classes-using-interfaces.html' title='Breaking up classes using interfaces'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-4362022613846960696</id><published>2009-07-08T07:21:00.000-07:00</published><updated>2009-07-08T08:04:38.638-07:00</updated><title type='text'>Concurrency on a single thread</title><content type='html'>When I wrote my &lt;a href="http://sharp-gamedev.blogspot.com/2008/09/tutorial-7-concurrency.html"&gt;article&lt;/a&gt; about concurrency, I did a bit of searching to find out how to use multi-threading in F#. One of the hits was a blog &lt;a href="http://cs.hubfs.net/blogs/hell_is_other_languages/archive/2008/08/03/6506.aspx"&gt;entry&lt;/a&gt; on HubFS by gneverov titled "Hell Is Other Languages : Concurrency on a single thread". At that time, I was a bit confused by the article. Why would one want single-threaded concurrency when we already had multi-threaded concurrency? Part of the answer lies in reactive programming.&lt;br /&gt;&lt;br /&gt;Recently, I read an &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/06/10/pumping-the-guide.aspx"&gt;article&lt;/a&gt; by Shawn Hargreaves, "Pumping the Guide", where he describes some design issues with using the Guide on the Xbox. The Guide is the part of the Xbox GUI which is used for performing common operations, such as entering text, selecting a device where game data is saved, seeing which of your friends are online and what they are doing... The problem is to have the game still running in the background while the Guide is opened.&lt;br /&gt;&lt;br /&gt;The solution chosen by the XNA team was to make calls to the Guide non-blocking. This however makes it harder for game developers to use it, as it forces them to keep track of the application state explicitly, including both the state of the game and the state of the Guide.&lt;br /&gt;&lt;br /&gt;Kevin Gadd's shows a elegant solution to this problem in C# using custom enumerators in an &lt;a href="http://www.luminance.org/code/2009/06/13/asynchronous-programming-for-xna-games-with-squaredtask"&gt;article&lt;/a&gt; aptly named "Asynchronous programming for xna games with Squared.Task".&lt;br /&gt;&lt;br /&gt;Kevin's implementation in C# is as pretty as it can get, but it would probably look even better in F# using asynchronous computations. Although the async { ... } notations is exactly what we want, the Async functions do not seem to support the kind of single-threaded concurrency that Kevin's Square.Task does.&lt;br /&gt;&lt;br /&gt;The code by gneverov however should be easy to modify to execute one single step in one of the active tasks, if it does not already support that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-4362022613846960696?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/4362022613846960696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=4362022613846960696' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4362022613846960696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/4362022613846960696'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/07/concurrency-on-single-thread.html' title='Concurrency on a single thread'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2929525480437294778</id><published>2009-07-02T10:24:00.000-07:00</published><updated>2009-07-04T02:32:31.871-07:00</updated><title type='text'>WiX again.</title><content type='html'>In my previous post I expressed my disappointment with WiX. However, after an additional day of struggling with it, I may change my mind. I managed to find a pretty straightforward solution to (almost) all my problems. Getting there wasn't straightforward at all, though.&lt;br /&gt;&lt;br /&gt;Here are the lessons I learned in the process:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Do not overwrite existing files using &amp;lt;File&amp;gt; elements.&lt;/span&gt;&lt;br /&gt;When your software gets uninstalled, it will remove your file, but the old file won't be restored. The solution that first popped up in my mind, namely to backup old files, isn't as easy as it seems. The problem is that the backup copy will be left behind after the software gets uninstalled.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&amp;lt;CopyFile&amp;gt; is not your friend.&lt;/span&gt;&lt;br /&gt;...at least as far as backing up existing files goes. I tried to back up the old file by copying it into my application's folder using CopyFile, and failed miserably. Maybe I missed something, but it seems CopyFile is designed to make copies of the files you install, not of existing files.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&amp;lt;CustomAction&amp;gt; is way too complex for its own good (and yours).&lt;/span&gt;&lt;br /&gt;CustomAction can be used in many different ways, using slightly different syntaxes. I attempted to use it to backup files, and finally succeeded. It wasn't easy. I tried to use it to run a command (COPY), but it failed. Same problem with other commands such as REN and DEL. No success running batch files either. I tried running a jscript, and that failed too. Since the creator pf WiX advises against using scripts in custom actions, I did not insist. I ended up using "xcopy.exe", which worked (with a catch: the target must be an existing directory, otherwise xcopy demands to interact with the user, and we don't want that).&lt;br /&gt;&lt;br /&gt;I found ONE use of CustomAction, and I am not planning on trying out other uses. At least not for a while.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&amp;lt;RemoveFile&amp;gt; is your friend.&lt;/span&gt;&lt;br /&gt;Unlike CopyFile, it's easy to use to clear up stuff in your application's folder. I used it to remove the backup after restoring it during uninstallation.&lt;br /&gt;&lt;br /&gt;In case you wonder how to handle back-ups in WiX, that's the way I did it:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;&amp;lt;Property Id='XCOPY'&amp;gt;xcopy.exe&amp;lt;/Property&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;CustomAction Id='Backup'&lt;br /&gt;              Property='XCOPY'&lt;br /&gt;              ExeCommand='"[ExistingFolder]PlugIn.dll" "[OldFiles]" /Y'&lt;br /&gt;              Result='check'&lt;br /&gt;              Execute='deferred' /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;CustomAction Id='Install'&lt;br /&gt;              Property='XCOPY'&lt;br /&gt;              ExeCommand='"[NewFiles]PlugIn.dll" "[ExistingFolder]" /Y'&lt;br /&gt;              Result='check'&lt;br /&gt;              Execute='deferred' /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;CustomAction Id='Restore'&lt;br /&gt;              Property='XCOPY'&lt;br /&gt;              ExeCommand='"[OldFiles]PlugIn.dll" "[ExistingFolder]" /Y'&lt;br /&gt;              Result='ignore'&lt;br /&gt;              Execute='deferred' /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;InstallExecuteSequence&amp;gt;&lt;br /&gt;  &amp;lt;Custom Action='BackupPlugIn' Before='InstallPlugIn'&amp;gt;Not Installed&amp;lt;/Custom&amp;gt;&lt;br /&gt;  &amp;lt;Custom Action='InstallPlugIn' After='InstallFiles'&amp;gt;Not Installed&amp;lt;/Custom&amp;gt;&lt;br /&gt;  &amp;lt;Custom Action='RestorePlugIn' Before='RemoveFiles'&amp;gt;Installed&amp;lt;/Custom&amp;gt;&lt;br /&gt;&amp;lt;/InstallExecuteSequence&amp;gt;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;Directory Id='NewFiles' Name='New Files'&amp;gt;&lt;br /&gt;  &amp;lt;Component Id='NewFiles' Guid='...'&amp;gt;&lt;br /&gt;    &amp;lt;File Id='NewFile' Name='Plugin.dll' Source='build/PlugIn.dll' /&amp;gt;&lt;br /&gt;  &amp;lt;/Component&amp;gt;&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Directory Id='OldFiles' Name='Old Files'&amp;gt;&lt;br /&gt;  &amp;lt;Component Id='OldFiles' Guid='...'&amp;gt;&lt;br /&gt;    &amp;lt;CreateFolder /&amp;gt;&lt;br /&gt;    &amp;lt;RemoveFile Id='CleanUpBackup' Name='PlugIn.dll' On='uninstall' /&amp;gt;&lt;br /&gt;  &amp;lt;/Component&amp;gt;&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note how I avoided overwriting files in the "Component" elements. I do that using CustomAction instead, both when installing my plug-in and when restoring the old one.&lt;br /&gt;&lt;br /&gt;Something that's missing are rollback actions. There should be one for each deferred action, namely an action removing the xcopy-ed file. I don't know of any standard program to remove files on Windows, and I'd rather not write one myself. Where is "rm"?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;UPDATE:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WiX experts are probably shaking their heads when they read this code:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;  &amp;lt;Custom Action='RestorePlugIn' Before='RemoveFiles'&amp;gt;Installed&amp;lt;/Custom&amp;gt;&lt;br /&gt;&amp;lt;/InstallExecuteSequence&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;While it does do what I intended when the user removes the software, it is also executed when users perform other actions than install or uninstall, such as repair an installation. As a result, an attempt to repair an installation will restore the old plug-in, which of course is more likely to destroy the installed software...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2929525480437294778?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2929525480437294778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2929525480437294778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2929525480437294778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2929525480437294778'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/07/wix-again.html' title='WiX again.'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-74779273369508489</id><published>2009-07-01T10:50:00.000-07:00</published><updated>2009-07-01T12:24:43.674-07:00</updated><title type='text'>WiX, because we can.</title><content type='html'>For today's post, I thought I might write on something that's not directly related to F#. Instead, this article deals with &lt;a href="http://wix.sourceforge.net/"&gt;WiX&lt;/a&gt;, a piece software intended to help creating installers. WiX and F# do share their approach to writing programs, though, namely the declarative way.&lt;br /&gt;&lt;br /&gt;First, I must say I am no expert in installers. I have built a couple rpm packages on Linux, and found the experience OK, but not particularly enjoyable. I have also used NullSoft Scriptable Install System (NSIS for short) for top10, and gave up with it. My main gripe is that NSIS is really more a scripting language, and not a particularly good one at that. I don't think it's worse than the other install systems out there, though I haven't tried them all. I did try WISE, for instance, but failed to install it. Now, that's irony...&lt;br /&gt;&lt;br /&gt;The problem is that these tools try to solve the problem using a procedural approach. The programmer has to specify what to do during an installation, which typically includes copying files on the hard disk, setting up a few shortcuts, messing up with the registry. Specifying all this is a tedious task, but it's not even half the job. One must also specify what to do when the user decides to uninstall the software. Typically, this means clearing up the mess in the registry, removing the shortcuts, deleting files.&lt;br /&gt;&lt;br /&gt;Obviously, it should be possible to deduce the uninstallation process from the installation process. It's not just a matter of convenience, but of correctness.&lt;br /&gt;&lt;br /&gt;WiX attracted a bit of attention when it came out, being Open Source software produced by Microsoft. Another side of it worth of interest is that it uses a declarative approach to specifying installation procedures. Instead of writing the sequence of operations needed to (un)install software, one specifies what to install, and where. Which is the way it should be.&lt;br /&gt;&lt;br /&gt;As attractive as it seems to be, I must say I am disappointed. The three full days of experimenting I have spent on WiX have been rather painful.&lt;br /&gt;&lt;br /&gt;The first issue is that WiX is based on Windows Installer, a.k.a MSI, whose documentation is pretty hard to grasp for a newcomer. Part of the problem resides in the core design choices, which seem genuinely weird to me. An MSI installer is not a program, it's a database, which contains a description of a workflow, where the actions make up the installation procedure. Now, installations a probably some of the most linear processes one can think of, meaning workflows are complete overkill. Why one would use a database to store a workflow is another mystery.&lt;br /&gt;&lt;br /&gt;WiX attempts to hide these layers of insanity. All you need to do to copy a file on the system is specify which file you want to copy, and where. WiX takes care of generating the code to undo the copy if it fails, as well as the code to remove the file when uninstalling.&lt;br /&gt;&lt;br /&gt;Sadly, WiX only goes halfway. If your installation process happens to write over an existing file, the uninstallation process &lt;a href="http://www.mail-archive.com/wix-users@lists.sourceforge.net/msg05622.html"&gt;won't restore&lt;/a&gt; the original file. This must be handled manually, and requires a decent understanding of MSI, its workflows, custom actions and databases.&lt;br /&gt;&lt;br /&gt;What's worse, WiX adds another layer of wickedness of its own, namely XML. That was probably the only technology missing in the stack...&lt;br /&gt;&lt;br /&gt;In case you urgently need a headache, I suggest you go have a look at &lt;a href="http://msdn.microsoft.com/en-us/library/aa372038(VS.85).aspx"&gt;Suggested InstallExecuteSequence&lt;/a&gt;, which is the sequence of actions one should take to install software. That's 60 of them, no less. If that sounds like a lot, well it is. The catch is that the same sequence is used for uninstallation. Approximately half of these actions are active when installing, the other half being active while uninstalling. The question that immediately pops up is "why not use two separate sequences"? But then, one would not need conditions, such a shame...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-74779273369508489?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/74779273369508489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=74779273369508489' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/74779273369508489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/74779273369508489'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/07/wix-because-we-can.html' title='WiX, because we can.'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6403302412892326141</id><published>2009-05-20T02:24:00.000-07:00</published><updated>2010-11-12T13:03:24.589-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>XNA asteroid clone aborted</title><content type='html'>I have decided to abort my attempt to write a 3d asteroids clone for the XBox 360. As, there already are quite a few 2d clones of the original Asteroids, I had decided to make a 3d version. The problem, as I pointed in an earlier post, is that one needs a considerably larger number of asteroids to make the game interesting. The magic number here seems to be 1000 asteroids.&lt;br /&gt;&lt;br /&gt;I wanted collision response between asteroids. Doing collision detection is quadratic in the number of objects, unless one uses space partitioning. My experiments showed that the naive way (without space partitioning) works fine for 100 asteroids, but does not scale up.&lt;br /&gt;&lt;br /&gt;I implemented an octree data structure to speed things up. The idea here is to partition space in boxes of varying size, where each box contains at most about 10 asteroids. Collision detection can then be done on groups of 10 asteroids.&lt;br /&gt;&lt;br /&gt;The optimization worked fine when the game was run on the PC, but not on the XBox. The game run at 60 fps on the PC, with noticeable "hickups" every few seconds though. The game run at less than 10 fps on the XBox.&lt;br /&gt;&lt;br /&gt;The culprit is the gargabe collector on the XBox. When looking on the net, one finds that the suggested solution is to minimize the number of live objects, which involves using structs. Unfortunately, most of the nice constructs of F#, such as discriminated unions and records, are translated to classes. Replacing these by structs is feasible, but it's not a very pleasant experience.&lt;br /&gt;&lt;br /&gt;I also feel that I do not want to invest time developing skills to avoid garbage collection when the correct solution is to fix the garbage collector on XBox.&lt;br /&gt;&lt;br /&gt;That does not mean I am giving up on XNA and the XBox, but I will have to find other computationally easier projects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6403302412892326141?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6403302412892326141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6403302412892326141' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6403302412892326141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6403302412892326141'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/05/xna-asteroid-clone-aborted.html' title='XNA asteroid clone aborted'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8706196487713869264</id><published>2009-04-12T01:16:00.000-07:00</published><updated>2009-04-12T01:24:11.309-07:00</updated><title type='text'>Race condition in "First obstacles and solutions"</title><content type='html'>I fixed a bug in my asteroids clone yesterday which turned out to be a race condition. The problem was in map_parallel:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;let map_parallel (func : 'a -&gt; 'b) (items : 'a[]) =&lt;br /&gt;    let results = Array.zero_create (items.Length)&lt;br /&gt;    let count = ref items.Length&lt;br /&gt;    use notify = new System.Threading.AutoResetEvent(false)&lt;br /&gt;&lt;br /&gt;    items&lt;br /&gt;    |&gt; Array.iteri (&lt;br /&gt;        fun i item -&gt;&lt;br /&gt;            System.Threading.ThreadPool.QueueUserWorkItem (&lt;br /&gt;                fun _ -&gt;&lt;br /&gt;                    let res = func item&lt;br /&gt;                    results.[i] &lt;- res&lt;br /&gt;!:                  System.Threading.Interlocked.Decrement count |&gt; ignore&lt;br /&gt;!:                  if !count = 0 then notify.Set() |&gt; ignore&lt;br /&gt;            ) |&gt; ignore&lt;br /&gt;       )&lt;br /&gt;    notify.WaitOne() |&gt; ignore&lt;br /&gt;    results&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I have marked the two faulty lines in the code above with "!:". The (hopefully) correct version is:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;                  let c = System.Threading.Interlocked.Decrement count&lt;br /&gt;                  if c = 0 then notify.Set() |&gt; ignore&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In the faulty version, it is possible for two threads to execute "then notify.Set()". The second thread may then raise an exception as "notify" may already have been disposed of.&lt;br /&gt;&lt;br /&gt;The code in the original post was corrected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8706196487713869264?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8706196487713869264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8706196487713869264' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8706196487713869264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8706196487713869264'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/04/race-condition-in-first-obstacles-and.html' title='Race condition in &quot;First obstacles and solutions&quot;'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-8113678951964748908</id><published>2009-03-29T14:16:00.000-07:00</published><updated>2009-12-13T08:48:01.917-08:00</updated><title type='text'>Structs that look like records</title><content type='html'>I've spent some time trying to improve my asteroids clone in F# for the XBox360. I present the first results in this post.&lt;br /&gt;&lt;br /&gt;But first, some non-technical considerations. Microsoft has now made available to XNA creators (i.e. game programmers) the download statistics of their games. A vast majority of creators seem disappointed, but I think that's more a sign of too high expectations than a failure of the platform itself.&lt;br /&gt;One of the creators reported that full game downloads went down when Microsoft raised the time limit in trial versions from 4 minutes to 8 minutes. Players have the ability to download a trial version of an XBox Live Community Game before buying the full version. Trial versions typically have some features disabled (this is up to the game creator) and a mandatory time limit (which cannot be controlled by game creators).&lt;br /&gt;What happened there, apparently, is that the game is played in short sessions shorter than 8 minutes at a time, making the free trial version sufficiently appealing that gamers did not feel a need to buy the full version.&lt;br /&gt;&lt;br /&gt;Asteroids is not typically a game you play for long periods at a time, so I expect my game may suffer the same problem.&lt;br /&gt;&lt;br /&gt;Back to the technical side of things. I found a way to make structs look like records. Here is the declaration:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;type State =&lt;br /&gt;    struct&lt;br /&gt;        val props : Properties&lt;br /&gt;        val pos : Vector3&lt;br /&gt;        val speed : Vector3&lt;br /&gt;        val impulses : Vector3&lt;br /&gt;        val force : Vector3&lt;br /&gt;        &lt;br /&gt;        new (props, pos, speed, impulses, force) = &lt;br /&gt;            { props = props ;&lt;br /&gt;              pos      = pos ;&lt;br /&gt;              speed    = speed ;&lt;br /&gt;              impulses = impulses ;&lt;br /&gt;              force    = force }&lt;br /&gt;        &lt;br /&gt;        static member inline Default (props, ?pos, ?speed, ?impulses, ?force) =&lt;br /&gt;            State(&lt;br /&gt;                props,&lt;br /&gt;                pos = defaultArg pos Vector3.Zero,&lt;br /&gt;                speed = defaultArg speed Vector3.Zero,&lt;br /&gt;                impulses = defaultArg impulses Vector3.Zero,&lt;br /&gt;                force = defaultArg force Vector3.Zero)&lt;br /&gt;                &lt;br /&gt;        member inline x.Clone (?pos, ?speed, ?impulses, ?force) =&lt;br /&gt;            new State (&lt;br /&gt;              x.props,&lt;br /&gt;              pos      = defaultArg pos      x.pos,&lt;br /&gt;              speed    = defaultArg speed    x.speed,&lt;br /&gt;              impulses = defaultArg impulses x.impulses,&lt;br /&gt;              force    = defaultArg force    x.force )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;... and here is how it's used:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;        member x.ApplyCenterForce (v : Vector3) =&lt;br /&gt;            let force = x.force + v &lt;br /&gt;            x.Clone (force = force)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is very similar to the old code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;let applyCenterForce (v : Vector3) (x : State) =&lt;br /&gt;    let force = x.force + v&lt;br /&gt;    { x with force = force }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looking back at the first snipplet, notice how I declared "x.Clone":&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;        static member inline Default (props, ?pos, ?speed, ?impulses, ?force) =&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The question marks before the arguments mean that these arguments are optional. If the caller does not provide them, they automatically get the "None" value.&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;            new State (&lt;br /&gt;              x.props,&lt;br /&gt;              pos      = defaultArg pos      x.pos,&lt;br /&gt;              speed    = defaultArg speed    x.speed,&lt;br /&gt;              impulses = defaultArg impulses x.impulses,&lt;br /&gt;              force    = defaultArg force    x.force )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;"defaultArg" is a convenience F# standard function which returns the first value unless it's "None", in which case the second value is returned.&lt;br /&gt;&lt;br /&gt;The function was declared "inline" to avoid creating lots of "Option" objects at call sites. For instance, the disassembled version of "ApplyCenterForce" looks like this:&lt;br /&gt;&lt;pre class="brush: c#"&gt;&lt;br /&gt;public HeavyObject.State ApplyCenterForce(Vector3 v)&lt;br /&gt;{&lt;br /&gt;    return new HeavyObject.State(this._props, this._pos, this._speed, this._impulses, this._force + v);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Compare with the version without "inline":&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;public HeavyObject.State ApplyCenterForce(Vector3 v)&lt;br /&gt;{&lt;br /&gt;    Vector3 vector = this._force + v;&lt;br /&gt;    return this.Clone(null, null, null, new Option&lt;Vector3&gt;(vector));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As the entire point with structs is to avoid allocating objects on the heap, having an "Option&lt;Vector3&gt;" created for each call to ApplyCenterForce is not quite acceptable.&lt;br /&gt;&lt;br /&gt;It's not clear that using structs is a clear win in all situations. Performance on the PC is negatively affected, as garbage collection is almost free there, whereas copying structs when passing them as parameters to functions isn't. Performance on the XBox360, however, is improved, as garbage collection is kept under control.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-8113678951964748908?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/8113678951964748908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=8113678951964748908' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8113678951964748908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/8113678951964748908'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/03/structs-that-look-like-records.html' title='Structs that look like records'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2184405112602281273</id><published>2009-03-25T15:02:00.000-07:00</published><updated>2009-12-13T08:44:13.716-08:00</updated><title type='text'>First obstacles and solutions</title><content type='html'>I've got forward with my asteroids clone on the XBox 360 using XNA, and I started noticing a few issues, not all technical.&lt;br /&gt;&lt;br /&gt;First, a 3d space is mostly empty. I did not realize the probability of being hit by an asteroid is pretty low. In order to make the game somewhat interesting, I need a good 1k asteroids in a 100m x 100m x 100m cube. I doubt any player will have the patience and perseverance to shoot each of these 1000 asteroids. I have ideas about solving that problem, but I'm not sure which one to pick yet.&lt;br /&gt;&lt;br /&gt;Regarding performance, the game initially ran fine with 100 asteroids, but as I say above, I will need 10 times that amount. The initial bottleneck was collision detection, which was quadratic. I solved this on the PC using space partitioning with an octree.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: f#"&gt;&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;open Microsoft.Xna.Framework&lt;br /&gt;open System.Collections.Generic&lt;br /&gt;&lt;br /&gt;type NodeData&lt;'a&gt; =&lt;br /&gt;    { bbox : BoundingBox ;&lt;br /&gt;      sub_nodes : Node&lt;'a&gt; [] }&lt;br /&gt;      &lt;br /&gt;and Node&lt;'a&gt; =&lt;br /&gt;    | Leaf of BoundingBox * 'a []&lt;br /&gt;    | Node of NodeData&lt;'a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let mkBBox (p1 : Vector3) (p2 : Vector3) =&lt;br /&gt;    let x1, x2 =&lt;br /&gt;        if p1.X &lt; p2.X then (p1.X, p2.X) else (p2.X, p1.X)&lt;br /&gt;    let y1, y2 =&lt;br /&gt;        if p1.Y &lt; p2.Y then (p1.Y, p2.Y) else (p2.Y, p1.Y)&lt;br /&gt;    let z1, z2 =&lt;br /&gt;        if p1.Z &lt; p2.Z then (p1.Z, p2.Z) else (p2.Z, p1.Z)&lt;br /&gt;    &lt;br /&gt;    BoundingBox (Vector3 (x1, y1, z1), Vector3 (x2, y2, z2))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let map_parallel (func : 'a -&gt; 'b) (items : 'a[]) =&lt;br /&gt;    let results = Array.zero_create (items.Length)&lt;br /&gt;    let count = ref items.Length&lt;br /&gt;    use notify = new System.Threading.AutoResetEvent(false)&lt;br /&gt;    &lt;br /&gt;    items&lt;br /&gt;    |&gt; Array.iteri (&lt;br /&gt;        fun i item -&gt;&lt;br /&gt;            System.Threading.ThreadPool.QueueUserWorkItem (&lt;br /&gt;                fun _ -&gt;&lt;br /&gt;                    let res = func item&lt;br /&gt;                    results.[i] &lt;- res&lt;br /&gt;                    let c = System.Threading.Interlocked.Decrement count&lt;br /&gt;                    if c = 0 then notify.Set() |&gt; ignore&lt;br /&gt;            ) |&gt; ignore&lt;br /&gt;        )&lt;br /&gt;    notify.WaitOne() |&gt; ignore&lt;br /&gt;    results&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;let rec partition (count_limit) (intersect) (items : 'a []) (bbox : BoundingBox) multi_threaded =&lt;br /&gt;    if items.Length &lt; count_limit&lt;br /&gt;    then&lt;br /&gt;        (bbox, items) |&gt; Leaf&lt;br /&gt;    else&lt;br /&gt;        let in_bbox =&lt;br /&gt;            items&lt;br /&gt;            |&gt; Array.filter (fun item -&gt; intersect item bbox)&lt;br /&gt;&lt;br /&gt;        let center = 0.5f * (bbox.Min + bbox.Max)&lt;br /&gt;        let pts = bbox.GetCorners ()&lt;br /&gt;&lt;br /&gt;        let sub_nodes =&lt;br /&gt;            pts&lt;br /&gt;            |&gt; (if multi_threaded then map_parallel else Array.map) (&lt;br /&gt;                fun pt -&gt;&lt;br /&gt;                    let sub_box = mkBBox center pt&lt;br /&gt;                    partition count_limit intersect in_bbox sub_box false&lt;br /&gt;                )&lt;br /&gt;&lt;br /&gt;        { bbox = bbox ;&lt;br /&gt;          sub_nodes = sub_nodes }&lt;br /&gt;        |&gt; Node&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let rec getVisible (view : BoundingFrustum) addVisible (partition : Node&lt;'a&gt;) =&lt;br /&gt;    match partition with&lt;br /&gt;    | Leaf (bbox, items) -&gt;&lt;br /&gt;        if bbox.Intersects (view)&lt;br /&gt;        then&lt;br /&gt;            items |&gt; Array.iter addVisible&lt;br /&gt;    | Node data -&gt;&lt;br /&gt;        if data.bbox.Intersects (view)&lt;br /&gt;        then&lt;br /&gt;            data.sub_nodes&lt;br /&gt;            |&gt; Array.iter (getVisible view addVisible)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It's pretty rough code, but there are some interesting bits anyway. In "partition", the function creating the octree, I use multithreading in the top call in an attempt to take advantage of the multiple cores. My timings on the PC show however little global benefit in using multithreading, but I don't know how much "partition" contributes to the overall execution time. It's too early to draw any conclusion, but at least performance is not negatively affected.&lt;br /&gt;&lt;br /&gt;Note that I reimplemented map_parallel (which I had introduced in an earlier Tutorial about concurrency) without using asynchronous computations. It's obviously inferior to the older version as it does not handle exceptions, but it has the advantage of actually working on both the PC and the XBox360. The older version causes an "error code 4" on the XBox. I don't know why, I'll try to report that on hubfs with a smaller test case as soon as I get time.&lt;br /&gt;&lt;br /&gt;The octree made the PC version run nicely with 1000 asteroids and more, but the XBox360 is still running very slowly, which makes me think that I have finally hit the limitations of its garbage collector. Note that I have not verified that, not being very comfortable with the development kit yet.&lt;br /&gt;&lt;br /&gt;Currently, each asteroid is represented using a record, and records get translated to classes by the F# compiler. The records are stored in an array. I wonder if it would work better with structs instead, the idea being that an array of structs should be seen as one object, whereas an array of classes is composed of 1001 objects in this case. As the performance of garbage collection is dependent on the number of objects, but not so much on their size, an array of struct should offer better performance.&lt;br /&gt;&lt;br /&gt;The sad thing is that I really liked records, I wish F# allowed the [&amp;lt;Struct&amp;gt;] attribute on records.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2184405112602281273?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2184405112602281273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2184405112602281273' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2184405112602281273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2184405112602281273'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/03/ive-got-forward-with-my-asteroids-clone.html' title='First obstacles and solutions'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5182993005839407896</id><published>2009-03-14T10:47:00.000-07:00</published><updated>2010-11-12T13:04:56.629-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asteroidhunter'/><title type='text'>F# game running on the console</title><content type='html'>I have just succeeded to write and run my first game on my XBox360. Here is proof of it:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nDGpBaX7_xg/SbvuOd9oEiI/AAAAAAAAAhM/3xCYbcrw0Wk/s1600-h/asteroids-2009-03-14.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_nDGpBaX7_xg/SbvuOd9oEiI/AAAAAAAAAhM/3xCYbcrw0Wk/s400/asteroids-2009-03-14.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5313102117742318114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The game is composed of an F# library and a top-level C# application. The game, a 3d clone of Asteroids, is still very far from being complete. For instance controls require a keyboard, and the code is still riddled with bugs. Never the less, the first attempt to deploy on the XBox was successful, which is quite encouraging. See &lt;a href="http://grammerjack.spaces.live.com/blog/cns!F2629C772A178A7C!158.entry?ppud=4&amp;wa=wsignin1.0&amp;sa=494581287"&gt;Grammerjack's old blog&lt;/a&gt; for details on each step of the deployment process.&lt;br /&gt;&lt;br /&gt;The F# code is written in a pure functional way, which I fear is not going to work out in the end. Such code relies heavily on the garbage collector, and the current version of the XBox360 .NET environment is known to be weak on this point.&lt;br /&gt;&lt;br /&gt;I wonder if it's possible to modify the .NET code emitted by the F# compiler to replace instantiations of new objects by references to items in pre-allocated arrays. This would make it possible to keep purity in the F# source code while maintaining decent performance.&lt;br /&gt;Right now, I feel that if I was to write code relying heavily on in-place modifications, I would rather do that in C# than in F#.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5182993005839407896?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5182993005839407896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5182993005839407896' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5182993005839407896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5182993005839407896'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2009/03/f-game-running-on-console.html' title='F# game running on the console'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nDGpBaX7_xg/SbvuOd9oEiI/AAAAAAAAAhM/3xCYbcrw0Wk/s72-c/asteroids-2009-03-14.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-515220045024297521</id><published>2008-12-26T06:36:00.000-08:00</published><updated>2010-11-12T13:16:19.631-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Parsing DirectX .X files</title><content type='html'>This has been by far the most demanding episode to write in these series of tutorials, but finally it's there. See &lt;a href="http://code.google.com/p/fs-gamedev/wiki/Tutorial10"&gt;http://code.google.com/p/fs-gamedev/wiki/Tutorial10&lt;/a&gt; for the text and source code.&lt;br /&gt;&lt;br /&gt;This tutorial shows how to parse .X files, which are used for 3d models and scenes. Note that DirectX offers convenient functions to manipulate these files, meaning that the practical usefulness of the code in this tutorial is limited, unless you don't have access to DirectX.&lt;br /&gt;&lt;br /&gt;This tutorial demonstrates the following concepts:&lt;br /&gt;&lt;br /&gt;    * Discriminated unions and simple pattern matching&lt;br /&gt;    * Stateless lexing&lt;br /&gt;    * Hiding side effects in IO operations&lt;br /&gt;    * Error handling using the option type&lt;br /&gt;    * Defining mutually and self dependent types&lt;br /&gt;    * Building functions at run-time by combining basic functions&lt;br /&gt;&lt;br /&gt;The content of this tutorial is significantly denser than usual. The really interesting part in my opinion resides however in the design decision to separate parsing in two stages. During the first stage, second-stage parsers are dynamically created by combining simple parsers (such as a semi-colon parser, an int parser, even a "zero" parser parsing nothing). Second-stage parsing simply consists of calling the result of first-stage parsing, which results in hierarchical data representing faces, lights and materials composing a 3d scene.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-515220045024297521?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/515220045024297521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=515220045024297521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/515220045024297521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/515220045024297521'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/12/parsing-directx-x-files.html' title='Parsing DirectX .X files'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5445919190546343916</id><published>2008-11-09T08:07:00.000-08:00</published><updated>2008-11-09T08:37:38.844-08:00</updated><title type='text'>Situation update</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Tutorials&lt;/span&gt;&lt;br /&gt;There has been little visible activity on the tutorials recently. That's because I have been busy implementing a small 3d object viewer. I have the somewhat unfortunate tendency to choose complexity over simplicity, which means that this viewer should be cross-platform. It is based on a generic scene-graph library and will support both DirectX (using SlimDX) and OpenGL (using the TAO framework).&lt;br /&gt;It can display 3d objects stored in .X files, currently using the DirectX API. I have started a mini-project to write my own parser for it, as DirectX is limited to windows platforms.&lt;br /&gt;I am starting to see the end of the tunnel, and the following tutorials should come soon:&lt;br /&gt;&lt;br /&gt;- A generic scene graph library. It will demonstrate the use of some of F# objected-oriented constructs. It will also show how to use SlimDX with F#, which you can already see in snk_kid's &lt;a href="http://cs.hubfs.net/forums/thread/6960.aspx"&gt;examples&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;- A parser for .X files. Writing this code proved more challenging than expected: .X files start by defining the data structures that are used later in the file to describe the data. See e.g. &lt;a href="http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/directx/"&gt;Direct-X File Format&lt;/a&gt;. This is a flexible but unusual approach: Data structures are normally fixed from file to file, and parsers can be written with this knowledge at hand. I found an elegant solution using a functional approach: The data structure declarations are parsed, generating new data parsers, which are used later when parsing the data itself.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;XNA&lt;/span&gt;&lt;br /&gt;I am staying clear of XNA for the time being. It would seem that my dream of getting my &lt;a href="http://top10-racing.org"&gt;racing game&lt;/a&gt; to run on the XBox360 is not realizable, as the CLR on the XBox360 is notably slow when it comes to computations on floats, which are hardly avoidable in physics simulations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Mono and games&lt;/span&gt;&lt;br /&gt;Regarding performance and games, it seems Mono is overtaking Microsoft's CLR. Miguel de Icaza has &lt;a href="http://tirania.org/blog/archive/2008/Nov-03.html"&gt;announced&lt;/a&gt; that Mono now has experimental support for SIMD instructions. My racing game is currently implemented in C++, but does not take advantage of SIMD instructions. I am hopeful that a new clean implementation of my physics engine in F# may actually be faster than the current C++ one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5445919190546343916?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5445919190546343916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5445919190546343916' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5445919190546343916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5445919190546343916'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/11/situation-update.html' title='Situation update'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3348050170656754343</id><published>2008-10-24T12:11:00.000-07:00</published><updated>2010-11-12T13:17:27.873-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Tutorials moving to Google code</title><content type='html'>From now on, I will use the &lt;a href="http://code.google.com/p/fs-gamedev/wiki/Main"&gt;wiki&lt;/a&gt; on the Google code project for the tutorials. This has the advantage that readers will be able to see the history of corrections. Another good thing is that the wiki supports syntax highlighting. Blogger's software does not seem especially fit for posting code.&lt;br /&gt;&lt;br /&gt;I think I will continue to use this blog for my thoughts and opinions about game programming and F#.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3348050170656754343?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3348050170656754343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3348050170656754343' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3348050170656754343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3348050170656754343'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/10/tutorials-moving-to-google-code.html' title='Tutorials moving to Google code'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-6413914601617341753</id><published>2008-10-19T12:48:00.000-07:00</published><updated>2010-12-05T14:08:46.399-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Tutorial 11b: Efficient generic programming</title><content type='html'>Specialization is a programming technique used to improve the performance of generic code. It consists of specifying specific implementations for one or several specific instantiations of generic code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Specialization using pattern matching&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The "runge_kutta_4" function shown in these tutorials contains the following lines:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;old + (1.0/6.0) * (v1 + 2.0 * (v2 + v3) + v4)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This is fine when dealing with floats, but with 3-dimensional vectors and larger types, it may be excessively slow due to the large amounts of intermediate values produced. Indeed, this code is the same as:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;tmp1 = v2 + v3&lt;br /&gt;tmp2 = 2.0 * tmp1&lt;br /&gt;tmp3 = tmp2 + v4&lt;br /&gt;tmp5 = v1 + tmp3&lt;br /&gt;tmp6 = 1.0 / 6.0&lt;br /&gt;tmp7 = tmp6 * tmp5&lt;br /&gt;old + tmp7&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Of these 7 intermediate values, 6 could be replaced by one.&lt;br /&gt;&lt;br /&gt;What if we had a function to add 6 vectors creating only one value, the final result?&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;let add6 ((v0: Vec3d), (v1: Vec3d), (v2: Vec3d), (v3: Vec3d), (v4: Vec3d), (v5: Vec3d)) =&lt;br /&gt;let x = v0.x + v1.x + v2.x + v3.x + v4.x + v5.x&lt;br /&gt;let y = v0.y + v1.y + v2.y + v3.y + v4.y + v5.y&lt;br /&gt;let z = v0.z + v1.z + v2.z + v3.z + v4.z + v5.z&lt;br /&gt;&lt;br /&gt;Vec3d(x, y ,z)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Admittedly, it's not very pretty, and it would be nice if the user of "runge_kutta_4" was not forced to provide such a function.&lt;br /&gt;&lt;br /&gt;F# has a parametric type called "option" useful to represent this kind of optional values. The C++ counter-part is to use a pointer, and let the null value denote the case when no value is provided.&lt;br /&gt;&lt;br /&gt;The dictionary of operations is modified as follows:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;type VecOps&amp;lt;'vector, 'scalar&amp;gt; = {&lt;br /&gt;up: 'vector&lt;br /&gt;add: 'vector * 'vector -&amp;gt; 'vector&lt;br /&gt;add6: Add6&amp;lt;'vector&amp;gt; option&lt;br /&gt;scale: 'scalar * 'vector -&amp;gt; 'vector&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;(By the way, another equivalent way of writing the declaration of add6 would be&lt;br /&gt;&lt;div class="mycode"&gt;add6: 'vector Add6 option&lt;br /&gt;&lt;/div&gt;)&lt;br /&gt;&lt;br /&gt;An instance of the dictionary using add6 is created as follows:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;let Vec3d_ops = {&lt;br /&gt;add = plus_Vec3d;&lt;br /&gt;scale = scale_Vec3d;&lt;br /&gt;add6 = Some add6;&lt;br /&gt;up = Vec3d(1.0)&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Or, to leave out add6:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;let Vec3d_ops = {&lt;br /&gt;add = plus_Vec3d;&lt;br /&gt;scale = scale_Vec3d;&lt;br /&gt;add6 = None;&lt;br /&gt;up = Vec3d(1.0)&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The last part of the "runge_kutta_4" function is modified to check if the dictionary of operations contains an "add6":&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;match vec_ops.add6 with&lt;br /&gt;// No addMany available, use pair-wise additions (will create many intermediate vectors).&lt;br /&gt;| None -&gt;&lt;br /&gt;old + (1.0/6.0) * (v1 + 2.0 * (v2 + v3) + v4)&lt;br /&gt;// addMany available, use it.&lt;br /&gt;| Some add -&gt;&lt;br /&gt;let tmp = add (v1, v2, v2, v3, v3, v4)&lt;br /&gt;old + (1.0/6.0) * tmp&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This is a new F# construct, called "pattern-matching". Basically, it means:&lt;br /&gt;&lt;br /&gt;"Check the value of vec_ops.add6. If it is equal to None, then do the sum the usual way. otherwise, if the value of vec_ops.add6 is of the form Some add, then do the some by using 'add'".&lt;br /&gt;&lt;br /&gt;I think pattern matching is a very nice construct. It allows you to match a value with fairly complex expressions called patterns. I won't dig deeper into patterns yet, let me just say that even though they look complex, the code generated by the compiler is as optimized as possible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Optimization troubles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, not everything runs as fine as I had hoped. If I look at the generated code, I see that the optimizations that the F# compiler performed in the first part of Tutorial 11 have now disappeared. The problem seems to be that the compiler no longer sees through the record used for the dictionary of operations, and is therefore unable to inline the addition and scale operations. It is also unable to see if vec_ops.add6 is constantly "None" or if it has a constant function value.&lt;br /&gt;&lt;br /&gt;As it turns out, the problem has nothing to do with pattern matching. Indeed, if I removed the "up" field from the record, or if use multiple parameters instead of a record, the generated code looks very nice, as shown below.&lt;br /&gt;&lt;br /&gt;When an "add6" function is provided:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nDGpBaX7_xg/STFm1pONmcI/AAAAAAAAAfo/yUVps0xG7WY/s1600-h/FS-Tut11b-1.png"&gt;&lt;img style="cursor: pointer; width: 358px; height: 101px;" src="http://3.bp.blogspot.com/_nDGpBaX7_xg/STFm1pONmcI/AAAAAAAAAfo/yUVps0xG7WY/s400/FS-Tut11b-1.png" alt="" id="BLOGGER_PHOTO_ID_5274109710412126658" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When no "add6" function is provided:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nDGpBaX7_xg/STFm_lQs8rI/AAAAAAAAAfw/ZCoihkiUt_Y/s1600-h/FS-Tut11b-2.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 116px;" src="http://2.bp.blogspot.com/_nDGpBaX7_xg/STFm_lQs8rI/AAAAAAAAAfw/ZCoihkiUt_Y/s400/FS-Tut11b-2.png" alt="" id="BLOGGER_PHOTO_ID_5274109881147519666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Was it worth it?&lt;/span&gt;&lt;br /&gt;I get a 25% performance boost thanks to "add6" when using 3d vectors. On the other hand, I get a 65% performance drop when summing floats. This seems to be a clear case where tailoring generic code to specific types really helps to achieve the best performance.&lt;br /&gt;There is a link to the full code available at the bottom of this page, if you want to try it out for yourself. I have made an habit of messing up my benchmark measurements, so don't take my word!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Time to conclude the part of these Tutorials dedicated to generic programming and low-level optimization.&lt;br /&gt;&lt;br /&gt;To summarize:&lt;br /&gt;1) Make sure your computations on floats are correct. NaN values kill performance.&lt;br /&gt;2) Avoid curried functions when performance is critical, especially for methods.&lt;br /&gt;3) Inline generic functions to avoid indirect calls to operations. However, do not take the habit of inlining all small functions. The compiler or the CLR do that for you.&lt;br /&gt;4) Keep dictionaries of operations small, or avoid them altogether. Alternatives include static type constraints, shown in Tutorial 9, or function parameters.&lt;br /&gt;&lt;br /&gt;Regarding item 4), I hope this is a problem that will be fixed in later releases of the F# compiler.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Source code&lt;/span&gt;&lt;br /&gt;The complete source code used in this tutorial is available on &lt;a href="http://code.google.com/p/fs-gamedev/source/browse/trunk/Tutorial011/Program011.fs"&gt;google code&lt;/a&gt; (with comments, for a change).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-6413914601617341753?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/6413914601617341753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=6413914601617341753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6413914601617341753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/6413914601617341753'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/10/tutorial-11b-efficient-generic.html' title='Tutorial 11b: Efficient generic programming'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nDGpBaX7_xg/STFm1pONmcI/AAAAAAAAAfo/yUVps0xG7WY/s72-c/FS-Tut11b-1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5110869707972845603</id><published>2008-10-15T13:05:00.000-07:00</published><updated>2010-12-05T14:09:11.109-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Tutorial 11: Efficient generic programming</title><content type='html'>In Tutorial 8 I introduced a method for generic programmings which uses so-called dictionaries of operations (see also pp 110-111 in Expert F#). I concluded the article with the following judgment:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;I'll close this up with a comment on performance. To put things bluntly, it's terrible. I am not quite sure if I have done something wrong, so I won't post scary numbers (yet), but I would say this method is not usable for real time physics simulations.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Bug fix&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, it turned out that (1) I did do something wrong, and (2) there was a lot of untapped optimization potential in this code.&lt;br /&gt;&lt;br /&gt;Before I go deeper into optimization techniques, let me correct a bug in the code:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;let spring (vec_ops: VecOps&amp;lt;'a, 'b&amp;gt;) stiff pos =&lt;br /&gt;vec_ops.scale stiff pos&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;should have been&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;let spring (vec_ops: VecOps&amp;lt;'a, 'b&amp;gt;) stiff pos =&lt;br /&gt;vec_ops.scale -stiff pos&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Without the minus sign, the simulated system quickly gains so much energy that the positions fall out of range. Apparently, floating point computations involving NaNs are very slow.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Faster, but still slow&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With that problem fixed, the program now runs with the following execution times:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1D (struct)&lt;br /&gt;Single (min, max, avg): 17.296000 17.382000 17.330000&lt;br /&gt;Multi (min, max, avg): 8.244000 8.591000 8.412000&lt;br /&gt;Single (min, max, avg): 78.617000 80.769000 79.340333&lt;br /&gt;Multi (min, max, avg): 41.145000 41.741000 41.362333&lt;br /&gt;2D (struct)&lt;br /&gt;Single (min, max, avg): 18.918000 19.332000 19.158667&lt;br /&gt;Multi (min, max, avg): 10.107000 10.411000 10.300667&lt;br /&gt;Single (min, max, avg): 108.103000 110.466000 109.122333&lt;br /&gt;Multi (min, max, avg): 56.108000 58.272000 57.140667&lt;br /&gt;3D (struct)&lt;br /&gt;Single (min, max, avg): 23.440000 23.683000 23.553667&lt;br /&gt;Multi (min, max, avg): 12.671000 15.129000 13.726667&lt;br /&gt;Single (min, max, avg): 112.160000 114.022000 113.266333&lt;br /&gt;Multi (min, max, avg): 60.331000 65.190000 63.192667&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that integration using 3-dimensional vectors is only ~1.5 times slower than when using 1-dimensional vectors, which is unexpected. The computations alone should really be 3 times slower. Where does the difference come from?&lt;br /&gt;&lt;br /&gt;The time for the 1-dimensional computation is roughly fp + ovh, where fp is the time spend doing additions and multiplications on floats, and ovh is the overhead, i.e. time spent in calling functions and allocating objects.&lt;br /&gt;Then the time for the 3-dimensional computation should be 3fp + ovh. For the sake of simplicity I'm assuming the overhead does not depend on the type of vector involved.&lt;br /&gt;I've done the math for single-threaded RK4, and it turns out that the overhead time is about 78% of the total execution time.&lt;br /&gt;&lt;br /&gt;It should be possible to do better, especially if we look at the performance of the code in Tutorial 9. Personally, I prefer the code in Tutorial 8, and would be glad if I could bring down the execution time to comparable levels.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Optimizations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A common (and valuable) advice on optimization techniques is to profile the code, using e.g. NProf. In the present case, however, NProf did not tell me anything I did not know.&lt;br /&gt;At this point, .NET reflector comes in handy as it allows one to look at the generated IL code.&lt;br /&gt;&lt;br /&gt;Let us look at the code for "ef_Vec1d", the Euler integration function using 1-dimensional vectors. It's not trivial to find, there is a bit of detective work to do. In the code for "_main", we find:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nDGpBaX7_xg/SPZSPvoV24I/AAAAAAAAAWk/-TJcY-IBdhw/s1600-h/FS-Tut11-1.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_nDGpBaX7_xg/SPZSPvoV24I/AAAAAAAAAWk/-TJcY-IBdhw/s320/FS-Tut11-1.PNG" alt="" id="BLOGGER_PHOTO_ID_5257480045438819202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ef_Vec1d is a partially evaluated function, which is compiled into an object mimicking a function. This kind of object holds the evaluated parameters as data members and has an "Invoke" method which is the function itself.&lt;br /&gt;There is a bit of overhead associated to partially evaluated functions, which means one should avoid them in performance critical sections of the code.&lt;br /&gt;If we look at "clo@64_1", we will see that it lacks any data member. Moreover, the "Invoke" method contains:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nDGpBaX7_xg/SPuOUPdOM3I/AAAAAAAAAXk/i8zs7ThjLzc/s1600-h/FS-Tut11-2.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nDGpBaX7_xg/SPuOUPdOM3I/AAAAAAAAAXk/i8zs7ThjLzc/s320/FS-Tut11-2.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5258953468282811250" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Notice how the compiler is accessing Vec1D_ops directly, instead of using a data member or a function parameter. Would it be possible to get the compiler to do the same kind of optimization inside "euler_implicit"? In order for this to be possible, "euler_implicit" must be declared "inline". The new "clo@64" becomes:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nDGpBaX7_xg/SPZTdBrkxHI/AAAAAAAAAW0/kzU_01Je_dw/s1600-h/FS-Tut11-3.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_nDGpBaX7_xg/SPZTdBrkxHI/AAAAAAAAAW0/kzU_01Je_dw/s320/FS-Tut11-3.PNG" alt="" id="BLOGGER_PHOTO_ID_5257481373134144626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The generated code is starting to be hard to read, but we can see that the body of "euler_implicit" was indeed inlined, and is now using Vec1D_ops directly. That is a nice optimization, but it would be better if the compiler had gone further and called "Vec1d.scale" directly. It might have even inlined "Vec1d.scale", as this method is very short.&lt;br /&gt;What can we do to help the compiler do that? I had to take a guess here, but I suspected using a record for VecOps instead of a class could be a good idea.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nDGpBaX7_xg/SPZTomyf5kI/AAAAAAAAAW8/qnX1kmVE_2s/s1600-h/FS-Tut11-4.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_nDGpBaX7_xg/SPZTomyf5kI/AAAAAAAAAW8/qnX1kmVE_2s/s320/FS-Tut11-4.PNG" alt="" id="BLOGGER_PHOTO_ID_5257481572073858626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That was a pretty good intuition. For some reason, classes prevent the F# compiler to "see through" them and remove them during optimization. Records, on the other hand, can be removed.&lt;br /&gt;&lt;br /&gt;This piece of code, which is much more easily readable than the previous one, exposes a new problem:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nDGpBaX7_xg/SPZTxxOXeSI/AAAAAAAAAXE/QRUeN5xVcdc/s1600-h/FS-Tut11-5.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_nDGpBaX7_xg/SPZTxxOXeSI/AAAAAAAAAXE/QRUeN5xVcdc/s320/FS-Tut11-5.PNG" alt="" id="BLOGGER_PHOTO_ID_5257481729493924130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note that "plus" is not a function of two Vec1d returning a Vec1d. What it really is is a function of a single Vec1d, returning a FastFunc, which is itself an object mimicking a function. Every time "plus" is called, a new function object is created, which is a bad thing, performance wise. Happily, the solution is easy: Change the signature of plus to take two Vec1d and return a Vec1d. Instead of Vec1d -&gt; Vec1d -&gt; Vec1d&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nDGpBaX7_xg/SPZT8vDoovI/AAAAAAAAAXM/TTyN1GjF_Jk/s1600-h/FS-Tut11-6.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_nDGpBaX7_xg/SPZT8vDoovI/AAAAAAAAAXM/TTyN1GjF_Jk/s320/FS-Tut11-6.PNG" alt="" id="BLOGGER_PHOTO_ID_5257481917890601714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;we want (Vec1d * Vec1d) -&gt; Vec1d:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nDGpBaX7_xg/SPZUEEqh_bI/AAAAAAAAAXU/hygUxSP_shc/s1600-h/FS-Tut11-7.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_nDGpBaX7_xg/SPZUEEqh_bI/AAAAAAAAAXU/hygUxSP_shc/s320/FS-Tut11-7.PNG" alt="" id="BLOGGER_PHOTO_ID_5257482043949972914" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After applying the same change to "scale", we get the following performance:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1D (struct)&lt;br /&gt;Single (min, max, avg): 1.959000 1.971000 1.964667&lt;br /&gt;Multi (min, max, avg): 0.990000 1.004000 0.995000&lt;br /&gt;Single (min, max, avg): 9.463000 9.509000 9.479667&lt;br /&gt;Multi (min, max, avg): 4.939000 5.023000 4.975667&lt;br /&gt;2D (struct)&lt;br /&gt;Single (min, max, avg): 3.485000 3.522000 3.507333&lt;br /&gt;Multi (min, max, avg): 1.783000 1.814000 1.794667&lt;br /&gt;Single (min, max, avg): 20.306000 20.692000 20.468333&lt;br /&gt;Multi (min, max, avg): 10.557000 10.657000 10.593000&lt;br /&gt;3D (struct)&lt;br /&gt;Single (min, max, avg): 6.089000 6.127000 6.104667&lt;br /&gt;Multi (min, max, avg): 3.073000 3.201000 3.152333&lt;br /&gt;Single (min, max, avg): 32.570000 32.616000 32.597333&lt;br /&gt;Multi (min, max, avg): 16.424000 16.784000 16.657667&lt;br /&gt;3D (record)&lt;br /&gt;Single (min, max, avg): 6.910000 6.958000 6.940667&lt;br /&gt;Multi (min, max, avg): 3.530000 3.575000 3.554667&lt;br /&gt;Single (min, max, avg): 33.879000 34.373000 34.065000&lt;br /&gt;Multi (min, max, avg): 17.662000 17.843000 17.758667&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That was quite a performance improvement, wasn't it?&lt;br /&gt;I have also implemented a 3d vector type using a record instead of a struct, in case it might magically improve performance. As you can see, it did not, there is no real difference with the struct.&lt;br /&gt;&lt;br /&gt;These numbers could certainly be improved further by using the techniques described in Tutorial 7, but I'll stop here for now.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Complete source code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the complete source code of the optimized version, see &lt;a href="http://code.google.com/p/fs-gamedev/source/browse/trunk/Tutorial008/Program008.fs?r=10"&gt;revision 8&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To compare the changes with the code from Tutorial 8, see &lt;a href="http://code.google.com/p/fs-gamedev/source/diff?spec=svn10&amp;amp;old=7&amp;amp;r=10&amp;amp;format=side&amp;amp;path=%2Ftrunk%2FTutorial008%2FProgram008.fs"&gt;the diff&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-5110869707972845603?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/5110869707972845603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=5110869707972845603' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5110869707972845603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/5110869707972845603'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/10/tutorial-11-efficient-generic.html' title='Tutorial 11: Efficient generic programming'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nDGpBaX7_xg/SPZSPvoV24I/AAAAAAAAAWk/-TJcY-IBdhw/s72-c/FS-Tut11-1.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3858190233811524937</id><published>2008-10-10T11:42:00.000-07:00</published><updated>2008-10-10T11:45:25.665-07:00</updated><title type='text'>Source code on Google code</title><content type='html'>Just a quick note to announce that I have created a &lt;a href="http://code.google.com/p/fs-gamedev/"&gt;google code project&lt;/a&gt; to host the source code used in this blog.&lt;br /&gt;I have not yet added all tutorials, but the seven first are already there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3858190233811524937?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3858190233811524937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3858190233811524937' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3858190233811524937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3858190233811524937'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/10/source-code-on-google-code.html' title='Source code on Google code'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-7754432757152006921</id><published>2008-09-27T02:17:00.000-07:00</published><updated>2010-12-05T14:10:06.631-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Tutorial 10: Generic programming using quotations</title><content type='html'>The code for this tutorial comes in several files.&lt;br /&gt;First: GenericPhysics.fs&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;#light&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;open Microsoft.FSharp.Linq.QuotationEvaluation&lt;br /&gt;&lt;br /&gt;#nowarn "57"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type ps&amp;lt;'Vec&amp;gt; = class&lt;br /&gt; val pos:'Vec&lt;br /&gt; val speed:'Vec&lt;br /&gt; new(pos, speed) = { pos = pos; speed = speed }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type sa&amp;lt;'Vec&amp;gt; = class&lt;br /&gt; val speed:'Vec&lt;br /&gt; val accel:'Vec&lt;br /&gt; new(speed, accel) = { speed = speed; accel = accel }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;let mk_gravity scale_func (up: 'Vec): 'Vec =&lt;br /&gt; let q =&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (*) = %scale_func in -9.81 * up&lt;br /&gt;     @&amp;gt;&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let mk_spring scale_func: float -&amp;gt; 'Vec -&amp;gt; 'Vec =&lt;br /&gt; let q =&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (*) = %scale_func in fun k v -&amp;gt; -k * v&lt;br /&gt;     @&amp;gt;&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let mk_drag scale_func: float -&amp;gt; 'Vec -&amp;gt; 'Vec =&lt;br /&gt; let q =&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (*) = %scale_func in fun k v -&amp;gt; -k * v&lt;br /&gt;     @&amp;gt;&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let mk_euler_implicit plus_func scale_func =&lt;br /&gt; let q =&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (+) = %plus_func in&lt;br /&gt;     let (*) = %scale_func in&lt;br /&gt;     fun accel_func pos speed delta -&amp;gt;&lt;br /&gt;         let speed2 = speed + delta * (accel_func pos speed)&lt;br /&gt;         let pos2 = pos + delta * speed2&lt;br /&gt;         ps&amp;lt;_&amp;gt;(pos2, speed2)&lt;br /&gt;     @&amp;gt;&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let inline adapt (f: 'Vec -&amp;gt; 'Vec -&amp;gt; 'Vec) =&lt;br /&gt; fun pos speed -&amp;gt;&lt;br /&gt;     let accel = f pos speed in&lt;br /&gt;         sa&amp;lt;_&amp;gt;(speed, accel)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let mk_rk4_q plus_func scale_func =&lt;br /&gt; &amp;lt;@&lt;br /&gt; fun deriv_func pos speed delta -&amp;gt;&lt;br /&gt;     let pf = %plus_func&lt;br /&gt;     let sf = %scale_func&lt;br /&gt;  &lt;br /&gt;     let extrapolate x delta dx =&lt;br /&gt;         pf x (sf delta dx)&lt;br /&gt;&lt;br /&gt;     let half_delta = 0.5 * delta&lt;br /&gt;   &lt;br /&gt;     let sa1: sa&amp;lt;_&amp;gt; = deriv_func pos speed&lt;br /&gt;     let sa2 = deriv_func (extrapolate pos half_delta sa1.speed) (extrapolate speed half_delta sa1.accel)&lt;br /&gt;     let sa3 = deriv_func (extrapolate pos half_delta sa2.speed) (extrapolate speed half_delta sa2.accel)&lt;br /&gt;     let sa4 = deriv_func (extrapolate pos delta sa3.speed)      (extrapolate speed delta sa3.accel)&lt;br /&gt;&lt;br /&gt;     let sixth_delta = delta / 6.0 &lt;br /&gt;&lt;br /&gt;     let update old v1 v2 v3 v4 =&lt;br /&gt;         pf old (sf sixth_delta&lt;br /&gt;             (pf v1&lt;br /&gt;             (pf v2&lt;br /&gt;             (pf v2&lt;br /&gt;             (pf v3&lt;br /&gt;             (pf v3&lt;br /&gt;                 v4))))))&lt;br /&gt;                       &lt;br /&gt;     let pos1 = update pos sa1.speed sa2.speed sa3.speed sa4.speed&lt;br /&gt;     let speed1 = update speed sa1.accel sa2.accel sa3.accel sa4.accel&lt;br /&gt;  &lt;br /&gt;     ps&amp;lt;'Vec&amp;gt;(pos1, speed1)&lt;br /&gt; @&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let mk_rk4 plus_func scale_func =&lt;br /&gt; let q = mk_rk4_q plus_func scale_func&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let simulate intg_func (t0: float) t_fin delta pos0 speed0 =&lt;br /&gt; let rec repeat t0 pos0 speed0 =&lt;br /&gt;     if t0 &amp;gt; t_fin then (pos0, speed0)&lt;br /&gt;     else&lt;br /&gt;         let t1 = t0 + delta&lt;br /&gt;         let ps: ps&amp;lt;_&amp;gt; = intg_func pos0 speed0 delta&lt;br /&gt;         repeat t1 ps.pos ps.speed&lt;br /&gt; repeat t0 pos0 speed0&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Second file: FloatPhysics.fs&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;#light&lt;br /&gt;&lt;br /&gt;let gravity = GenericPhysics.mk_gravity &amp;lt;@ fun x y -&amp;gt; x * y @&amp;gt; 1.0&lt;br /&gt;let drag = GenericPhysics.mk_drag &amp;lt;@ fun x y -&amp;gt; x * y @&amp;gt;&lt;br /&gt;let spring = GenericPhysics.mk_spring &amp;lt;@ fun x y -&amp;gt; x * y @&amp;gt;&lt;br /&gt;let rk4 = GenericPhysics.mk_rk4 &amp;lt;@ fun x y -&amp;gt; x + y @&amp;gt; &amp;lt;@ fun x y -&amp;gt; x * y @&amp;gt;&lt;br /&gt;let euler = GenericPhysics.mk_euler_implicit &amp;lt;@ fun x (y:float) -&amp;gt; x + y @&amp;gt; &amp;lt;@ fun x y -&amp;gt; x * y @&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Third file: Util.fs&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;#light&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;&lt;br /&gt;let run_time_func (func: unit -&amp;gt; 'a) =&lt;br /&gt; let watch = new System.Diagnostics.Stopwatch()&lt;br /&gt; watch.Start()&lt;br /&gt; let res = func ()&lt;br /&gt; watch.Stop()&lt;br /&gt; let diff0 = float watch.ElapsedMilliseconds / 1000.0&lt;br /&gt; (diff0, res)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let map_parallel func items =&lt;br /&gt; let tasks =&lt;br /&gt;     seq {&lt;br /&gt;         for i in items -&amp;gt; async {&lt;br /&gt;             return (func i)&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt; Async.Run (Async.Parallel tasks)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Last file: Main.fs&lt;br /&gt;&lt;div class="mycode"&gt;#light&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;open FloatPhysics&lt;br /&gt;open Util&lt;br /&gt;&lt;br /&gt;let inline accel pos speed =&lt;br /&gt; drag 1.0 speed + spring 100.0 pos + gravity&lt;br /&gt;&lt;br /&gt;let ef = (FloatPhysics.euler accel)&lt;br /&gt;let rk4f = (rk4 (GenericPhysics.adapt accel))&lt;br /&gt;&lt;br /&gt;let run euler_func s0 =&lt;br /&gt; let t0 = 0.0&lt;br /&gt; let t_fin = 1000.0&lt;br /&gt; let delta = 0.005&lt;br /&gt;&lt;br /&gt; let run_timed map_func =&lt;br /&gt;     let n_runs = 2&lt;br /&gt;     let times =&lt;br /&gt;         [&lt;br /&gt;             for i in 1..n_runs -&amp;gt;&lt;br /&gt;                 let (run_time, res) =&lt;br /&gt;                     run_time_func (fun () -&amp;gt;&lt;br /&gt;                         s0 |&amp;gt; map_func(fun (x, y) -&amp;gt;&lt;br /&gt;                             GenericPhysics.simulate euler_func t0 t_fin delta x y))&lt;br /&gt;                 run_time&lt;br /&gt;         ]&lt;br /&gt;  &lt;br /&gt;     let max = Seq.max times&lt;br /&gt;     let min = Seq.min times&lt;br /&gt;     let avg = (Seq.fold (fun x y -&amp;gt; x+y) 0.0 times) / float n_runs&lt;br /&gt;     (min, max, avg)&lt;br /&gt;&lt;br /&gt; let single_min, single_max, single_avg = run_timed List.map&lt;br /&gt; let multi_min, multi_max, multi_avg = run_timed map_parallel&lt;br /&gt;&lt;br /&gt; printfn "Single (min, max, avg): %f %f %f" single_min single_max single_avg&lt;br /&gt; printfn "Multi (min, max, avg): %f %f %f" multi_min multi_max multi_avg&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let n_bodies = 2&lt;br /&gt;&lt;br /&gt;let s0_float = [ for s in 1..n_bodies -&amp;gt; (float s, 0.0) ]&lt;br /&gt;run ef s0_float&lt;br /&gt;run rk4f s0_float&lt;br /&gt;&lt;br /&gt;ignore(Console.ReadKey(true))&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nDGpBaX7_xg/SN5PswY-ZrI/AAAAAAAAAWE/ewp00_RPUMQ/s1600-h/project_file_order.PNG"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://2.bp.blogspot.com/_nDGpBaX7_xg/SN5PswY-ZrI/AAAAAAAAAWE/ewp00_RPUMQ/s320/project_file_order.PNG" alt="" id="BLOGGER_PHOTO_ID_5250721845883070130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;If you want to compile these sources using Visual Studio, you need to know that the order in which the files appear in the project is important. If a file B uses types or values from a file A, then A must be placed higher in the list of files of the project.&lt;br /&gt;&lt;br /&gt;You will also need to add references to the following DLLs: FSharp.PowerPack and FSharp.PowerPack.Linq.&lt;br /&gt;&lt;br /&gt;Let us now take a deeper look at the new features of F# used in the code.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;open Microsoft.FSharp.Linq.QuotationEvaluation&lt;br /&gt;&lt;br /&gt;#nowarn "57"&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The main item of this Tutorial is quotations. These represent pieces of code which can be constructed at compile time, changed dynamically at run time, and recompiled and executed dynamically. This last part is still experimental, and requires the use of a specific module.&lt;br /&gt;The "#nowarn" directives tells the compiler not to warn us about this feature being experimental.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;let mk_gravity scale_func (up: 'Vec): 'Vec =&lt;br /&gt; let q =&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (*) = %scale_func in -9.81 * up&lt;br /&gt;     @&amp;gt;&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The interesting piece here is the part between &amp;lt;@ and @&amp;gt;. The entire thing is called a quotation. It must contain a valid segment of F# code. The F# compiler will parse the code in this quotation, and build an object representing this code. More precisely, the compiler will generate an abstract syntax tree (AST). Note that this object does not in itself constitute executable code.&lt;br /&gt;You may be wondering what "%scale_func" means in this context. The "%" operator specifies that another AST should be inserted there. "scale_func" is the variable which should contain the AST to insert.&lt;br /&gt;To clarify this, look at the call to mk_gravity in FloatPhysics.fs:&lt;br /&gt;&lt;div class="mycode"&gt;let gravity = GenericPhysics.mk_gravity &amp;lt;@ fun x y -&amp;gt; x * y @&amp;gt; 1.0&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The resulting quotation would therefore look as follows:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (*) = fun x y -&gt; x * y in -9.81 * up&lt;br /&gt;     @&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;which is has the same effect as:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     -9.81 * up&lt;br /&gt;     @&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;An AST generated from a quotation can be compiled using method "Compile", or compiled and executed using method "Eval".&lt;br /&gt;Had I written "q.Eval()" instead, "mk_gravity" would have returned a value of type "unit -&amp;gt; 'Vec", i.e. a function taking no argument and returning a vector when called. We may just as well returned the vector directly, which we can do by using method "Eval" instead.&lt;br /&gt;&lt;br /&gt;If we take a step back and look at what we have just achieved, we will see that we have constructed a rather complicated way of perform the product of a vector by a scalar.&lt;br /&gt;&lt;br /&gt;Let us look at the next function for a more interesting example.&lt;br /&gt;&lt;div class="mycode"&gt;let mk_spring scale_func: float -&amp;gt; 'Vec -&amp;gt; 'Vec =&lt;br /&gt; let q =&lt;br /&gt;     &amp;lt;@&lt;br /&gt;     let (*) = %scale_func in fun k v -&amp;gt; -k * v&lt;br /&gt;     @&amp;gt;&lt;br /&gt; q.Eval()&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;While I wrote this code I repeatedly found myself wondering "What did I just write?". Happily, the compiler can answer that question.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nDGpBaX7_xg/SN5YAAPAU0I/AAAAAAAAAWM/O1cmXOcg2dE/s1600-h/type_mk_spring.PNG"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://1.bp.blogspot.com/_nDGpBaX7_xg/SN5YAAPAU0I/AAAAAAAAAWM/O1cmXOcg2dE/s320/type_mk_spring.PNG" alt="" id="BLOGGER_PHOTO_ID_5250730972646757186" border="0" /&gt;&lt;/a&gt;This function takes an AST which should represent a function taking a float and a vector (in curried form) and returning a vector. The "mk_spring" function will then return a function taking a float and a vector and returning a vector. In other words, it will "unquote" the quotation, which is simply done by evaluating the AST. Before doing so, it inserts the quoted form of the function performing the product of a vector by a scalar into q, which in the present case has the same effect as:&lt;br /&gt;&lt;div class="mycode"&gt;        &amp;lt;@&lt;br /&gt;     let (*) = fun x y -&amp;gt; x * y in fun k v -&amp;gt; -k * v&lt;br /&gt;     @&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Or in simpler terms:&lt;br /&gt;&lt;div class="mycode"&gt;        &amp;lt;@&lt;br /&gt;     -k * v&lt;br /&gt;     @&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;We have found yet another way to perform the product of a vector (which is actually a float in this simple example) by a scalar (another float, but not to be mistaken with the vector). The "mk_spring" function differs from "mk_gravity" in the way that its parameters are expected to vary. Gravity is assumed to be constant, and so is the upward direction, denoted by the "up" parameter of "mk_gravity". The stiffness coefficient and the position of the body, on the other hand, change across calls.&lt;br /&gt;&lt;br /&gt;Using quotations to achieve genericity can be seen as some kind of hybrid between the functional approach described in Tutorial 8 and the approach based on static constraints of Tutorial 9. It shares with Tutorial 8 its use of function parameters to specify the implementation of operations on vectors. It share with Tutorial 9 its way of emitting specific code for each concrete type of vector.&lt;br /&gt;&lt;br /&gt;I had hoped this would result in more efficient code, but that is unfortunately not currently the case. The quotation evaluation functionality is still experimental, and it may be possible that future versions of F# might produce faster code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 102, 102);"&gt;Update&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 102, 102);"&gt;I've come across an &lt;/span&gt;&lt;a style="color: rgb(255, 102, 102);" href="http://blogs.msdn.com/jomo_fisher/archive/2007/03/28/fast-switching-with-linq.aspx"&gt;entry in Jomo Fisher's blog&lt;/a&gt;&lt;span style="color: rgb(255, 102, 102);"&gt; about Linq which makes me wonder if my code is really right. Jomo has used Linq in a setting where performance is truly impressive. Why I am getting such bad results here? Further investigation needed...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(255, 102, 102);"&gt;End of Update&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The point of the approach described here is not so much what it achieves, but what possibilities it opens. For instance, it is possible to implement aggressive optimization techniques that the F# compiler will probably never support, such as rearranging code to avoid creating objects for intermediate values, or turning pure computations into computations with local side effects. Obviously, it would not be realistic to support all features of F#, but a subset dedicated to computations would probably suffice. Using Quotations.Expr from F# and Reflection.Emit from .NET, it seems very feasible to write a specialized optimizing compiler for a subset of F#.&lt;br /&gt;Other interesting potential uses of quotations for games include programs to run on the GPU (shaders), or on any other kind of peripheral, for that matter (game controllers, head-on displays...).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-7754432757152006921?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/7754432757152006921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=7754432757152006921' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7754432757152006921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/7754432757152006921'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/09/tutorial-10-generic-programming-using.html' title='Tutorial 10: Generic programming using quotations'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nDGpBaX7_xg/SN5PswY-ZrI/AAAAAAAAAWE/ewp00_RPUMQ/s72-c/project_file_order.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-2812815359875712978</id><published>2008-09-24T13:18:00.000-07:00</published><updated>2010-12-05T14:10:06.632-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Updated C++ version</title><content type='html'>This is the C++ version of the integrator, updated to use vectors.&lt;br /&gt;&lt;br /&gt;UPDATE: Bug fixes. Funny how non-explicit single-argument constructors can hide errors in your code...&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;// RK++NET.cpp : main project file.&lt;br /&gt;&lt;br /&gt;#include "stdafx.h"&lt;br /&gt;#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;map&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;const double gravity = -9.81;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;inline&lt;br /&gt;T spring(const T&amp; pos)&lt;br /&gt;{&lt;br /&gt;  return -100.0 * pos;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;inline&lt;br /&gt;T drag(double k, const T&amp; pos)&lt;br /&gt;{&lt;br /&gt;  return -k * pos;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename A&amp;gt;&lt;br /&gt;class EulerImplicit&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  EulerImplicit(const A&amp; accel):&lt;br /&gt;      accel(accel)&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;  template&amp;lt;typename T&amp;gt;&lt;br /&gt;  inline&lt;br /&gt;  void operator()(T&amp; pos, T&amp; speed, const double delta) const&lt;br /&gt;  {&lt;br /&gt;    speed += delta * accel(pos, speed);&lt;br /&gt;    pos += delta * speed;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  const A&amp; accel;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename A&amp;gt;&lt;br /&gt;class RK4&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  RK4(const A&amp; accel):&lt;br /&gt;      accel(accel)&lt;br /&gt;      {&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;  template&amp;lt;typename T&amp;gt;&lt;br /&gt;  inline&lt;br /&gt;  void operator()(T&amp; pos, T&amp; speed, const double delta) const&lt;br /&gt;  {&lt;br /&gt;    const double half_delta = 0.5 * delta;&lt;br /&gt;    &lt;br /&gt;    std::pair&amp;lt;T, T&amp;gt; k1 = accel(pos, speed);&lt;br /&gt;    std::pair&amp;lt;T, T&amp;gt; k2 = accel(pos + half_delta * k1.first, speed + half_delta * k1.second);&lt;br /&gt;    std::pair&amp;lt;T, T&amp;gt; k3 = accel(pos + half_delta * k2.first, speed + half_delta * k2.second);&lt;br /&gt;    std::pair&amp;lt;T, T&amp;gt; k4 = accel(pos + delta * k3.first, speed + delta * k3.second);&lt;br /&gt;&lt;br /&gt;    pos += delta / 6.0 * (k1.first + 2.0 * (k2.first + k3.first) + k4.first);&lt;br /&gt;    speed += delta / 6.0 * (k1.second + 2.0 * (k2.second + k3.second) + k4.second);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  const A&amp; accel;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;class Force&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  explicit Force(const T&amp; up) : m_drag(1.0), m_gravity(gravity*up)&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  T operator()(const T&amp; pos, const T&amp; speed) const&lt;br /&gt;  {&lt;br /&gt;    return drag(m_drag, speed) + spring(pos) + m_gravity;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;&lt;br /&gt;  const double m_drag;&lt;br /&gt;  T m_gravity;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename A&amp;gt;&lt;br /&gt;class Adapt&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Adapt(const A&amp; accel):&lt;br /&gt;    accel(accel)&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  template&amp;lt;typename T&amp;gt;&lt;br /&gt;    inline std::pair&amp;lt;T, T&amp;gt; operator()(const T&amp; pos, const T&amp; speed) const&lt;br /&gt;  {&lt;br /&gt;    std::pair&amp;lt;T, T&amp;gt; ret;&lt;br /&gt;    ret.first = speed;&lt;br /&gt;    ret.second = accel(pos, speed);&lt;br /&gt;    return ret;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  const A&amp; accel;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T, typename I&amp;gt;&lt;br /&gt;inline&lt;br /&gt;void simulate(const I&amp; intg_func, T&amp; pos, T&amp; speed, double t0, const double t_fin, const double delta)&lt;br /&gt;{&lt;br /&gt;  while(t0 &amp;lt; t_fin)&lt;br /&gt;  {&lt;br /&gt;    t0 += delta;&lt;br /&gt;    intg_func(pos, speed, delta);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;int DIM&amp;gt;&lt;br /&gt;class VecD&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  VecD() {&lt;br /&gt;    for (int i=0; i&amp;lt;DIM; ++i)&lt;br /&gt;      vals[i] = 0.0;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  explicit VecD(double v0, double v1=0.0, double v2=0.0)&lt;br /&gt;  {&lt;br /&gt;    if (DIM &amp;gt;= 1)&lt;br /&gt;      vals[0] = v0;&lt;br /&gt;&lt;br /&gt;    if (DIM &amp;gt;= 2)&lt;br /&gt;      vals[1] = v1;&lt;br /&gt;&lt;br /&gt;    if (DIM &amp;gt;= 3)&lt;br /&gt;      vals[2] = v2;&lt;br /&gt;&lt;br /&gt;    for (int i=3; i&amp;lt;DIM; ++i)&lt;br /&gt;      vals[i] = 0.0;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  inline VecD&amp;lt;DIM&amp;gt; operator+=(const VecD&amp;lt;DIM&amp;gt;&amp; other)&lt;br /&gt;  {&lt;br /&gt;    for (int i=0; i&amp;lt;DIM; ++i)&lt;br /&gt;      vals[i] += other.vals[i];&lt;br /&gt;    return *this;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  inline VecD&amp;lt;DIM&amp;gt; operator+(const VecD&amp;lt;DIM&amp;gt;&amp; other) const&lt;br /&gt;  {&lt;br /&gt;    VecD&amp;lt;DIM&amp;gt; tmp(*this);&lt;br /&gt;    return tmp += other;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;  double vals[DIM];&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;int DIM&amp;gt;&lt;br /&gt;inline&lt;br /&gt;VecD&amp;lt;DIM&amp;gt;&lt;br /&gt;operator*(double k, const VecD&amp;lt;DIM&amp;gt;&amp; other)&lt;br /&gt;{&lt;br /&gt;  VecD&amp;lt;DIM&amp;gt; ret(other);&lt;br /&gt;  for (int i=0; i&amp;lt;DIM; ++i)&lt;br /&gt;    ret.vals[i] *= k;&lt;br /&gt;  return ret;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;typedef VecD&amp;lt;1&amp;gt; Vec1D;&lt;br /&gt;typedef VecD&amp;lt;2&amp;gt; Vec2D;&lt;br /&gt;typedef VecD&amp;lt;3&amp;gt; Vec3D;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void make_pos(int i, double&amp; out) { out = (double)i; }&lt;br /&gt;void make_pos(int i, Vec1D&amp; out) { out = Vec1D((double) i); }&lt;br /&gt;void make_pos(int i, Vec2D&amp; out) { out = Vec2D(1.0, (double) i); }&lt;br /&gt;void make_pos(int i, Vec3D&amp; out) { out = Vec3D(1.0, (double) i, -1.0); }&lt;br /&gt;&lt;br /&gt;void make_up(double &amp;out) { out = 1.0; }&lt;br /&gt;void make_up(Vec1D &amp;out) { out = Vec1D(1.0); }&lt;br /&gt;void make_up(Vec2D &amp;out) { out = Vec2D(0.0, 1.0); }&lt;br /&gt;void make_up(Vec3D &amp;out) { out = Vec3D(0.0, 1.0, 0.0); }&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename Vec&amp;gt;&lt;br /&gt;void run_sim(const char *descr)&lt;br /&gt;{&lt;br /&gt;  typedef std::vector&amp;lt; std::pair&amp;lt;Vec, Vec&amp;gt; &amp;gt; Tuples;&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; descr &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;br /&gt;  const double t0 = 0.0;&lt;br /&gt;  const double t_fin = 1000.0;&lt;br /&gt;  const double delta = 0.005;&lt;br /&gt;  const int N_BODIES = 100;&lt;br /&gt;&lt;br /&gt;  Tuples initial_states;&lt;br /&gt;  initial_states.reserve(N_BODIES);&lt;br /&gt;  for (int i=0; i&amp;lt;N_BODIES; ++i)&lt;br /&gt;  {&lt;br /&gt;    Vec pos;&lt;br /&gt;    make_pos(i, pos);&lt;br /&gt;    initial_states.push_back( std::make_pair(pos, Vec(0.0)) );&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  double el = 0.0;&lt;br /&gt;  const int NRUNS=3;&lt;br /&gt;  for (int i=0; i&amp;lt;NRUNS; ++i)&lt;br /&gt;  {&lt;br /&gt;    Tuples states(initial_states);&lt;br /&gt;&lt;br /&gt;    Vec up;&lt;br /&gt;    make_up(up);&lt;br /&gt;    Force&amp;lt;Vec&amp;gt; accel(up);&lt;br /&gt;    EulerImplicit&amp;lt; Force&amp;lt;Vec&amp;gt; &amp;gt; euler(accel);&lt;br /&gt;    long int start0 = GetTickCount();&lt;br /&gt;    for (Tuples::iterator it = states.begin();&lt;br /&gt;      it != states.end();&lt;br /&gt;      ++it)&lt;br /&gt;    {&lt;br /&gt;      simulate(euler, it-&amp;gt;first, it-&amp;gt;second, t0, t_fin, delta);&lt;br /&gt;    }&lt;br /&gt;    el += (GetTickCount() - start0) / 1000.0;&lt;br /&gt;  }&lt;br /&gt;  std::cout &amp;lt;&amp;lt; "Time: " &amp;lt;&amp;lt; el / NRUNS &amp;lt;&amp;lt; "\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;  run_sim&amp;lt;double&amp;gt;("double");&lt;br /&gt;  run_sim&amp;lt;Vec1D&amp;gt;("class 1D");&lt;br /&gt;  run_sim&amp;lt;Vec2D&amp;gt;("class 2D");&lt;br /&gt;  run_sim&amp;lt;Vec3D&amp;gt;("class 3D");&lt;br /&gt;&lt;br /&gt;  char c;&lt;br /&gt;  std::cin &amp;gt;&amp;gt; c;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-2812815359875712978?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/2812815359875712978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=2812815359875712978' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2812815359875712978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/2812815359875712978'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/09/updated-c-version.html' title='Updated C++ version'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-3605429990910194637</id><published>2008-09-24T11:15:00.000-07:00</published><updated>2010-12-05T14:10:06.632-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Tutorial 9: Generic programming using type constraints</title><content type='html'>This Tutorial 9 shows a generic implementation of the integrator, based on type parameters.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;#light&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let run_time_func (func: unit -&amp;gt; 'a) =&lt;br /&gt;    let watch = new System.Diagnostics.Stopwatch()&lt;br /&gt;    watch.Start()&lt;br /&gt;    let res = func ()&lt;br /&gt;    watch.Stop()&lt;br /&gt;    let diff0 = float watch.ElapsedMilliseconds / 1000.0&lt;br /&gt;    (diff0, res)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let map_parallel func items =&lt;br /&gt;    let tasks =&lt;br /&gt;        seq {&lt;br /&gt;            for i in items -&amp;gt; async {&lt;br /&gt;                return (func i)&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    Async.Run (Async.Parallel tasks)&lt;br /&gt;&lt;br /&gt;type ps&amp;lt;'num&amp;gt; = struct&lt;br /&gt;    val pos:'num&lt;br /&gt;    val speed:'num&lt;br /&gt;    new(pos, speed) = { pos = pos; speed = speed }&lt;br /&gt;end&lt;br /&gt;    &lt;br /&gt;type VecN =&lt;br /&gt;    One of float&lt;br /&gt;    | Two of float*float&lt;br /&gt;    | Three of float*float*float&lt;br /&gt;with&lt;br /&gt;    static member inline plus (a: VecN) (b: VecN) =&lt;br /&gt;        match (a, b) with&lt;br /&gt;            | (One(v), One(w)) -&amp;gt; One(v+w)&lt;br /&gt;            | (Two(v0, v1), Two(w0, w1)) -&amp;gt; Two(v0 + w0, v1 + w1)&lt;br /&gt;            | (Three(v0, v1, v2), Three(w0, w1, w2)) -&amp;gt; Three(v0 + w0, v1 + w1, v2 + w2)&lt;br /&gt;            | _ -&amp;gt; failwith "Size mismatch"&lt;br /&gt;&lt;br /&gt;    static member inline scale (k: float) (a: VecN) =&lt;br /&gt;        match a with&lt;br /&gt;            | One(v) -&amp;gt; One(k * v)&lt;br /&gt;            | Two(v0, v1) -&amp;gt; Two(k * v0, k * v1)&lt;br /&gt;            | Three(v0, v1, v2)  -&amp;gt; Three(k * v0, k * v1, k * v2)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type Vec1d = struct&lt;br /&gt;    val x: float&lt;br /&gt;    &lt;br /&gt;    new (x) = { x = x }&lt;br /&gt;    &lt;br /&gt;    static member inline plus (a: Vec1d) (b: Vec1d) = Vec1d(a.x + b.x)&lt;br /&gt;    static member inline scale (k: float) (a: Vec1d) = Vec1d(k * a.x)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type Vec2d = struct&lt;br /&gt;    val x: float&lt;br /&gt;    val y: float&lt;br /&gt;    &lt;br /&gt;    new (x, y) = { x = x; y = y }&lt;br /&gt;    &lt;br /&gt;    static member inline plus (a: Vec2d) (b: Vec2d) = Vec2d(a.x + b.x, a.y + b.y)&lt;br /&gt;    static member inline scale (k: float) (a: Vec2d) = Vec2d(k * a.x, k * a.y)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type Vec3d = struct&lt;br /&gt;    val x: float&lt;br /&gt;    val y: float&lt;br /&gt;    val z: float&lt;br /&gt;    &lt;br /&gt;    new (x, y, z) = { x = x; y = y; z = z }&lt;br /&gt;    &lt;br /&gt;    static member inline plus (a: Vec3d) (b: Vec3d) = Vec3d(a.x + b.x, a.y + b.y, a.z + b.z)&lt;br /&gt;    static member inline scale (k: float) (a: Vec3d) = Vec3d(k * a.x, k * a.y, k * a.z)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type CVec1d (x: float) = class&lt;br /&gt;    member v.X = x&lt;br /&gt;&lt;br /&gt;    static member inline plus (a: CVec1d) (b: CVec1d) = CVec1d(a.X + b.X)&lt;br /&gt;    static member inline scale (k: float) (a: CVec1d) = CVec1d(k * a.X)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type CVec2d (x: float, y:float) = class&lt;br /&gt;    member v.X = x&lt;br /&gt;    member v.Y = y&lt;br /&gt;&lt;br /&gt;    static member inline plus (a: CVec2d) (b: CVec2d) = CVec2d(a.X + b.X, a.Y + b.Y)&lt;br /&gt;    static member inline scale (k: float) (a: CVec2d) = CVec2d(k * a.X, k * a.Y)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;type CVec3d (x: float, y: float, z: float) = class&lt;br /&gt;    member v.X = x&lt;br /&gt;    member v.Y = y&lt;br /&gt;    member v.Z = z&lt;br /&gt;    &lt;br /&gt;    static member inline plus (a: CVec3d) (b: CVec3d) = CVec3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z)&lt;br /&gt;    static member inline scale (k: float) (a: CVec3d) = CVec3d(k * a.X, k * a.Y, k * a.Z)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;let gravity = &lt;br /&gt;    -9.81&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let inline spring (pos: ^vec) =&lt;br /&gt;    let (*) k x = (^vec: (static member inline scale: float -&amp;gt; ^vec -&amp;gt; ^vec) k) x&lt;br /&gt;    let k = 100.0&lt;br /&gt;    -k * pos&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let inline drag k (pos: ^speed) (speed: ^speed) =&lt;br /&gt;    let (*) k x = (^vec: (static member inline scale: float -&amp;gt; ^vec -&amp;gt; ^vec) k) x&lt;br /&gt;    -k * speed&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let inline euler_implicit accel_func (pos: ^vec) (speed: ^vec) delta =&lt;br /&gt;    let (+) x y = (^vec: (static member inline plus: ^vec -&amp;gt; ^vec -&amp;gt; ^vec) x) y&lt;br /&gt;    let (*) k x = (^vec: (static member inline scale: float -&amp;gt; ^vec -&amp;gt; ^vec) k) x&lt;br /&gt;    &lt;br /&gt;    let speed2 = speed + (delta * (accel_func pos speed))    &lt;br /&gt;    let pos2 = pos + (delta * speed2)        &lt;br /&gt;    ps&amp;lt;_&amp;gt;(pos2, speed2)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let inline simulate intg_func t0 t_fin delta pos0 speed0 =&lt;br /&gt;    let oc = OptimizedClosures.FastFunc3&amp;lt;_,_,_,_&amp;gt;.Adapt(intg_func)&lt;br /&gt;    let rec repeat t0 pos0 speed0 =&lt;br /&gt;        if t0 &amp;gt; t_fin then (pos0, speed0)&lt;br /&gt;        else&lt;br /&gt;            let t1 = t0 + delta&lt;br /&gt;            let ps: ps&amp;lt;_&amp;gt; = oc.Invoke(pos0, speed0, delta)&lt;br /&gt;            repeat t1 ps.pos ps.speed&lt;br /&gt;    repeat t0 pos0 speed0&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;let inline accel (up: ^vec) (pos: ^vec) (speed: ^vec) =&lt;br /&gt;    let (+) x y = (^vec: (static member inline plus: ^vec -&amp;gt; ^vec -&amp;gt; ^vec) x) y&lt;br /&gt;    let (*) k x = (^vec: (static member inline scale: float -&amp;gt; ^vec -&amp;gt; ^vec) k) x&lt;br /&gt;    (drag 1.0 pos speed) + (spring pos) + (gravity * up)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let run euler_func s0 =&lt;br /&gt;    let t0 = 0.0&lt;br /&gt;    let t_fin = 1000.0&lt;br /&gt;    let delta = 0.005&lt;br /&gt;&lt;br /&gt;    let run_timed map_func = &lt;br /&gt;        let n_runs = 3&lt;br /&gt;        let times =&lt;br /&gt;            [&lt;br /&gt;                for i in 1..n_runs -&amp;gt;&lt;br /&gt;                    let (run_time, res) = run_time_func (fun () -&amp;gt; s0 |&amp;gt; map_func(fun (x, y) -&amp;gt; simulate euler_func t0 t_fin delta x y))&lt;br /&gt;                    run_time&lt;br /&gt;            ]&lt;br /&gt;        &lt;br /&gt;        let max = Seq.max times&lt;br /&gt;        let min = Seq.min times&lt;br /&gt;        let avg = (Seq.fold (fun x y -&amp;gt; x+y) 0.0 times) / float n_runs&lt;br /&gt;        (min, max, avg)&lt;br /&gt;&lt;br /&gt;    let single_min, single_max, single_avg = run_timed List.map&lt;br /&gt;    let multi_min, multi_max, multi_avg = run_timed map_parallel&lt;br /&gt;&lt;br /&gt;    printfn "Single (min, max, avg): %f %f %f" single_min single_max single_avg&lt;br /&gt;    printfn "Multi (min, max, avg): %f %f %f" multi_min multi_max multi_avg&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let n_bodies = 10&lt;br /&gt;&lt;br /&gt;let s0_Vec1d = [ for s in 1..n_bodies -&amp;gt; (Vec1d(float s), Vec1d(0.0)) ]&lt;br /&gt;let ef_Vec1d = euler_implicit (accel (Vec1d(1.0)))&lt;br /&gt;&lt;br /&gt;let s0_Vec2d = [ for s in 1..n_bodies -&amp;gt; (Vec2d(float s, 1.0), Vec2d(0.0, 0.0)) ]&lt;br /&gt;let ef_Vec2d = euler_implicit (accel (Vec2d(0.0, 1.0)))&lt;br /&gt;&lt;br /&gt;let s0_Vec3d = [ for s in 1..n_bodies -&amp;gt; (Vec3d(float s, 1.0, -1.0), Vec3d(0.0, 0.0, 0.0)) ]&lt;br /&gt;let ef_Vec3d = euler_implicit (accel (Vec3d(0.0, 1.0, 0.0)))&lt;br /&gt;&lt;br /&gt;let s0_CVec1d = [ for s in 1..n_bodies -&amp;gt; (CVec1d(float s), CVec1d(0.0)) ]&lt;br /&gt;let ef_CVec1d = euler_implicit (accel (CVec1d(1.0)))&lt;br /&gt;&lt;br /&gt;let s0_CVec2d = [ for s in 1..n_bodies -&amp;gt; (CVec2d(float s, 1.0), CVec2d(0.0, 0.0)) ]&lt;br /&gt;let ef_CVec2d = euler_implicit (accel (CVec2d(0.0, 1.0)))&lt;br /&gt;&lt;br /&gt;let s0_CVec3d = [ for s in 1..n_bodies -&amp;gt; (CVec3d(float s, 1.0, -1.0), CVec3d(0.0, 0.0, 0.0)) ]&lt;br /&gt;let ef_CVec3d = euler_implicit (accel (CVec3d(0.0, 1.0, 0.0)))&lt;br /&gt;&lt;br /&gt;let s0_One = [ for s in 1..n_bodies -&amp;gt; (One(float s), One(0.0)) ]&lt;br /&gt;let ef_One = euler_implicit (accel (One(1.0)))&lt;br /&gt;&lt;br /&gt;let s0_Two = [ for s in 1..n_bodies -&amp;gt; (Two(float s, 1.0), Two(0.0, 0.0)) ]&lt;br /&gt;let ef_Two = euler_implicit (accel (Two(0.0, 1.0)))&lt;br /&gt;&lt;br /&gt;let s0_Three = [ for s in 1..n_bodies -&amp;gt; (Three(float s, 1.0, -1.0), Three(0.0, 0.0, 0.0)) ]&lt;br /&gt;let ef_Three = euler_implicit (accel (Three(0.0, 1.0, 0.0)))&lt;br /&gt;&lt;br /&gt;printfn "1D (struct)"&lt;br /&gt;run ef_Vec1d s0_Vec1d&lt;br /&gt;&lt;br /&gt;printfn "2D (struct)"&lt;br /&gt;run ef_Vec2d s0_Vec2d&lt;br /&gt; &lt;br /&gt;printfn "3D (struct)"&lt;br /&gt;run ef_Vec3d s0_Vec3d&lt;br /&gt;&lt;br /&gt;printfn "1D (class)"&lt;br /&gt;run ef_CVec1d s0_CVec1d&lt;br /&gt;&lt;br /&gt;printfn "2D (class)"&lt;br /&gt;run ef_CVec2d s0_CVec2d&lt;br /&gt; &lt;br /&gt;printfn "3D (class)"&lt;br /&gt;run ef_CVec3d s0_CVec3d&lt;br /&gt;&lt;br /&gt;printfn "1D (union)"&lt;br /&gt;run ef_One s0_One&lt;br /&gt;&lt;br /&gt;printfn "2D (union)"&lt;br /&gt;run ef_Two s0_Two&lt;br /&gt; &lt;br /&gt;printfn "3D (union)"&lt;br /&gt;run ef_Three s0_Three&lt;br /&gt; &lt;br /&gt;ignore (Console.ReadKey(true))&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Here come the detailed explanations:&lt;br /&gt;&lt;div class="mycode"&gt;type VecN =&lt;br /&gt;    One of float&lt;br /&gt;[...]&lt;br /&gt;type CVec3d (x: float, y: float, z: float) = class&lt;br /&gt;    member v.X = x&lt;br /&gt;    member v.Y = y&lt;br /&gt;    member v.Z = z&lt;br /&gt;    &lt;br /&gt;    static member inline plus (a: CVec3d) (b: CVec3d) = CVec3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z)&lt;br /&gt;    static member inline scale (k: float) (a: CVec3d) = CVec3d(k * a.X, k * a.Y, k * a.Z)&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;These definitions show different ways to implement vector types. The first method, which uses a union, is a bit uncommon. It is inelegant because it does not take advantage of the type system to capture the fact that adding vectors of different dimensions is not allowed. It is also the slowest implementation of vectors of all.&lt;br /&gt;Follow definitions of one, two and three dimensional vectors using structs, which we already saw in the previous tutorial. The last group is almost identical, except for the fact that classes are used. I won't go into the &lt;a href="http://fsharpnews.blogspot.com/2007/05/structs-vs-classes.html"&gt;differences between structs and classes&lt;/a&gt; in this post, but it's interesting to see that structs are faster in this program. This is however not generally true, even when considering only the special case of 3d vectors.&lt;br /&gt;&lt;br /&gt;The interesting part starts below.&lt;br /&gt;&lt;div class="mycode"&gt;let inline spring (pos: ^vec) =&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;This defines a generic function "spring" taking a parameter of type "^vec". Note that "vec" here is not an actual type, but a type variable. We have already used the notation " 'vec", which plays a similar role. The difference resides in who creates the concrete function. In the case of " 'vec", this is handled by the generics mechanics in the .NET runtime. In the present case, using "^vec", it is handled by the F# compiler.&lt;br /&gt;(QUESTION: is that correct? I tried replacing "^vec" with "'vec" in this line, and that worked too.)&lt;br /&gt;This requires the function to be declared as inline. The compiler will generate a new copy of the code for each concrete type with which it is used.&lt;br /&gt;For further details about type constraints, see &lt;a href="http://www.atrevido.net/blog/2008/08/31/Statically+Typed+Duck+Typing+In+F.aspx"&gt;Statically typed duck typing in F#&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;    let (*) k x = (^vec: (static member scale: float -&amp;gt; ^vec -&amp;gt; ^vec) k) x&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I will start with the part of the line after the "=" symbol. It constitutes a type constraint, and means that "^vec" must have a static member named "scale", accepting a float and returning a function from "^vec" to "^vec" (in other words: a function taking a float and a "^vec" and returning a "^vec").&lt;br /&gt;The rest of the line defines a function "*", thus overloading the multiplication operator, which allows us to write expressions in a natural way. Note that this method could also have been used in Tutorial 8, its availability is not subject to the use of type constraints.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;    let k = 100.0&lt;br /&gt;    -k * pos&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Finally something we recognize...&lt;br /&gt;&lt;br /&gt;You may have noticed that unlike Tutorial 8, this tutorial includes the optimizations from Tutorial 7 and 7b (aggressive inlining and OptimizedClosures). They do seem to make a difference here.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update:&lt;/span&gt;&lt;br /&gt;This Tutorial used to include a section comparing the performance of the F# and the C++ versions of Euler using doubles and structs (for 1-, 2- and 3-dimensional vectors). I noticed the timing results depended very much on whether the programs were started from Visual Studio or directly from Windows. C++ programs using .NET are faster when started from Visual studio, whereas F# programs run faster when started outside of Visual Studio. The differences were large enough to render comparisons meaningless, and I have therefore decided to remove the benchmark results until I have cleared that up.&lt;br /&gt;&lt;br /&gt;I have kept the most original method to write generic code for the next Tutorial. Stay tuned!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3205414380859703216-3605429990910194637?l=sharp-gamedev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sharp-gamedev.blogspot.com/feeds/3605429990910194637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3205414380859703216&amp;postID=3605429990910194637' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3605429990910194637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3205414380859703216/posts/default/3605429990910194637'/><link rel='alternate' type='text/html' href='http://sharp-gamedev.blogspot.com/2008/09/tutorial-9-generic-programming-using.html' title='Tutorial 9: Generic programming using type constraints'/><author><name>Joh.</name><uri>http://www.blogger.com/profile/11997760819395618904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_nDGpBaX7_xg/SMtsHWn8kgI/AAAAAAAAAVs/LLhB2sz6yXA/S220/g_raf2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3205414380859703216.post-5677755152132599508</id><published>2008-09-22T12:58:00.000-07:00</published><updated>2010-12-05T14:10:06.633-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Tutorial 8: Generic programming, functional approach</title><content type='html'>I have decided to continue this series by extending the integrator to handle 2d and 3d. One of the annoyances an amateur game developer encounters is the multiplication of 3d vector classes. They all use the same data layout, all offer the same methods, all offer the same performance, yet there is at least one such class per library. For instance, in my &lt;a href="http://www.top10-racing.org/"&gt;go-kart racing game&lt;/a&gt;, I have to deal with 3d vectors in OpenAL, 3d vectors in CGAL (which I used for DeLaunay triangulation), and should I start using ODE (a physics library), I'll have to deal with yet another type of 3d vectors. To make things worse, I am myself guilty of having implemented my own 3d vector math library.&lt;br /&gt;&lt;br /&gt;The type inference feature in F# makes it easy to avoid introducing yet another 3d vector class. When the obligation to explicitly annotate all your variables with types disappears, writing polymorphic code becomes easy.&lt;br /&gt;&lt;br /&gt;What approaches do we have to write generic code?&lt;br /&gt;- the object-oriented approach based on interfaces, classes and method overriding,&lt;br /&gt;- what I would call the functional approach,&lt;br /&gt;- the template approach (in C++ terminology) also known as the generics approach (Java, .Net and friends terminology), and&lt;br /&gt;- an approach which I have never seen yet (in compiled languages), which I will call the meta-programming approach.&lt;br /&gt;&lt;br /&gt;I will skip over the first method, mostly because it has already abundantly been described and explained.&lt;br /&gt;The second method is the subject of this Tutorial, and is also described in chapter 5 of &lt;a href="http://www.amazon.com/Expert-F-Experts-Voice-Net/dp/1590598504"&gt;Expert F#&lt;/a&gt;&lt;br /&gt;The third method will be explored in the next Tutorial, and I am keeping the fourth method, the most exciting, for the last of the tutorials dedicated to generic programming.&lt;br /&gt;Normally I would have started by showing the code, but in this case I thought I needed to justify why I should change the code at all. Especially if you come from C++, you might think that running the integration in 2d or 3d would just be a matter of changing the kind of vectors passed to the "simulate" and "accel" functions. As long as the new vector types support "operator+" and "operator*" we should be fine.&lt;br /&gt;You would be wrong. Consider:&lt;br /&gt;&lt;div class="mycode"&gt;let x = 0.5 * a&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I am not sure of the reasons behind this design decision, but in F#, this means that "a" and "x" are inferred to be the same type as 0.5, which is float. Moreover, the multiplication operator is now constrained to be applicable only on floats. That's right, you are no longer allowed to write "2 * 3". Like it or not, that's the way it is.&lt;br /&gt;&lt;br /&gt;In practice, this means that I am probably best off avoiding operators + and *. Instead, the caller of my functions will have to tell them what functions to use to perform arithmetic operations.&lt;br /&gt;&lt;br /&gt;OK, enough talk, here comes the co
