I'm working on a F# console application. In the properties I set the output type of application to Windows Application to hide the console. I also created a form to run in its place. Currently I only have a simple form with no controls. To make the form I added referances to System.Windows.Forms and System.Drawing and opened them along with System.Runtime.InteropServices.
The part that I don't know how to do is extending the aero-glass. There are loads of exaples on how to do it in C#. For example, here is the API call and MARGINS structure:
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("dwmapi.dll")]
pubic static extend int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
The API call from Form_Load event:
MARGINS margins = new MARGINS();
margins.cxLeftWidth = 0;
margins.cxRightWidth = 100;
margins.cyTopHeight = 0;
margins.cyBottomHeight = 0;
int result = DwmExtendFrameIntoClientArea(this.Handle, ref margins);
This is what I've got so far in F#:
The API call and MARGINS structure:
[<StructLayout(LayoutKind.Sequential)>]
type MARGINS =
struct
val cxLeftWidth : int
val cxRightWidth : int
val cyTopHeight : int
val cyBottomHeigh t: int
new(left, right, top, bottom) = { cxLeftWidth = left; cxRightWidth = right; cyTopHeight = top; cyBottomHeigh = bottom } (*Is there any other way to do this?*)
end
[<DllImport("dwmapi.dll")>]
extend int DwmExtendFrameIntoClientArea(IntPtr hWnd, (*I need help here*))
The API call from Form_Load event:
let margins = new MARGINS(0, 100, 0, 0); (*Is there any other way to do this?*)
let result : int = DwmExtendFrameIntoClientArea(this.Handle, (*I need help here*))
I have been searching around but I can't find anything about using ref parameters like this in F#. I know this would be a lot easier to write in C# but the code behind the form will be easier to write int F# because it's a functional programing language and the whole program I'm writing is orientated around functions. I know this is purely decorative but please help.
In general, extern (AKA P/Invoke or platform invoke) definitions in F# use C-like syntax (and note that it's extern, not extend):
[<DllImport("dwmapi.dll")>]
extern int DwmExtendFrameIntoClientArea(nativeint hWnd, MARGINS& pMarInset)
This can then be used as follows:
let mutable margin = ...
let result = DwmExtendFrameIntoClientArea(this.Handle, &margin)
Note that the way that you have defined MARGINS is not quite analogous to the C# definition. The various val definitions are not mutable, and are actually properties rather than fields (though they're backed by fields, so it's probably not a big deal). If you want them to be mutable fields, you can add the mutable keyword after val for each field:
[<Struct; StructLayout(LayoutKind.Sequential)>]
type MARGINS =
val mutable cxLeftWidth : int
val mutable cxRightWidth : int
val mutable cyTopHeight : int
val mutable cyBottomHeight: int
(I've also used the Struct attribute instead of struct ... end, but that's just for brevity). You can initialize this like you do in C#, or using F#'s named arguments:
let mutable margin = MARGINS(cxRightWidth = 100)
Related
I'm trying to implement a OrderedSet in F# (a set where you can get items by order of insertion). This is my first naive attempt at it (I still have to deal with possible duplicates in the IEnumerable passed to the constructor. The comparator is also still missing).
I don't think any of the above matters, though. I've been trying to solve the problem and, as far as I could gather from my research, it seems the issue is about indentation or lack of parentheses somewhere.
If I comment out my attempt at implement ISet, there is no issue, which leads me to believe there is something wrong with that part specifically. Here's the code:
open System
open System.Collections.Generic;
type public OrderedSet<'T> public (collection : IEnumerable<'T> option) as this =
let mutable _set = SortedSet<int * 'T>()
do
if Option.isSome(collection) then
let mapper (idx: int) (elem: 'T) = (idx, elem)
do _set <- SortedSet<int * 'T>(Seq.mapi mapper collection.Value)
interface ISet<'T> with
member this.Count
with get() = this._set.Count
I only had to make two changes:
Indent the if under the do.
Remove this. in front of _set, because it's let-bound, not a class member.
You also have to finish implementing ISet, of course. Here's the resulting code:
open System
open System.Collections.Generic;
type public OrderedSet<'T> public (collection : IEnumerable<'T> option) as this =
let mutable _set = SortedSet<int * 'T>()
do
if Option.isSome(collection) then
let mapper (idx: int) (elem: 'T) = (idx, elem)
do _set <- SortedSet<int * 'T>(Seq.mapi mapper collection.Value)
interface ISet<'T> with
member this.Count
with get() = _set.Count
I have a native C library and I want do some F# coding with it. The thing is I get exception:
System.TypeLoadException: Cannot marshal field 'log' of type
'LoggingModel': There is no marshaling support for this type.
at
System.StubHelpers.ValueClassMarshaler.ConvertToNative(IntPtr dst,
IntPtr src, IntPtr pMT, CleanupWorkList& pCleanupWorkList)
at
FSI_0009.Initialize(ComponentOverrideFlags flags, LoggingModel&
loggingModel, ThreadingModel& threadingModel, SchedulingModel&
schedulingModel, IntPtr memoryModel)
at
.$FSI_0011.main#()
in
D:\dev_p\f#\FunBindings\FunExample\Environment.fs:line 16 Stopped due
to error
Here the code:
module Interop
[<CLSCompliant(true); Flags>]
type LogTarget =
| None = 0
| Console = 1
| Trace = 2
| Custom = 4
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type LogCallback = delegate of LogTarget * string * string * nativeint -> unit
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type ReleaseCallback = delegate of nativeint -> unit
[<Struct>]
type LoggingModel =
val mutable targets : LogTarget
val mutable log : LogCallback
val mutable deleteModel : ReleaseCallback
val mutable userparam : IntPtr
[<DllImport("CLIBRARY.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "txInitialize")>]
[<MethodImpl(MethodImplOptions.ForwardRef)>]
extern int Initialize(ComponentOverrideFlags flags, LoggingModel& loggingModel, ThreadingModel& threadingModel, SchedulingModel& schedulingModel, IntPtr memoryModel)
module Environment
let initialize =
let mutable loggingModel = new LoggingModel()
let mutable threadingModel = new ThreadingModel()
let mutable schedulingModel = new SchedulingModel()
Initialize(ComponentOverrideFlags.None, &loggingModel, &threadingModel, &schedulingModel, IntPtr.Zero)
Basically, I get the aforementioned error when I try to execute "initialize" function in interactive.
I would really appreciate any help.
Update: I've checked the code a bit more and noticed that outside of the interactive console it seems to be working, without failing with exceptions. I need to provide a bit more coverage for CLibrary to be sure. Meanwhile, if there anybody who knows what could cause this exception and how it could be prevented, I would really appreciate the answer.
I think the problem is that delegate of LogTarget * string * string * nativeint -> unit declares a delegate where the arguments are curried. (This doesn't really make sense to me either since a * b normally represents a tuple.)
The subtly different delegate of (LogTarget * string * string * nativeint) -> unit declares a delegate with tupled arguments which would be compatible with a native function.
You can see this difference if you try and assign a .NET method to two different delegate types:
type Curried = delegate of int * int -> int
type Tupled = delegate of (int * int) -> int
//let a = new Curried (Math.Max) // doesn't compile
let b = new Tupled (Math.Max) // works
Have you tried adding [<MarshalAsAttribute(UnmanagedType.FunctionPtr)>] to LoggingModel?
[<Struct>]
type LoggingModel =
val mutable targets : LogTarget
[<MarshalAsAttribute(UnmanagedType.FunctionPtr)>]
val mutable log : LogCallback
[<MarshalAsAttribute(UnmanagedType.FunctionPtr)>]
val mutable deleteModel : ReleaseCallback
val mutable userparam : IntPtr
IL code without this attribute is:
// Fields
.field public class Interop.LogCallback log
but with this attribute is:
// Fields
.field public marshal(Func) class Interop.LogCallback log
Without marshal(Func)/MarshalAs attribute the delegate cannot be marshalled even with the UnmanagedFunctionPointer attribute. Cannot test it with a native library though.
In Unity3D we are able to make a field accessible inside the editor by marking it as public. This then allows assigning the field's variable in the GUI instead of hard-coding it. This C# code for example will show a "speed" field that can be manually edited during development. It will default to 10 if left unmodified:
public class Example : MonoBehaviour {
public float speed = 10.0F;
}
I tried doing this in F# with automatic properties:
type Example() =
inherit MonoBehaviour()
member val speed = 10.f with get,set
but this doesn't work. It does, however, work if I use explicit properties
[<DefaultValue>] val mutable speed : float32
but this has the drawback of not being able to specify a default value in the same expression.
Aren't explicit and automatic properties compiling down to the same thing, with the only difference being that explicit properties are always initialized to zero? And how can I declare the equivalent of the C# code in F#?
I think you are playing a little loosely with the terms "field" and "property".
The Unity editor doesn't bind properties automatically, and the first example you've provided is F#'s auto-properties. For the record, you couldn't bind the following C# in Unity editor pane either:
// does not bind in editor either
class Example : MonoBehavior {
public float speed { get; set; }
}
You have to use the code with [DefaultValue] and just initalize it in the constructor or alternatively have a let-bound private field that is tagged [SerializeField] and write your own property wrapper:
type Example () =
[<SerializeField>]
let mutable _speed = 10f
member this.speed
with get () = _speed
and set val = _speed <- val
I think you're confusing two different concepts: explicit fields and auto-properties. Under the hood, a property is more like a method than a field, although access/assignment are syntactically similar. The F# equivalent of your C# would be:
type Example() as this =
[<DefaultValue>] val mutable public speed: float32;
do this.speed <- 10.0f
Another way to implement this, which avoids the [<DefaultValue>] and imperative initialization, would be as follows (note the absence of default constructor on the first line):
type Example =
val mutable public speed : float32
new() = { speed = 10.0f }
I have looked at some other similar questions on SO, but they don't appear to address the following specifically.
What I want to achieve is to have compile-time constants that cannot be altered.
I have a program which I reorganized a little in order to de-clutter. The program had some const declarations prior to "main()". I moved these to a class, however it required that I declare them as "static const". I then thought, ok those other "const" declarations prior to "main()" should probably also be "static const". However when I attempted that, the Editor advised "Top-level declarations cannot be declared to be 'static'". EG.
static const int I_CORRECT_YN = 12; // prompt nr.
So, I am a little confused. I thought that a "const" was static. Why do I have to declare "static" in the class? Why can't I declare a "top level" const as "static"? Also, what is the difference between:
static const int I_CORRECT_YN = 12;
const int I_CORRECT_YN = 12;
static final int I_CORRECT_YN = 12;
final int I_CORRECT_YN = 12; ?
What is the best or only way to declare compile-time values that cannot be altered?
I guess I am looking at the literal meaning, but I presume there is a more complex meaning.
Why do I have to declare "static" in the class?
Because instance variables/methods can't be const. This would mean their value could be different per instance, which can't be the case for compile-time constants. (Source)
Why can't I declare a "top level" const as "static"?
The static modifier marks variables/methods as class-wide (same value for every instance of the class). Top-level stuff is application-wide and doesn't belong to any class, so marking them as class-wide doesn't make any sense and is not allowed. (Source)
What is the best or only way to declare compile-time values that cannot be altered?
You are already doing it - add static when defining class constants. Don't add it when defining top-level constants. Also, use const. final vars aren't compile-time values.
What is the difference between [source code with different constant definitions omitted]
static const and const is the pretty much the same, usage depends on context.
The difference between const and final is that const are compile-time constants - they can only be initialized using literal values (or expressions constisting of operators and literal values) and can't be changed. final variables also can't be changed after being initialized, but they are basically normal variables. This means any kind of expression can be used, and the value can be a different one for every class instance:
import "dart:math";
Random r = new Random();
int getFinalValue() {
return new Random().nextInt(100);
}
class Test {
// final variable per instance.
final int FOO = getFinalValue();
// final variable per class. "const" wouldn't work here, getFinalValue() is no literal
static final int BAR = getFinalValue();
}
// final top-level variable
final int BAZ = getFinalValue();
// again, this doesn't work, because static top-level elements don't make sense
// static final int WAT = getFinalValue();
void main() {
Test a = new Test();
print(Test.BAR);
print(BAZ); // different from Test.BAR
print(a.FOO);
a = new Test();
print(Test.BAR); // same as before
print(BAZ); // same as before
print(a.FOO); // not the same as before, because it is another instance,
// initialized with another value
// but this would still be a syntax error, because the variable is final.
// a.FOO = 42;
}
I hope this helped, and I didn't descibe it too confusing. :]
Does it imply that whenever I am passed an array of a non nullable type, I should still check if it is null? Actually it is not even possible to check <> null but have to use operator.unchecked .How is it better than C#?
type test=
{
value: int
}
let solution = Array.zeroCreate 10
solution.[0] <- {value = 1}
solution.[1].value // System.NullReferenceException: Object reference not set to an instance of an object
type test =
{value: int;}
val solution : test [] =
[|{value = 1;}; null; null; null; null; null; null; null; null; null|]
val it : unit = ()
It depends where the array is being passed from.
If the array is created and used only within F#, then no, you don't need to check for null; in fact, you shouldn't check for null (using Unchecked.defaultOf) because the F# compiler optimizes some special values like [] (and None, in certain cases) by representing them as null in the compiled IL.
If you're consuming an array being passed in by code written in another language (such as C#), then yes, you should still check for null. If the calling code just creates the array and doesn't mutate it any further, then you'll only need to perform the null checks once.
EDIT : Here's a previous discussion about how the F# compiler optimizes the representation of certain values using null: Why is None represented as null?
As the documentation for Array.zeroCreate indicates, it initializes the elements to Unchecked.defaultof<_>. This therefore carries with it all of the same caveats that direct use of Unchecked.defaultof does. Generally, my advice would be to use Array.create/Array.init whenever possible, and to treat Array.zeroCreate as a possible performance optimization (requiring care whenever dealing with non-nullable types).
You're creating a record type, which is implemented as a class, which is indeed nullable. If you intended to create a struct, your code should look something like this:
type test =
struct
val value: int
new(v) = { value = v }
override x.ToString() = x.value.ToString()
end
let solution = Array.zeroCreate 10
solution.[0] <- test(1)
This outputs: val solution : test [] = [|1; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
You could also write the type using the Struct attribute, saving you a level of indentation.
[<Struct>]
type test =
val value: int
new(v) = { value = v }
override x.ToString() = x.value.ToString()