3

What does "^" mean when it's in front of a type?

Example:

int : ^T -> int

string : ^T -> string

Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • 2
    It is one of those things that you can not ignore and need to be aware of but don't go out of your way to use it now that you know about it. If you understand it and need it then use it. Most of the time I use it is when the type inferencing is telling me that it is needed and then I purposely add the type declaration using `^` so that it is obvious. This is a personal preference and not standard. – Guy Coder Jan 11 '16 at 14:00
  • Thanks Guy Coder. This stuff is just way over my head. – Scott Nimrod Jan 11 '16 at 14:16
  • 1
    I would suggest you change your first real project but you are making progress and asking meaningful questions. My first big personal project was converting code from OCaml to F# which meant I only had to focus on the differences between OCaml and F#, which is a lot less than the differences between C# and F#. – Guy Coder Jan 11 '16 at 14:29
  • 1
    As you are finding, type inferencing is a big part of the ML family of languages and understanding it is key to working with them. The way they modified type inferencing for F# to accommodate .NET doesn't make it easier. See [Converting OCaml to F#: Differences between typing and type inference](http://stackoverflow.com/q/12341767/1243762) for links to hopefully helpful type inferencing info. – Guy Coder Jan 11 '16 at 14:39

1 Answers1

8

this indicates an Statically Resolved Type Parameter

from MSDN:

A statically resolved type parameter is a type parameter that is replaced with an actual type at compile time instead of at run time. They are preceded by a caret (^) symbol.

so it's very similar to 'T but you can use it to give member constraints and the compiler will resolve them at compile-time (obviously) - usually you are just using inline and the type-inference will work it out for you - but there are some quite advanced tricks (for example FsControl) out there using this (not often used) feature

example

let inline add a b = a + b

val inline add :
  a: ^a -> b: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

will add such a constraint to indicate that this will work with all numeric types (it will add an member constraint to an static operator (+))

Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • AFAIK, statically resolved type parameters are applicable _only_ to inline functions and, ironically, they are not visible in examples. – MKaama Jan 11 '16 at 14:03
  • you are right about the first one (maybe I should have made it clearer) - but they are (right in the example) visible - and you can declare them yourself (but it's a bit of a mess - you have to use the same syntax as you see there) – Random Dev Jan 11 '16 at 14:13
  • Thanks Carsten. I'm waving the white flag on this one. My simple mind just can't understand these abstract expressions nor their intent. – Scott Nimrod Jan 11 '16 at 14:13
  • 1
    It's really not that bad - it just tells the compiler that it should look for types `a` `b` and `c` so that either `a` or `b` has an static operator named `( + )` with the given signature and then replace (`inline`) the call - in real life this will be the addition operator on a single type like `int` or `double` (where `a = b = c`) - so instead of `add 4 5` the compiler will yield just `4 + 5` with the `+` from `int` – Random Dev Jan 11 '16 at 14:44
  • 1
    @ScottNimrod If you think about an addition function, it could work on a lot of types: floats, doubles, ints, etc. This kind of annotation tells the compiler, please verify that any argument we give our function has some special property about it (in this case an overloaded `+` operator). It it has the special property, it can always make the function work, otherwise it's a compiler error. – TheInnerLight Jan 11 '16 at 14:45
  • 1
    @TheInnerLight AFAIK the compiler will generate non-generic code and replace the call with this - the constraint is used to look for a concrete implementation – Random Dev Jan 11 '16 at 14:50
  • @Carsten Yes, they are an entirely resolved at compile time hence they don't work if you try to call them from a .NET language other than F#. – TheInnerLight Jan 11 '16 at 14:56