Questions on Formatters
See original GitHub issueCurrent Formatters are registered by type + mime-type. I’m trying to determine the exact rule that is used to select the relevant formatter.
Question 1 - Sometimes formatters seem to apply to subtypes but not always, e.g. obj
formatters
For example consider
Formatter<IComparable>.Register((fun (s:IComparable) writer -> writer.Write(s.ToString() + "!!!! (IComparable, html)")), "text/html");
Formatter<IComparable>.Register((fun (s:IComparable) writer -> writer.Write(s.ToString() + "!!!! (IComparable, plain)")), "text/plain");
Then values like 1
, System.DateTime.Now
and DayOfWeek.Monday
do invoke the IComparable printer.:
> 1
1!!!! (IComparable, html)
However, if I do this
Formatter<obj>.Register((fun s writer -> writer.Write(s.ToString() + "!!!! (obj, html)")), "text/html");
Formatter<obj>.Register((fun s writer -> writer.Write(s.ToString() + "!!!! (obj, plain)")), "text/plain");
then the obj
formatter is not invoked at all unless the exact runtime type of the value is System.Object
, e.g.
1
andbox 1
do not invoke the printer (surprise!)DateTime.Now
does not invoke the printer (surprise!)new System.Object()
does invoke the printer ( as expected)
I’m just a little confused what the rule is here. Is obj
special? Also, what’s the priority if multiple conflicting formatters are registered, e.g. one form System.DateTime and one for IComparable?
Question 2 - Formatters can’t apply to selective values
There is no way for a formatter to apply only to specific values except via System.Type. The conext here is that in F# Interactive (AddPrinter, returning string) and older F# notebooks (AddHtmlPrinter, returning HTML), formatters can return null
to indicate that they are not interested in formatting a specific value.
This means you could, for example, register a formatter for type System.Object
and pick specific classes of values to your heart’s content, e.g.
fsi.AddPrintTransformer(fun (x:obj) ->
match x with
| :? string as s when s = "beep" -> box ["quack"; "quack"; "quack"]
| _ -> null)
let y = "beep"
This outputs:
val y : string = ["quack"; "quack"; "quack"]
For example, you can register a formatter for “PythonObject” but only decide to format Python tensors. And you can have multiple such formatters active.
At least, I was thinking that the old F# approach should be implementable in terms of the primitives available in .NET Interactive.
I’m trying to think how important this is for F#. Probably the case above is the most important - interacting with a highly heterogenous type in some other object model (PythonObject, RObject, COM Object, ExcelObject etc.).
Issue Analytics
- State:
- Created 3 years ago
- Comments:7 (7 by maintainers)
Top GitHub Comments
@zyzhu There is a way to do this but the APIs need to be more clearly differentiated and made more discoverable:
I’ll close this out as going through and implementing #694 has answered most of my questions.
I’ll be taking a look at this one shortly too: