If you use ASP.NET MVC with F# CTP (Monday brings Beta 1 and probably many changes), you might run into an issue of how to scope certain things. For example, an IDisposable is used to create blocks, for things like an HTML form. Example in C#:
<% using (Html.BeginForm()) {%>
<fieldset><legend>Fields</legend>...</fieldset>
<% } %>
This is needed because VB and C# didn't have any easy function/block syntax (VB 10 should fix this), and many C# developers are still wary of higher order functions. How does this play out in F#? First off, whitespace is important. This can get really messy with the current F# ASP.NET integration. Basically, always open the script blocks on a separate line, and indent from the first column. Example:
<% let i = 0 this.Response.Write(sprintf "i = %d" i) %>
<% let i = 0
this.Response.Write(sprintf "i = %d" i) %>
(Note that the 'this' variable is bound to the current page.) This fails:
Compiler Error Message: FS0010: Unexpected keyword 'let' or 'use' in expression. Expected incomplete structured construct at or before this point or other tokenSource Error:
Line 111: let mutable parameterContainer = parameterContainer Line 112: __w.Write("\r\n") |> ignore Line 113: let i = 0 Line 114: this.Response.Write(sprintf "i = %d" i) Line 115: __w.Write("\r\n <h2>Create</h2>\r\n\r\n ") |> ignore
Note how the <% is counted as space, so the let starts off indented 3 spaces. Instead, we need to write it so:
<%
let i = 0
This works fine. You can also put the %> on the next line if you like. Now, on to ASP.NET MVC's IDisposable usage. A straightforward use of the F# using function won't work:
<b>Demo</b> <% using (Mvc.Html.FormExtensions.BeginForm this.Html) (fun _ -> %> <p>Inside a form</p> <% ) %>
<b>Demo</b>
using (Mvc.Html.FormExtensions.BeginForm this.Html) (fun _ -> %>
<p>Inside a form</p>
<% ) %>
Compiler Error Message: FS0191: The mutable variable '__w' is used in an invalid way. Mutable variables may not be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via 'ref' and '!'.Source Error:
Line 114: __w.Write("\r\n\r\n<b>Demo</b>\r\n\r\n") |> ignore Line 115: Line 116: using (Mvc.Html.FormExtensions.BeginForm this.Html) (fun _ -> Line 117: __w.Write("\r\n\r\n <p>Inside a form</p>\r\n\r\n") |> ignore Line 118: )
As the error says, this is because the __w variable is mutable, so we can't play with it inside a lambda. I'm not sure if this will be worked around -- they'd have to change the codegen quite a bit, I'd think. As a side note, the F# CTP does not support C# extension methods (hence the verbose calling of BeginForm), but F# will eventually -- maybe in the Beta.
The way we must scope is with a use binding. There's no way I see to accomplish this with whitespace alone. Due to the ASPX translation process, this would probably be very error prone. Instead, we can simply put the use binding inside a do expression:
<b>Demo</b> <% do (use form = Mvc.Html.FormExtensions.BeginForm this.Html %> <b>Inside the form</b> <% ) %> <b>Outside of the form</b>
do (use form = Mvc.Html.FormExtensions.BeginForm this.Html %>
<b>Inside the form</b>
<b>Outside of the form</b>
The parentheses setup the scope exactly how we want it.
Remember Me