One issue that I've had since the beginning was "How do I represent the different item types (book, game, project) in a strongly typed way while also reducing the amount of boilerplate I need?"
In C#, I'd just make some interfaces and an object hierarchy and call it a day. And while one can do that in F#, it's against the spirit of what I'm trying to learn.
I went down a few paths (including some pretty
gnarly heroic reflection code, immortalized in this "delete all the old code" commit) but nothing ever really felt right. I ultimately just ended up copy-pasting a bunch of the same code into
Project.fs and moved on.
I've slowly been solving this, starting a couple weeks ago when I added some discriminated unions to represent each type (in this commit). That ended up with a lot of similar code in pattern matching blocks, but I felt okay about it because the compiler was going to help me out by noticing missed patterns.
Then, last weekend, I watched a talk from Mads Torgersen on "The functional journey of C#". He made a point that a big difference between OO and functional programming is that OO lets you put new behaviors in one place (encapsulated in the base class, perhaps) while functional programming makes you spread it out all over the place and duplicate things in each function. But the functional approach is more extensible since all the behavior is out in the open.
He said it better. Go watch the talk.
Anyway, I've taken that to heart and done a great big refactor today.
Before, I really wanted to be able to have a list of, like,
FormField<'t> to support things like
This is fine as far as it goes but:
- You can't put those in the same list because they're all different types
- You can't pattern match over the generic type so it's hard to do things with them
This wouldn't have been so bad in C#. I'd just have a non-generic
FormField interface or something. I don't know. But in F#, it's kind of a drag.
So I embraced what Mads was saying about duplicating behaviors as needed. I now have a new "FormField" concept where each FormField is a discriminated union of everything that a form field could ever be.
I wrapped up a bunch of pattern matched functions to do things with these and it's kind of annoying but really not that bad. The compiler and tooling helps a lot here.
I'm pretty pleased with it.
I know this is far from perfect and not what an F# master would write.
But I think this is a solid improvement and shows how much I'm growing into this new-to-me language and paradigm.
I can only imagine six months from now when all of this seems really gross to me and I have much better ways to accomplish all of it.
I can't wait.