Reputation: 2973
I'm trying to code a type to represent a pointer in GPU device, and it should act like an array, with indexed property for get and set. I get no problem if the element type is a primitive type, but when I use a struct, I cannot change its member's value.
See this code:
#nowarn "9"
open System
open System.Runtime.InteropServices
[<Struct;StructLayout(LayoutKind.Sequential)>]
type MyStruct =
val mutable x : int
val mutable y : int
val mutable z : int
override this.ToString() = sprintf "(%d,%d,%d)" this.x this.y this.z
let deviceOnly() = failwith "this function should be used in quotation only"
type DevicePtr<'T>(h:nativeint) =
member this.Handle = h
member this.Item with get (idx:int) : 'T = deviceOnly() and set (idx:int) (value:'T) : unit = deviceOnly()
member this.Reinterpret<'T2>() = DevicePtr<'T2>(h)
member this.Volatile() = DevicePtr<'T>(h)
static member (+) (ptr:DevicePtr<'T>, offset:int) = DevicePtr<'T>(ptr.Handle + nativeint(offset * sizeof<'T>))
let test() =
let mutable test1 = MyStruct()
test1.x <- 1
let foo (collection:MyStruct[]) =
collection.[0].x <- 1
let bar (collection:DevicePtr<MyStruct>) =
collection.[0].x <- 1
//error FS0257:
// Invalid mutation of a constant expression.
// Consider copying the expression to a mutable local, e.g. 'let mutable x = ...'.
So, the type is DevicePtr<'T>, and it has indexed property Item with both get and set method. but the get method just return a value of 'T, so I cannot mutate it. But the system array works.
Anyone has some experience like this? to create a type works like array? which I hope the get function of the indexed property return a mutable ref instead of a value.
Upvotes: 1
Views: 261
Reputation: 6155
You cannot create a type that works with structures like an array because the language and runtime give special handling to arrays that other classes do not get.
With an array, an expression accessing an element that is a structure, as in your foo
function, causes the element to be directly modified in place. The collection.[0]
is effectively setting up a "pointer" or "reference" to an element that the .x
expression is then applied to, allowing you to manipulate the object in place.
For other classes, the indexer is just another function, meaning a copy of the value is being returned. So in the bar
function, the collection.[0]
creates a copy of the value returned instead of the reference you get from the array. Because the .x
would be modifying the temporary copy, the compiler issues the error you see. (A very similar warning would occur in C# or VB for similar code.) As the message suggests, you will need to create a variable to hold the copy, modify the copy, and assign it back to collection.[0]
.
Upvotes: 2