Fable
Fable copied to clipboard
String interpolation breaks some custom printf-style functions
Description
Custom printf-style functions have access to the PrintfFormat instance that encodes useful information about the format string itself (both at the type level and at the runtime value level). Fable handles these just fine when it comes to traditional style calls (e.g. myPrintf "Hello, %s" x), but emits code that violates the type signature when used with interpolated strings (e.g. myPrintf $"Hello, %s{x}"). Instead of getting a PrintfFormat object, Fable actually gives you a string masquerading as a PrintfFormat. Many users will never see an issue because they don't need to actually inspect the PrintfFormat, but in the rare case you do, they evaluate to undefined. It would be nice to make Fable behave closer to what the F# compiler does in this case.
I am running into this specifically while adding interpolation support to the Fable portion of FSharp.Logf.
Repro code
open System
open FSharp.Core.Printf
let f (fmt: StringFormat<'T>) : 'T =
Console.WriteLine fmt.Value
sprintf fmt
let g x = f "wow %d" x
let h x = f $"wow %d{x}"
g 42
h 42
Expected and actual results
Under .NET, this prints:
fmt.Value = wow %d
fmt.Value = wow %d%P()
Under Fable, this prints:
fmt.Value = wow %d
fmt.Value = undefined
Details
Peeking at the transpiled JS (see here) reveals that for the specific case of interpolated strings, it's being squashed before being passed into the custom printf function, instead of in some inner component.
The specific scenario I'm running into this is while adding string interpolation support to the Fable implementation of my FSharp.Printf library. For some context, it essentially needs to be able to perform a regex replacement on the format string itself (see logf.fs#L277). This code, as written, crashes when used with an interpolated string because format.Value evaluates to undefined. While I can partially work around the issue and make it at least not crash, it's not possible to implement the replacement truly correctly in this scenario without a fix from Fable.
Related information
- Fable version: 4.24.0
- Operating system: Windows 11