Declare the nativeptr<unit> type - f#

I'd like to know if it's possible in F# to declare the type:
nativeptr<unit>
This seems not possible (compiler complains with "A generic construct requires that the type 'unit' is an unmanaged type"). Is there a workaround I could use?
The ultimate goal is to declare my own blitDelegate for exposing the opcode Cpblk to some of my F# code.
Thanks.
Edit:
Here's what I've tried based on kvb's answer:
type blitDelegate<'T when 'T : unmanaged> = delegate of nativeptr<'T> * nativeptr<'T> * uint32 -> unit
let createBlitDelegate<'T when 'T : unmanaged>() =
let dm = new DynamicMethod("blit",
typeof<System.Void>,
[| typeof<nativeptr<'T>>; typeof<nativeptr<'T>>; typeof<uint32> |])
let ilGenerator = dm.GetILGenerator()
ilGenerator.Emit(OpCodes.Ldarg_0)
ilGenerator.Emit(OpCodes.Ldarg_1)
ilGenerator.Emit(OpCodes.Ldarg_2)
ilGenerator.Emit(OpCodes.Cpblk)
ilGenerator.Emit(OpCodes.Ret)
dm.CreateDelegate(typeof<blitDelegate<'T>>) :?> blitDelegate<'T>
let blit (blitDel:blitDelegate<'T>) dst src byteWidth = blitDel.Invoke(dst, src, byteWidth)
Then I call this code from a class member like that:
let dst = //get nativeint destination address
let src = //get nativeint source address
let bd = createBlitDelegate<'T>()
let tdst = NativePtr.ofNativeInt<'T> dst
let tsrc = NativePtr.ofNativeInt<'T> src
do blit bd tdst tsrc (uint32 size)
//Program.MemCpy.Invoke(dst.ToPointer(), dst.ToPointer(), uint32 size)
This results in a runtime error at blit (System.Security.VerificationException: Operation could destabilize the runtime.)
The commented code works well (and can be found here) but my point was to code it in F# (not C#).
The reason why I wanted to use at first a nativeptr<unit> is that it is actually the type of the two first arguments of MemCpy delegate (that matches void* type) and somewhat wanted to mimic it.
Edit2:
Based on kvb's edit, I modified my code to host the delegate creation in a type using static members (like the C# version) and it now works.
I don't use the version with the unmanaged constraint but this one, since I actually need to blit array of structs:
type blitDelegate = delegate of nativeint * nativeint * uint32 -> unit

From your description, it's not clear to me why you'd like a nativeptr<unit>. Essentially, nativeptr<'t> is just a thin wrapper over nativeint with some helpers for doing arithmetic on the pointer. Since you're unlikely to have an array of units, I don't see how this actually helps you, though. Perhaps if you show more of your code it will be easier to give a more satisfactory answer.
EDIT
I think you're doing almost everything right. However, anonymously hosted DynamicMethods must be verifiable, and the cpblk opcode is never verifiable. Try using a different constructor for DynamicMethod to host it on a type or module.

Related

How to use Akka.Streams.*.ConcatMany in F#?

I want to create a flow that creates a new source (it will be a persistence query) out of incoming elements, and then flattens the results. Something like this simplified example:
var z = Source.Single(1).ConcatMany(i => Source.Single(i));
this code compiles and works as expected. My problem is that when I translate it to F#:
let z = Source.Single(1).ConcatMany(fun i -> Source.Single(i))
I get an error saying
This expression was expected to have type
'IGraph<SourceShape<'a>,Akka.NotUsed>'
but here has type
'Source<int,Akka.NotUsed>'
I think that the cause of that is that F# handles co/contravariance differently than C# and cannot simply convert these generic specializations (https://github.com/fsharp/fslang-suggestions/issues/162), but I cannot figure out a way to make a convertion between an int and a SourceShape<int>. Is it possible to convert this example to F#?
Looking at the code on GitHub, it appears that Source<TOut, TMat> is a direct implementation of IGraph, so you should just be able to cast it:
public sealed class Source<TOut, TMat> : IFlow<TOut, TMat>, IGraph<SourceShape<TOut>, TMat>
let z = Source.Single(1).ConcatMany(fun i -> Source.Single(i) :> IGraph<SourceShape<int>,Akka.NotUsed>)
I think the biggest difference between the C# and F# usage is that C# will automatically do the upcast for you.
One workaround that I found is to use Akkling.Streams wrapper library:
open Akkling.Streams
let x =
Source.singleton 1
|> Source.collectMap(fun x -> Source.singleton x)
the question how to do this without Akkling remains open.

byref return in F# 4.5

I am trying to add a F#-style interface to a type, that has a byref return method.
Here's the code:
type IPool<'P, 'T when 'T: struct> =
abstract member GetReference: ITypedPointer<'P, 'T> -> byref<'T>
let Ref<'TPool, 'P, 'T when 'TPool :> IPool<'P, 'T>> (pool: 'TPool) pointer =
pool.GetReference pointer
Now to my surprise, a similar thing worked fine until I introduced IPool interface. Before that Ref itself contained an implementation like &pool.data.[idx], and worked fine.
I tried installing nightly build of F# Tools, cause latest release does not officially support byref returns, and PR to introduce them was recently completed: https://github.com/Microsoft/visualfsharp/pull/4888
However, I still get error FS3209: The address of the variable 'copyOfStruct' cannot be used at this point. A method or function may not return the address of this local value. in Visual Studio. Type outref<T> still does not seem to be available either. Am I missing something?
I also tried to drop the pointer parameter, and just return pool.GetReference to only get a different error message.
Addition: the ultimate goal is to be able to do
let aref = Ref pool ptr
let bref = Ref pool ptr
aref <- 42
assert(aref = bref)
e.g. give caller a direct reference to an internal memory, usually backed by an array, similar to Span<T>. I am making this for performance reasons, so it is not OK to allocate on every call to Ref.
For some reason, reducing generalization helped to get rid of the error:
let Ref<'P, 'T when 'T: struct> (pool: IPool<'P, 'T>) pointer = pool.GetReference pointer
Solution provided by
https://github.com/Microsoft/visualfsharp/issues/5366#issuecomment-407521220
Though it does not explain why the original code does not compile.
I don't think it's standard practice to return a byref type. This type is really meant for method parameters, mostly for C# interop with out or ref parameters. Take a look at this StackOverflow question for a good explanation.
What you can do is change the method on your interface to take a tuple of ITypedPointer<'P,'T> and byref<'T> (usage of byref is not allowed with curried parameters) and return unit instead. Then you can call GetReference like any standard .NET method with an out parameter in C#. That would look something like this:
type ITypedPointer<'P, 'T> = interface end
type IPool<'P, 'T when 'T: struct> =
abstract member GetReference: ITypedPointer<'P, 'T> * byref<'T> -> unit
let Ref<'TPool, 'P, 'T when 'TPool :> IPool<'P, 'T>> (pool: 'TPool) pointer =
let mutable value = Unchecked.defaultof<'T>
pool.GetReference(pointer, &value)
value

Error FS0037 sometimes, very confusing

If I write the following F# code, the compiler issues an error.
let a = 123
let a = 123
The error produced is:
error FS0037: Duplicate definition of value 'a'
If I write the same code in a function like this:
let fctn =
let a =123
let a =123
a
it doesn't produce any error.
I don't understand the difference. Can anyone please explain?
Edit : first code I write in module level.
I agree this is confusing. The problem is that let behaves differently when it is used as a local variable (within a function) and when it is used as a global definition (within a module).
Global definitions (in a module) are compiled as static members of a static class and so a name can be used only once. This means that top-level use of:
let a = 10
let a = 11
... is an error, because F# would have to produce two static members of the same name.
Local definitions (inside a function or some other nested scope) are compiled to Common IL and the variable name essentially disappears (the IL uses the stack instead). In this case, F# allows you to shadow variables, that is, you can hide a previous variable by re-using an existing name. This can be inside a function, or even just a do block inside a module, type or other function:
do
let a = 10
let a = 11
()
This is a bit confusing, because variable shadowing only works inside local scopes but not at the top level. It makes sense when you know how things are compiled though.
As an aside, while IL allows overloads of members by the same name, such overloads cannot be defined at module level in F#. Instead, you'd need to define them specifically as static member on a class (type in F#).
on scope and shadowing
as CaringDev mentioned (but not explained) you will probably see what the shadowing is about when you make the scope a bit more obvious (using the let ... in ... construct #light let you shorten a bit - but you still can use it even without #light off)
Try this:
> let a = 233 in let a = 555 in a;;
val it : int = 555
as you can see the expression evaluates to the shadowed value of a - but the original is not lost:
> let a = 233 in (let a = 555 in a), a;;
val it : int * int = (555, 233)
it's just not in scope in the inner let ... in ...
btw: you can rewrite your example to:
let fctn =
let a = 123 in
(let a =123 in a)
(I added the parentheses just to make this more obvious)
the other on the module level really defines a value for the scope of the module and is not really an expression but a definition
The first snippet defines two public values with the same name.
The second hides (shadows) a value.
With the first you would have externally visible change of state (a behaves like mutable) whereas with the second you can't (you have two as in different scopes).
If you write your statements in #light off ML syntax it becomes obvious immediately.

Why does the F# compiler give an error for one case but not the other?

I'm working on a platform invoke call from F#, and I am getting a compiler error I really can't make that much sense out of. First, let me show the C signature of what I am doing:
int Foo(
ULONG_PTR *phHandle,
DWORD flags
);
In F#, I think the correct way to invoke this natively is as so:
[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
(
[<Out>]nativeint& phHandle,
uint32 flags
)
If I try to call this in a class, I get a compilation error when calling it like so:
type Class1() =
[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
(
nativeint& phHandle,
uint32 flags
)
member this.Foo() =
let mutable thing = nativeint 0
APlatformInvokeCall(&thing, 0u) |> ignore
thing
The error is:
A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Weirdly, when I do this all in a module, the compilation errors go away:
module Module1 =
[<DllImport("somedll.dll")>]
extern int APlatformInvokeCall
(
nativeint& phHandle,
uint32 flags
)
let Foo() =
let mutable thing = nativeint 0
APlatformInvokeCall(&thing, 0u) |> ignore
thing
Why does this compile as a module, but not as a class?
I don't think it's valid to define an extern method within a class in F#.
If you pull up the F# 3.0 language specification and search for DllImport, near the bottom is a table listing some special attributes and how they can be used. The text for [<DllImport>] says:
When applied to a function definition in a module, causes the F# compiler to ignore the implementation of the definition, and instead compile it as a CLI P/Invoke stub declaration.
That seems to indicate that it's only valid to declare extern methods (that use [<DllImport>]) on functions defined in a module; it doesn't say anything about class members though.
I think you're running into a compiler bug. Please submit this code to fsbugs#microsoft.com so they can fix the error message emitted by the compiler -- it should really be giving you an error about defining an extern method in a class since that's not allowed by the language spec.
Whether this is a bug not withstanding, maybe this is what's going on: If APlatformInvokeCall were considered a static member function, that member have a single argument of tuple type. Tuples are compiled into objects of generic type (see here, at the bottom, or 5.1.3 in the spec). In this case that tuple is
System.Tuple<nativeint&, uint32>
But ECMA 335 II.9.4 says you can't instantiate generic types at byref types. This explains the error reported.
This explanation fits the fact mentioned above that Class1 works (well, compiles) if you modify the extern declaration and call to take instead a single argument. It also fits the fact that the module version works, since in that version there is no considering APlatFormInvokeCall a member function.
The simple solution is to check the spec, here is the class definition grammar:
type type-name pat_opt as-defn)opt =
class
class-inherits-decl_opt
class-function-or-value-defns_opt
type-defn-elements
end
then we have
class-function-or-value-defn :
attributes_opt staticopt let rec_opt function-or-value-defns
attributes_opt staticopt do expr
which doesn't allow extern.
and
type-defn-element :
member-defn
interface-impl
interface-signature
which isn't what you want either.
As a result, we can see that using extern as you are trying to use it can't be done inside a class.

Why is F# inferring my function implements IComparable?

I'm a hobbyist programmer (cook by trade) that's currently trying to teach myself F# and functional programming in general.
Anyway, I was fooling around with DeflateStream and wrote the following two functions:
let Compress compressMe =
let ds = new DeflateStream(File.Create("compressed.txt"), CompressionMode.Compress)
File.OpenRead(compressMe).CopyTo(ds)
ds.Close()
let Decompress =
let ds = new DeflateStream(File.OpenRead("compressed.txt"), CompressionMode.Decompress)
ds.CopyTo(File.Create("decompressed.txt"))
ds.Close()
In the body of the main function they are called one right after the other like this:
Compress args.[0]
Decompress
However, if compressed.txt doesn't exist when the program is run Decompress throws a FileNotFoundException which is surprising because the only thing that could throw this is the call to File.OpenRead("compress.txt"). After about an hour I figured out that Decompress was implementing IComparable and was being executed before the call to it in the main function. I found that by changing its definition to let Decompress () = [...] it no longer implemented IComparable and my code executed as it was intended to. Can anyone tell me why F# was infering IComparable and why such and inference would cause the function to execute before the main function marked with [<EntryPoint>]? Also, please forgive the imperitive style of my code, I'm incredibly new at this.
Thanks in adavance.
I'm not entirely sure about the IComparable bit, but the issue you have is that without the parentheses, the compiler is treating Decompress as a value not a function. This would be similar to if you had written.
let compressedName = "compressed.txt"
in that case, compressedName is now a value. Adding the parentheses tells the compiler that this is a function whose code must be called each time the function is rather than a value initialized once (before the entry point) by the code you wrote.
When you write something like
let value =
//some long calculation
[<Entrypoint>]
let main args = ...
The compiler executes the long calculation before main. This is because you probably use the value later in your code. To suppress this, as you found, you need to use let value() = ....
I am not sure where Icomparable is coming from, but this is the key to what is happening.
Note, if you write
let a = ...
let b = ...
The compiler will gurantee a is calculated before b executes.
As others have pointed out, the absence of parentheses in the declaration is significant.
let Decompres = ...
declares a variable of type unit. This type is used to represent "data" (even if this data doesn't encode much information), and it implements IComparable like any other data-oriented type.
let Decompress() = ...
declares a function, and functions in F# are not comparable, probably because there is no universally accepted notion of equality on functions.
I can't see that the "IComparable-ness" of Decompress had anything to do with the exception you got.

Resources