I've read through a good chunk of Expert F# and am working on building an actual application. While debugging, I've grown accustomed to passing fsi commands like this to make things legible in the repl window:
fsi.AddPrinter(fun (x : myType) -> myType.ToString())
I would like to extend this to work with the printf formatter, so I could type e.g.
printf "%A" instanceOfMyType
and control the output for a custom type. The book implies that this can be done (p 93, "Generic structural formatting can be extended to work with any user-defined data types, a topic covered on the F# website"), but I have failed to find any references as to how to actually accomplish this. Does anyone know how? Is it even possible?
Edit:
I should have included a code sample, it's a record type that I'm dealing with, e.g.
type myType =
{a: int}
override m.ToString() = "hello"
let t = {a=5}
printfn "%A" t
printfn "%A" (box t)
both print statements yield:
{a = 5;}
It looks like the Right Way to do this in F# 2.0 is by using the StructuredFormatDisplay
attribute, for example:
[<StructuredFormatDisplay("hello {a}")>]
type myType = {a: int}
In this example, instead of the default {a = 42;}
, you would get hello 42
.
This works the same way for object, record, and union types. And although the pattern must be of the format "PreText {PropertyName} PostText"
(PreText and PostText being optional), this is actually more powerful than ToString()
because:
PropertyName
can be a property of any type. If it is not a string, then it will also be subject to structured formatting. Don Syme's blog gives an example of recursively formatting a tree in this way.
It may be a calculated property. So you could actually get ToString()
to work for record and union types, though in a rather round-about way:
[<StructuredFormatDisplay("{AsString}")>]
type myType =
{a: int}
override m.ToString() = "hello"
member m.AsString = m.ToString() // a property that calls a method
By the way, ToString()
will always be used (even for record and union types) if you call printfn "%O"
instead of printfn "%A"
.