Thursday, November 26, 2009

F# under the covers XI -- Literal expressions that aren't; attributes that don't

The problem with being unable to attribute just the getter or setter of a property is resolved at the 1.9.9.9 release (February 2010 CTP).

Consider the following simple C# property

public static FileShare get_Options()
{
return (FileShare.Delete | FileShare.Write);
}
view raw gistfile1.cs hosted with ❤ by GitHub

This compiles in debug mode to

.method public hidebysig specialname static valuetype [mscorlib]System.IO.FileShare get_Options() cil managed
{
.maxstack 1
.locals init (
[0] valuetype [mscorlib]System.IO.FileShare CS$1$0000)
L_0000: nop
L_0001: ldc.i4.6
L_0002: stloc.0
L_0003: br.s L_0005
L_0005: ldloc.0
L_0006: ret
}
view raw gistfile1.cs hosted with ❤ by GitHub

which assigns the literal result -- 6 -- of the expression to the temporary that is then returned. The analogous F# method

static member Options with get() = System.IO.FileShare.Delete ||| System.IO.FileShare.Write
// or equivalently
static member Options = System.IO.FileShare.Write ||| System.IO.FileShare.Delete
view raw gistfile1.fs hosted with ❤ by GitHub

compiles to IL which preserves the expression to execute only at run time:

.method public specialname static valuetype [mscorlib]System.IO.FileShare get_Options() cil managed
{
.maxstack 4
L_0000: nop
L_0001: ldc.i4.2
L_0002: ldc.i4.4
L_0003: or
L_0004: ret
}
view raw gistfile1.cs hosted with ❤ by GitHub

which makes static analysis of the code in the more usually analysed state a rather more complicated business.

Another complicating factor is that while this syntax

[<...>]
static member Options = System.IO.FileShare.Write ||| System.IO.FileShare.Delete
view raw gistfile1.fs hosted with ❤ by GitHub

builds, it attaches the attribute (with Method and Constructor usage only) to the property as a whole; and not the generated get_Options method, as in

[...]
public static FileShare Options
{
get
{
return (FileShare.Write | FileShare.Delete);
}
}
view raw gistfile1.cs hosted with ❤ by GitHub

What I'd like to express, and what I've not found a way to express, is

public static FileShare Options
{
[...]
get
{
return (FileShare.Write | FileShare.Delete);
}
}
view raw gistfile1.cs hosted with ❤ by GitHub

and MSDN remains opaque on the subject as well.

This is something I could code around, but I can't yet see a clean way of doing to allow separate attributes on the getters and the setters.

Later: The intended syntax for this option is, much as you might expect, this:

static member Options
with [<...>] get() =
System.IO.FileShare.Write ||| System.IO.FileShare.Delete
view raw gistfile1.fs hosted with ❤ by GitHub

with the necessary insets as shown (to avoid error FS0010: Incomplete structured construct at or before this point in pattern), however on filing a bug report I got confirmation that it is a known issue with the Beta 2 release (aka October 2009 CTP), that this still decorates the property and not just the getter.

2 comments :

Anonymous said...

Doesn't this work as expected ?

static member Options with
  [< CoverageExemption( Points = 1, Justification = "Code generated is not a Literal") >]get() =
     System.IO.FileShare.Write ||| System.IO.FileShare.Delete

Steve Gilham said...
This comment has been removed by the author.