hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

Type casting

Last post 06-19-2006, 3:10 by nikie. 10 replies.
Sort Posts: Previous Next
  •  06-02-2006, 16:23 323

    Type casting

    I am still struggling with some very simple constructs in F#. How do I a type cast?

    let f x =

    String.Format("Object x: {0} ",x)


    The compiler complains:
    file1.fs(15,3): error: The method Format is overloaded. Possible matches are shown below. Resolve the overloading by adding further type annotations to the arguments.

    file1.fs(15,3): FS0041: Possible overload: 'String.Format(string format, obj arg0) : string'.

    file1.fs(15,3): FS0041: Possible overload: 'String.Format(string format, obj [] args) : string'.

    file1.fs(15,3): error: Overloading not resolved.

    If you use String.Format("",x,x) it can be resolved but there has to be a way to make it work correctly.

    Constraining the input type does not help here.

    And while I am complaining has string lost its GetHashCode function? How do I hash a string?

    Yours,
      Alois Kraus

  •  06-03-2006, 9:19 329 in reply to 323

    Re: Type casting

    Both of these work for me:

    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.

    "3".GetHashCode();;

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

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

    Cheers!

    Don

     

  •  06-03-2006, 10:40 330 in reply to 329

    Re: Type casting

    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.

    > 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)"


    Robert Pickering, MVP
    http://strangelights.com
  •  06-04-2006, 3:40 332 in reply to 330

    Re: Type casting

    I find it rather confusing that the snippet

    let f x:string =

    String.Format("Object x: {0} ",x)


    does not work while

    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

    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

  •  06-04-2006, 4:35 334 in reply to 332

    Re: Type casting

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

    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:

    > 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:

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

    val write_stuff : unit -> unit

    Or more consisely:

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

    val write_stuff : unit -> unit


    Robert Pickering, MVP
    http://strangelights.com
  •  06-05-2006, 12:54 338 in reply to 334

    Re: Type casting

    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

  •  06-13-2006, 10:43 347 in reply to 329

    Re: Type casting

    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:

    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 (#"" ...)? ).
  •  06-13-2006, 13:22 348 in reply to 347

    Re: Type casting

    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

     

  •  06-14-2006, 14:59 355 in reply to 348

    Re: Type casting

    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).
  •  06-18-2006, 4:31 365 in reply to 355

    Re: Type casting

    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)



    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;;

  •  06-19-2006, 3:10 366 in reply to 365

    Re: Type casting

    > 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.
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems