Pages

Sunday, April 29, 2012

Metro portable sample published

Our team provides a metro spreadsheet application with portable library. The new F# 3.0 does support portable library which is currently a way to write Win8 app using F#. The portable library hosts all the logic and the UI logic is still in the application, which is a clean cut for the F# library and front-end UI.




Monday, April 23, 2012

A Trick in F# Interop

When I try to crack the .CAB file, I found the COM interop in F# is different from C#.

the code sample in C# like the following code after adding "Microsoft Shell Controls And Automation" from "COM" tab.


bool ExpandCabFile(string CabFile, string DestDir)
    {
      if (!Directory.Exists(DestDir)) return false;
      Shell sh = new Shell();
      Folder fldr = sh.NameSpace(DestDir);
      foreach (FolderItem f in sh.NameSpace(CabFile).Items()) fldr.CopyHere(f, 0);
      return true;
    }


It should be straightforward to transform from this C# to F#. But it turns out the Shell cannot be created because it is an interface! Yes, you are not reading a typo. Shell is a interface if you use the Object Viewer.

The C# side can pick up the CoClass attribute so the new statement is calling into the ShellClass. Actually you cannot new ShellClass in C# code.


    [CoClass(typeof(ShellClass))]
    [Guid("866738B9-6CF2-4DE8-8767-F794EBE74F4E")]
    public interface Shell : IShellDispatch5
    {
    }

In F# side, you have to create ShellClass instead of Shell. So if you want to convert C# code which involves COM component to F# code, try to find the real class by finding the CoClass attribute. The complete F# code is listed below:


    let shell = new ShellClass()
    let folder = shell.NameSpace(Path.GetDirectoryName(fn))
    let fileName = Path.GetFileName(fn)
    let currentFolder =
    if not (Directory.Exists currentFolder) then
        Directory.CreateDirectory currentFolder |> ignore
    for item in shell.NameSpace(fn).Items() do
        folder.CopyHere(item, 0)


Saturday, April 21, 2012

Self Note: Word 2010 field

As my book is adding more and more listings, figures, and tables. It was so bad that I cannot use cross-reference because of the template restriction. I am forced to find a way to define something can increase automatically and can be referenced.

OK, first define something to automatically increase. The "seq" field is what I chose. SEQ chapter1List is used to define a list sequence.

Secondly, I need to find a way to do reference. I select the text needs to be referenced and set it as a Bookmark. When the cross-reference can work. 

Word fields are not updated automatically. Use Ctrl+A to select all and F9 is the way to update all fields.


Thursday, April 19, 2012

XML document on F# primary constructor


XML document on primary constructor is not supported. The workaround is to define another constructor with a dummy parameter. See the following sample code

/// my xml doc
type A(args) =
               

// change to the following code with a dummy parameter
type A private(args, _dummyParameter:unit) =
                /// docs
                new(args) = A(args, ())

Friday, April 13, 2012

Execution of Static Initializers

I have been struggling with the following code for days. Now it is clear that it is by design.

If you create a project with two files, one is File1.fs and the other is Program.fs. Put the following code in the File1.fs

namespace BB
// define a Point2D class with parameterized primary contructor
type Point2D(xValue:double, yValue:double) =
    // define a static field named count
    static let mutable count = 0
   
type Screen() =
    let points = System.Collections.Generic.List < Point2D > ()
    member this.Item with get(x:int) = points.[x]
                     and set(x:int) (v) = points.[x] <- v
module TestModule =
    let screen = Screen()
    let r2 = screen.[0]
and create the Point2D class in Program.fs.
let a = BB.Point2D()
When you run it you are going to bump into an exception about TypeInitializationException. OK, please move your staring eyes down to the TestModule, even it is 300 lines down below. screen.[0] is access a non-existing element. 


Do if a static variable is initialized, the module is also executed. So next time when you see this wired error, you  need to look around OR open the inner exception's call stack information. 


Thursday, April 12, 2012

Auto-Implement Property and Constructor do binding in Beta

From the previous F# auto-implemented property post, that property declaration shortcut does provide convenience to developer. However, when it combines with the constructor, there are something interesting.


type A() as this =
    do this.Bar()
    // let Y@ = 0
    member this.Bar() = printfn "In F()"
    //member val Y = 0 with get,set

let a = new A()

The code above works. But when you uncomment the auto-implemented property. The code compiles but will spite out an error at the printfn.




type A() as this =
    do this.Bar()

    // let Y@ = 0
    member this.Bar() = printfn "aaa"  //error!
    member val Y = 0 with get,set

let a = new A()


System.InvalidOperationException occurred
  HResult=-2146233079
  Message=The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized.
  Source=FSharp.Core
  StackTrace:
       at Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.FailInit()
  InnerException: 
I was confused by the error message at first glance. where is the object or value needs to be initialized? Actually this error says the A class cannot be initialized. If you want to ask why?

The auto-implemented property put a hidden backend field right after the do binding section. The commented out line after the do this.Bar() is the hidden code. As a result, when do binding is trying to execute this.Bar(), there is still one field, Y@,  needs to be initialized. Because one of the fields needs to be initialized, the instance is not initialized. That's how you get this error. 


This exists in Beta. So if you run into this problem, do not panic. you can try to use the old way to define the property.