Creating a Printer class for my own type.
I am doing this for learning and am aware that if I want to work with JSON I can use System.Text.Json
This is the type to extend:
And want to define a class like:
How should I extend the functionality of the JSON types. I had a ToString() method, but it didnt deal with indents and single responsibility principle.
11 Replies
I considered a bunch of if statements and casting the JSONValue to its subclasses, but this didnt seem good
I have tried reading how this is implemented in std but it was a lot more complicated to understand
this seems potentially like a case for interfaces?
i.e. declare an IPrettyPrintable interface and implement it on JSONNUm, JSONString, JSONBool etc
that way the relevant code for these types are kept with the rest of their functionality
and you can just do myValue.PrettyPrint() if you implement it on the base JSONValue type or what have you
would I be able to separate the printing part into a diffent namespace with this?
ideally i would likee to be able to choose whether i care about the printing or not
the implementation code for the interface would be in the same classes, and therefore namespaces, as the JSON types
if you don't care about the printing you could not implement the interface for one of the classes
i'm not sure how namespaces relate to that though
@Becquerel (ping on reply please) this is what I ended up with but I'm not sure if it is good code:
i couldn't think of a way to do it apart from this unless i wrote the code for printing inside the JSON.Types
i really want the printing of JSON to be separate to its representation
this is what the output looks like for an example jsonValuee
another reason i want the printing to be separate is because i can then do a toFile kind of print that prints it out in bytes, with no whitespace
is there a better way to do this using some OOP design pattern or does it need the dynamic dispatch based on the types
that kind of separation is a valid concern and something to look into... i would look into the visitor pattern, perhaps
a lesser-used pattern but i've seen it referenced as being particularly useful for parsing or consuming syntax-tree-like things
i think that is exactly what i was looking for thank you
i would just need to define an accept method in the JSONValue abstract class that accepts a PrettyPrinterVisitor and then define the prettyprintervisitor with the exact same methods that i have here
and i could avoid the if statements for the type
i will have a go at this tomorrow, and let you know how it turns out
this is the sort of pattern that i dont think i could have come up with myself
thank you @Becquerel (ping on reply please)
ive just read some articles slating the visitor pattern, but its surely still better than dynamic dispatch? 😢
if we're using the same definition of dynamic dispatch, i really wouldn't worry about it in c#
since this is a GC language to begin with
if performance is your concern
I’m not too sure about the definitions but I meant it as dynamically choosing which func to call at runtime based on these type checks
It seemed like bad code, but functionally I expect to pattern match on a type
I tried using a switch but encountered some errors
I was thinking something like data JsonVal = Num | String | Bool | Null | Array | Object
And then pattern matching on these, where the compiler knows the exhaustive list of patterns it can be
Defining a function to perform on each
oh i see. in c# you don't really do that with pattern matching so much as you use inheritance and subtyping
which also counts as dynamic dispatch because of vtable lookups etc. etc.
that's what i was getting at earlier when i was talking about interfaces
you work against variables of the IPrettyPrint type, and at runtime you dynamically get the implementation appropriate for the real type
that kind of style would be very common and idiomatic in c#
your style here sounds like something more common in rust, haskell or similar languages
c# has functional features but its legacy and core is still OOP
Yeah I’ve been coding a lot in Haskell recently
What would this look like? Without the visitor pattern I can’t see how to implement the dynamic dispatch with interfaces
I’m not too good at OOP compared to more functional code at the moment
I was kinda expecting the dispatch to work so long as I implemented a PrintValue for each of the JSONValue subclasses but this isn’t the case
I believe that the vtable type code would require implementing a function for each subclass which it then chooses the correct one? I imagine this to be like defining Print on each JSONValue subclass
Again, not sure about this