Both of these work for me:

1
2
3
4

let  f (x:string) = System.String.Format("{0}",x);;

let f (x:obj) = String.Format("Object x: {0} ",x);;


Re GetHashCode - it's actually there, but Visual Studio doesn't show it - this is a known bug.

1
2

"3".GetHashCode();;


However in general I would recommend you use the "hash" function from F# code, as this deals with hashing structural types:

1
2
3
4
5

> hash (3,"3");;
val it : int = -1684705507
> hash "3";;
val it : int = -842352755


Cheers!

Don

By on 6/3/2006 9:19 AM ()

This works fine for casting reference types, but what about value types, like integers? E.g. what's the preferred way to cast between Int and UInt16? Looking at the implementation of the Byte module, I've managed to write these:

1
2

let ui16_to_int (x : uint16) = (# "" x : int)
let int_to_ui16 (x : int) = (# "conv.u2" x : uint16)

but I'm not really sure what they do (is "conv.u2" an IL instruction? What's (#"" ...)? ).

By on 6/13/2006 10:43 AM ()

You should probably define these using the functions in System.Convert (e.g. System.Convert.ToInt16, generally with a type annotation), or use those functions directly. The use of inline IL code is subtle!

Don

By on 6/13/2006 1:22 PM ()

Thanks for the quick reply! Unfortunately, System.Convert does range-checking, which is something I don't want in this particular case. For example, I need a function uint16_to_int16 which converts 65531us to -5s without complaining; I guess I could convert from Int16 to Int32, then bitwise-and with 0xffff, and then convert back to UInt16, but that sounds a bit too complex for a simple cast...

Are there any plans to add syntax for casts between integer, floating point and decimal types to F#?

To give a little context: In my project I get two UDP data packets from a microcontroller, each containing a 16-bit time value (t0 and t1); The time values are simple counters, so conceptually I'd like to modell them as UInt16 values. Next, I have to calculate the time span (t1-t0) between these two time values (assuming they're less than 32786 steps apart), which is of course Int16. I also get a pair of 32-time values from a different source, and want to compare time spans between the two sources. The ultimate goal is to ensure that packets from various channels (microcontrollers and cameras) are in sync, even if the whole communication is unreliable. The algorithm for this is not trivial, and doing it in F# simplified the whole thing a lot (even though I'm quite a newbie).

By on 6/14/2006 2:59 PM ()

I was tardy in reply this time - my apologies.

I see your problem - your first approach was correct. Just follow the approach, e.g. from the uint64.fs implementation of the UInt64 module (note, these mappings have not been tested fully)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29



module UInt16 = begin
let of_uint32 (n:uint32) =  (# "conv.u2" n : uint16)
let to_uint32 (x:uint16) = (# "conv.u4" x : uint32)
let of_int16 (n:int16) =  (# "conv.u2" n : uint16)
let to_int16 (x:uint16) = (# "conv.i2" x : int16)
let of_int (n:int) =  (# "conv.u2" n : uint16)
let to_int (x:uint16) = (# "conv.i4" x : int)
let of_unativeint (n:unativeint) =  (# "conv.u2" n : uint16)
let to_unativeint (x:uint16) = (# "conv.u" x : unativeint)
let of_float (f:float) =  (# "conv.u2" f : uint16)
let to_float (x:uint16) =  (# "conv.r8" x : float)
end

module Int16 = begin
let of_int32 (n:int32) =  (# "conv.i2" n : int16)
let to_int32 (x:int16) = (# "conv.i4" x : int32)
let of_uint16 (n:uint16) =  (# "conv.i2" n : int16)
let to_uint16 (x:int16) = (# "conv.u2" x : uint16)
let of_int (n:int) =  (# "conv.i2" n : int16)
let to_int (x:int16) = (# "conv.i4" x : int)
let of_unativeint (n:unativeint) =  (# "conv.i2" n : uint16)
let to_unativeint (x:int16) = (# "conv.i" x : unativeint)
let of_float (f:float) =  (# "conv.i2" f : int16)
let to_float (x:int16) =  (# "conv.r8" x : float)
end;;



By on 6/18/2006 4:31 AM ()

> I was tardy in reply this time - my apologies.

I'm thankful enough that you're willing to answer newbie's questions on a sunday ;-)

Thanks for the code, I've put it in a separate file and it works like a charm. Renaming the functions so that they match the patterns in the Int32/Int64 modules was probably a good idea, too.

By on 6/19/2006 3:10 AM ()

I know this was the question asked but instead of String.Format I would use either "Printf.sprintf" or "any_to_string". "Printf.sprintf" is type safe, as the thing passed to it must match the token in the string. "any_to_string" pretty prints any F# types.

1
2
3
4
5

> Printf.sprintf "string %s int %i" "hello" 3;;
val it : string = "string hello int 3"
> any_to_string (1, 1);;
val it : string = "(1, 1)"

By on 6/3/2006 10:40 AM ()

I find it rather confusing that the snippet

1
2

let f x:string =
String.Format("Object x: {0} ",x)

does not work while

1
2

let f (x:string) =
String.Format("Object x: {0} ",x)

does its duty. It thought that the defintion of f (x ) does define that
the function takes a tuple whereas f x does not. I have also seen in
the sample sources of the chess game a function defintion like this

1
2
3
4
5

let LetUseDefault()=(
sFileComputer := (Application.StartupPath ^ "\\Images\\Computer\\computer.gif");
sFileHuman := (Application.StartupPath ^ "\\Images\\Human\\human.gif");
SetImage(pbc,!sFileComputer);
)

How does let f() = ( .... ) differ from a simple let f() = .... without the parenthesis?

And why do I need at the end of each command a simicolon?

Yours,
Alois Kraus

By on 6/4/2006 3:40 AM ()

The below is not an example of a tuple, it is just that all type anontations must be surrounded by parenthesis.

1
2

let f (x:string) =
String.Format("Object x: {0} ",x)

So you could define f that takes 2 string arguments and can be called in the curried style:

1
2
3

> let f (x:string) (y:string) =
String.Format("Object x: {0} ",x),
String.Format("Object y: {0} ",y);;

I believe there is no difference between an expression that is surrounded by parenthesis one that isn't. Parenthesis are usally used to sort out precedence, but any expression can be replaced by the same expression surrounded by parenthesis.

Semi colon means chain two statements together. A statement is an expression that returns unit, which is F#'s version of void. Say you want to chain two Console.WriteLines together, you could either write:

1
2
3
4
5

> let write_stuff () =
let _  = Console.WriteLine("Hello") in
Console.WriteLine("World");;

val write_stuff : unit -> unit

Or more consisely:

1
2
3
4
5

> let write_stuff () =
Console.WriteLine("Hello");
Console.WriteLine("World");;

val write_stuff : unit -> unit
By on 6/4/2006 4:35 AM ()

Thank you very much Robert. This did help me greatly to understand

bigger portions of the Chess sample application. I hope I will find

soon time to add more F# examples to my F#/C# article.

Yours,

Alois Kraus

By on 6/5/2006 12:54 PM ()