That does look weird. It is probably a type inference subtelty. Can you provide a complete working example, I think that would help us answer your question.Kurt

By on 3/2/2009 1:12 AM ()

Ahh, type inference [i]is[/i] the issue. This works:

5.0f * ((Vector3.Normalize Vector3.Forward) : Vector3);;

I don't see why it couldn't determine which overload of Normalize I am using based on the fact that I'm passing in a single argument of type Vector3...

By on 3/3/2009 11:07 PM ()

Hi Rotaerk,

If you haven't already, please file a bug report.

thanks,

Danny

By on 3/4/2009 3:07 AM ()

Yes, I'll file a bug report once I've confirmed what all is actually buggy behavior.

Pardon the annoying spacing; I haven't figured out this site's BBcode support yet.

Anyway, I found some interesting things related to this issue. Take these C# structs:

namespace TestLibrary

{

public struct TestStruct

{

float value;

public float Value { get { return value; } }

public TestStruct(float value)

{

this.value = value;

}

public static TestStruct operator *(float scalar, TestStruct testStruct)

{

return new TestStruct(scalar * testStruct.Value);

}

public static TestStruct Add(TestStruct a, TestStruct b)

{

System.Console.WriteLine("Add by val");

return new TestStruct(a.Value + b.Value);

}

public static void Add(ref TestStruct a, ref TestStruct b, out TestStruct result)

{

System.Console.WriteLine("Add by ref");

result = new TestStruct(a.Value + b.Value);

}

}

public struct JustByVal

{

float value;

public float Value { get { return value; } }

public JustByVal(float value)

{

this.value = value;

}

public static JustByVal operator *(float scalar, JustByVal testStruct)

{

return new JustByVal(scalar * testStruct.Value);

}

public static JustByVal Add(JustByVal a, JustByVal b)

{

System.Console.WriteLine("Add by val");

return new JustByVal(a.Value + b.Value);

}

}

public struct JustByRef

{

float value;

public float Value { get { return value; } }

public JustByRef(float value)

{

this.value = value;

}

public static JustByRef operator *(float scalar, JustByRef testStruct)

{

return new JustByRef(scalar * testStruct.Value);

}

public static void Add(ref JustByRef a, ref JustByRef b, out JustByRef result)

{

System.Console.WriteLine("Add by ref");

result = new JustByRef(a.Value + b.Value);

}

}

}

I can duplicate the issue I was having with Vector3:

> let a = TestStruct 5.0f

let b = TestStruct 5.0f;;

val a : TestStruct

val b : TestStruct

> 5.0f * (TestStruct.Add(a, b));;

5.0f * (TestStruct.Add(a, b));;

--------^^^^^^^^^^^^^^^^^^^^^

stdin(39,9): error FS0193: Type constraint mismatch. The type

TestStruct

is not compatible with type

float32.

The type 'TestStruct' is not compatible with the type 'float32'.

For some reason, it confuses the two overloads of Add. Removing the by-ref overload results in no error:

> let a = JustByVal 5.0f

let b = JustByVal 5.0f;;

val a : JustByVal

val b : JustByVal

> 5.0f * (JustByVal.Add (a, b));;

Add by val

val it : JustByVal = TestLibrary.JustByVal {Value = 50.0f;}

Removing the by-value overload also results in no error if you tweak the calling code a bit.

> let mutable a = JustByRef 5.0f

let mutable b = JustByRef 5.0f;;

val mutable a : JustByRef

val mutable b : JustByRef

> 5.0f * (JustByRef.Add (&a, &b));;

Add by ref

val it : JustByRef = TestLibrary.JustByRef {Value = 50.0f;}

In F#, you can (optionally) leave off arguments to "out" parameters, and it will return a tuple containing what would be the return value and all values that would have been placed in the omitted "out" parameters. The by-ref overload of TestStruct.Add has the F# type signature: (TestStruct byref * TestStruct byref * TestStruct ref -> unit). However, if you leave off the third argument, it behaves like a function with the signature: (TestStruct byref * TestStruct byref -> TestStruct). There seems to be some kind of clash between overloading and the"out"-parameter omission mechanism, as demonstrated in this code execution:

> let g = (TestStruct.Add : TestStruct byref * TestStruct byref -> TestStruct);;

val g : TestStruct byref * TestStruct byref -> TestStruct

> let h = (TestStruct.Add : TestStruct byref * TestStruct byref * TestStruct ref -> unit);;

val h : TestStruct byref * TestStruct byref * TestStruct ref -> unit

> let x = (JustByRef.Add : JustByRef byref * JustByRef byref -> JustByRef);;

val x : JustByRef byref * JustByRef byref -> JustByRef

> let y = (JustByRef.Add : JustByRef byref * JustByRef byref * JustByRef ref -> unit);;

let y = (JustByRef.Add : JustByRef byref * JustByRef byref * JustByRef ref -> unit);;

---------^^^^^^^^^^^^^^

stdin(50,10): error FS0001: Type mismatch. Expecting a

JustByRef byref * JustByRef byref * JustByRef ref

but given a

JustByRef byref * JustByRef byref.

The tuples have differing lengths of 3 and 2.

As demonstrated by g and x, it actually seems to generate an [i]overload[/i] of Add with the type signature (T byref * T byref -> T). However, it only seems to see the overload with the proper signature of (T byref * T byref * T ref -> unit) in TestStruct. When the by-val overload is removed, the by-ref overload with the proper signature disappears! Although that's not actually the case, because it can still be [i]called[/i] that way:

> let mutable a = JustByRef 5.0f

let mutable b = JustByRef 5.0f

let c = ref (JustByRef 5.0f);;

val mutable a : JustByRef

val mutable b : JustByRef

val c : JustByRef ref

> JustByRef.Add (&a, &b, c);;

Add by ref

val it : unit = ()

A related bug I ran across (which I will definitely report, because it said so) is:

> let g = (TestStruct.Add : TestStruct byref * TestStruct byref * TestStruct ref -> unit);;

val g : TestStruct byref * TestStruct byref * TestStruct ref -> unit

> let h = g;;

error FS0193: internal error: The type 'TestLibrary.TestStruct&' may not be used as a type argument.

Please build a small example that reproduces this problem and report it to fsbugs@microsoft.com.

val h : (TestStruct byref * TestStruct byref * TestStruct ref -> unit)

> let r = (TestStruct.Add : TestStruct byref * TestStruct byref -> TestStruct);;

val r : TestStruct byref * TestStruct byref -> TestStruct

> let s = r;;

error FS0193: internal error: The type 'TestLibrary.TestStruct&' may not be used as a type argument.

Please build a small example that reproduces this problem and report it to fsbugs@microsoft.com.

val s : (TestStruct byref * TestStruct byref -> TestStruct)

> let x = (JustByRef.Add : JustByRef byref * JustByRef byref -> JustByRef);;

val x : JustByRef byref * JustByRef byref -> JustByRef

> let y = x;;

error FS0193: internal error: The type 'TestLibrary.JustByRef&' may not be used as a type argument.

Please build a small example that reproduces this problem and report it to fsbugs@microsoft.com.

val y : (JustByRef byref * JustByRef byref -> JustByRef)

Anyway, I'm considering sending pretty much this whole post in a bug report, but I wanted to get some feedback first.

By on 3/4/2009 9:09 PM ()

Looks like you've documented the issue thoroughly. You should report it.Example to quote code (press the quote button, you'll see how the bbcode looks)

1
let codeExample x = match x with None -> true | Some _ -> false
By on 3/5/2009 4:34 AM ()

Is there a way to make the code bbcode-tag respect formatting? It did do syntax highlighting but removed all indentation and skipped lines.

By on 3/5/2009 7:18 AM ()

Thanks for the excellent analysis. Please do submit a report to fsbugs@microsoft.com

Kind regards

Don

By on 3/5/2009 5:24 AM ()

I've been unable to duplicate this issue in my own type. Unfortunately, if you want to test this with the Vector3 struct, you will need to download the <a href=http://www.microsoft.com/downloads/details.aspx?FamilyID=7d70d6ed-1edd-4852-9883-9a33c0ad8fee&displaylang=en>MS XNA Game Studio 3.0</a>. If you install that, you can use this to access the Vector3 struct: #r "Microsoft.Xna.Framework.dll" open Microsoft.Xna.Framework <a href=http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.vector3.aspx>The documentation for Vector3</a>. After a few test cases, it appears that [i]any[/i] static method Vector3.Foo that returns a Vector3 causes that error when applied in this manner: <quote>someFloat32 * (Vector3.Foo args);;</quote> However, [i]these[/i] use cases do not result in the error: <quote>(Vector3.Foo args) * someFloat32;; let foo = Vector3.Foo in someFloat32 * (foo args);;</quote> Looking at the definition of the Vector3 struct (written in C#), it has op_Multiply overloaded as such (bearing in mind that float is a Single in C#): public static Vector3 operator *(float scaleFactor, Vector3 value); public static Vector3 operator *(Vector3 value, float scaleFactor); public static Vector3 operator *(Vector3 value1, Vector3 value2); Given those overloads, I see no reason for the error, but it's as though it doesn't see the first one, and only when expressed in the syntax above.

By on 3/2/2009 11:46 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