Right. Good point. Setting fields directly in structs reveals this limitation.

Workaround 1: Provide a method to set the field

1
2
3
4
5
6
7
8
9
10
11
12
13
 

type Test = struct
    val mutable v: int
    
    member x.SetV(y) = x.v <- y
end
let incrTest (t: Test) =
      let mutable t2 = new Test() 
      t2.SetV(t.v + 1) // gives error
      t2

Workaround 2: Provide a setter property

1
2
3
4
5
6
7
8
9
10
11
type Test = struct
    val mutable v: int
    
    member x.V 
        with get() = x.v
        and  set(y) = x.v <- y
end
let incrTest (t: Test) =
      let mutable t2 = new Test() 
      t2.V <- t.v + 1 // gives error
      t2

Bug noted and will be fixed. Thanks as always :-)

Kind regards

don

By on 11/9/2007 3:35 PM ()

I was hoping this isn't a bug, but thanks for the quick answer.

Actually, I was experimenting with structs and mutation to get away from properties for optimization purposes, though F# with its obligatory getter-setters doesn't make this easy. The problem is that the .Net JIT has various limits with regard to inlining in general and structs in particular. For example, with the exception of pointer-size ints it cannot inline functions with value-type arguments (!!) (though the next CLR version supposedly fixes this) and there are limits with regard to how many consecutive calls are inlined, so that indirecting every field access through a function won't help performance. There is also the 32 byte code inlining limit, which a constructor for a struct with multiple fields will quickly exceed. In summary, the most performant way to deal with structs is to create them with the default constructor and to subsequently directly assign to and read from the fields. It would be great if F# allowed this kind of operation at least for structs, though I'd prefer to have the choice between properties and fields in classes too.Stephan

By on 11/9/2007 4:39 PM ()

Got it - thanks for the analysis.

We've been considering adding a "UseGenuineField" attribute to disable the generation of getter/setter properties and ensure a field of precisely the given name is generated. This is useful in codegen and other scenarios (e.g. CodeDom), and the above gives added reason to do this. This should also perhaps be the default representation for mutable fields in structs.

There are several reasons we generate properties for record and class fields. One is to make the "readonly" nature of immutable fields plain by only revealing a getter property. Another is that we are likely to make records match a signature that specifies only properties of a type: this is a very useful implementation technique, and of course we need matching compilation representations in order to do this.

Kind regards

Don

By on 11/9/2007 9:59 PM ()

Such an attribute would be great. For the meantime, is there maybe any hack to directly access the underlying _field without the getter, other than using C#? I need to use a struct within a struct (potentially within a struct), so I really can't afford properties. I tried inline MSIL but it doesn't seem to accept "ldfld"...

Thanks,
Stephan

By on 11/10/2007 9:47 AM ()

Hi Stephan,

I should have said in my answer to your original post that the intent of the error message was to get you to write your code in this kind of way, i.e. using an immutable struct:

1
2
3
4
5
6
7
8
9
10
11
12
13
 

type Test = 
  struct
    val v: int
    new(v) = { v = v }
    
  end
let incrTest (t: Test) =
    let mutable t2 = new Test() 
    t2 <- new Test(t.v + 1) // gives error
    t2

However there are of course situations where mutable structuis are useful, e.g. especially if the structs get large.

Kind regards

Don

By on 11/13/2007 10:36 AM ()

I don't know what you need to do, but you might consider the following syntax (I have no idea about its efficency):

1
2
3
4
5
6
7
8
9
10
11
12
type Test = {mutable v: int}

let incrTest t =


    let t2 = {v = 0}


    t2.v <- t.v + 1


    t2

or just:

1
2
3
let incrTest t = {v = t.v + 1}

Laurent.

By on 11/9/2007 4:52 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper