7

Why does the fail value throw an exception? fine value works. If I remove inline or if I convert 't into float then it works.

[<Struct>]
type Test<'t> =
  val x: 't
  val y: 't
  new (x,y) = { x = x; y = y }

  static member inline (+) ((x,y), a: _ Test) = 0
  static member inline (-) ((x,y), a: _ Test) = 0

let a = 1.,2.
let b = Test(1.,2.)
let fine = a - b
let fail = a + b

error message:

Unhandled Exception: System.TypeInitializationException: The type initializer fo r 'AdditionDynamicImplTable3' threw an exception. ---> System.NotSupportedExcep tion: Dynamic invocation of op_Addition involving coercions is not supported. at Microsoft.FSharp.Core.LanguagePrimitives.dyn@2445[a,b,c](Type aty, Type bt y, Unit unitVar0) at Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamicImplTable3..cctor () --- End of inner exception stack trace --- at Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamic[T1,T2,TResult](T1 x, T2 y) at .$Program.main@() in C:\Users\olsv\Docume nts\Visual Studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\Program. fs:line 14 Press any key to continue . . .

Oldrich Svec
  • 4,191
  • 2
  • 28
  • 54

1 Answers1

6

This looks like a bug in the compiler - or I am missing something (please report it at fsbugs at microsoft dot com). For some reason, the compiler fails to inline the call to the + operator (it seems to work for - and / and for custom operators like +., but fails for + and *).

This means that the compiler actually generates something like:

// Inlined - returns zero directly
fine = 0; 

// Failed to inline - calls a version which used dynamic lookup
fail = LanguagePrimitives.AdditionDynamic
         <Tuple<double, double>, Test.Test<double>, double>(a, b);

The AdditionDynamic method uses some internal table to find an implementation of + for the two types at runtime. Although you could register your type there, it would not really be useful, because the invocation would be slow.

I do not really have any nice workaround for this - if you need the operator only for some basic numeric types (float, int, etc.) then the easiest option might be to just avoid using inline here and define (an overloaded) operator for the specific types:

 static member (+) ((x:float,y:float), a: float Test) = x + y + a.x + a.y 

You can also try the trick with global operator and a helper type that implements the different overloads, but I'm not sure if that's going to help: see, for example, this past question.

Community
  • 1
  • 1
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553