3

Im using a resource file for strings, and then use also those with placeholders and needs to format the strings.

I have (about) the following code in my project:

let create s = sprintf (Printf.StringFormat<_>(s)) 

let formatstring = "%s:%d" // this is actually then gotten from the resource strings

let createsomespecificstring s d = create formatstring s d  

let resultstring = createsomespecificstring "123" 123

This code works when I use f#3.0. Swapping it to compile it with 3.1, it compiles but gives a runtime error:

Unable to cast object of type 'Final2@235[Microsoft.FSharp.Core.Unit,System.String,System.String,System.String,System.String]' to type 'Microsoft.FSharp.Core.FSharpFunc2[Microsoft.FSharp.Core.FSharpFunc2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.PrintfImpl+PrintfEnv3[Microsoft.FSharp.Core.Unit,System.String,System.String]],Microsoft.FSharp.Core.FSharpFunc2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.String,System.Object]]]'.

If Im running the above code in repl it doesnt work at all with:

stdin(28,5): error FS0030: Value restriction. The value 'resultstring' has been inferred to have generic type val resultstring : '_a
Either define 'resultstring' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.

The above code somewhat defeats the purpose of strong typing again, but its kind of nice when one has resource strings.

Am I doing something wrong (besides mentioned above)?

Any ideas on how to do it better and even make it work (especially in 3.1)?

Edit: After first answer (which works in that specific case) the number of formating options/arguments are "random" length:

let formatstring = "%s:%d:%d"
let createsomespecificstring s d d'  = create formatstring s d d'
let resultstring = createsomespecificstring "123" 123 345

Then it does not work again.

Helge Rene Urholm
  • 1,190
  • 6
  • 16
  • Have you tried `let resultstring:string = createsomespecificstring ...`? – kvb Dec 12 '14 at 15:13
  • @kvp *facepalm* no I hadnt. I could even do that at a "higher level" and then it works. let createsomespecificstring s d d' : string = create formatstring s d d' .... its confirmed. to bad you didnt write this as an answer. and to bad I didnt see that myself. thx! – Helge Rene Urholm Dec 12 '14 at 17:07

2 Answers2

1

Type annotation as @kvp hints at is the "correct" answer.

let createsomespecificstring s d d' : string = create formatstring s d d'

That does it in fsi, and in f# 3.1 when compiled on the tests I have done.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Helge Rene Urholm
  • 1,190
  • 6
  • 16
0

Here is a solution that works at least in fsi:

let create s = sprintf (Printf.StringFormat<_ -> _ -> string >(s)) 
let formatstring = "%s:%d" // this is actually then gotten from the resource strings
let createsomespecificstring s d = create formatstring s d
let resultstring = createsomespecificstring "123" 123

All that I needed was to add some extra dummy parameters and to enforce the return type of the sprintf to be a string.

John Palmer
  • 25,356
  • 3
  • 48
  • 67
  • Yes it does. In this specific case. It does not work though if changing the formatstring to f.i. "%s:%d:%d" and then further on in the code... – Helge Rene Urholm Dec 12 '14 at 07:58
  • right, but everywhere the code is used at say the `createssomespecificstring` you know the length, so just create multiple versions for all the lengths you need – John Palmer Dec 12 '14 at 11:43