I often find myself writing functions that look like this because they
allow me to easily mock data access, and still provide a signature that accepts parameters to determine what data to access.
public static string GetFormattedRate(
Func<string, RateType>> getRate,
string rateKey)
{
var rate = getRate(rateKey);
var formattedRate = rate.DollarsPerMonth.ToString("C0");
return formattedRate;
}
Or
public static string GetFormattedRate(
Func<RateType, string> formatRate,
Func<string, RateType>> getRate,
string rateKey)
{
var rate = getRate(rateKey);
var formattedRate = formatRate(rate);
return formattedRate;
}
Then I use it something like this:
using FormatterModule;
public static Main()
{
var getRate = GetRateFunc(connectionStr);
var formattedRate = GetFormattedRate(getRate, rateType);
// or alternatively
var formattedRate = GetFormattedRate(getRate, FormatterModule.FormatRate, rateKey);
System.PrintLn(formattedRate);
}
Is this a common practice? I feel like I should be doing something more like
public static string GetFormattedRate(
Func<RateType> getRate())
{
var rate = getRate();
return rate.DollarsPerMonth.ToString("C0");
}
But that doesn't seem to work very well because I'd have to make a new function to pass into the method for every rate type.
Sometimes I feel like I should be doing
public static string GetFormattedRate(RateType rate)
{
return rate.DollarsPerMonth.ToString("C0");
}
But that seems to take away any fetch and format re-usability. Whenever I want to fetch and format I have to write two lines, one to fetch and one to format.
What am I missing about functional programming? Is this the right way to do it, or is there a better pattern that's both easy to maintain and use?
Best Answer
If you do this long enough, you'll eventually find yourself writing this function over and over:
Congratulations, you've invented function composition.
Wrapper functions like this don't have much use when they're specialized to one type. However, if you introduce some type variables and omit the input parameter, then your GetFormattedRate definition looks like this:
As it stands, what you're doing has little purpose. It's not generic, so you need to duplicate that code all over the place. It overcomplicates your code because now your code has to assemble everything it needs from a thousand tiny functions on its own. Your heart's in the right place though: you just need to get used to using these sorts of generic higher order functions to put things together. Or, use a good old fashion lambda to turn
Func<A, B>
andA
intoFunc<B>
.Don't repeat yourself.