2

I am trying to write functional code, and I would like to avoid using the foreach loop below. How can I accomplish that?

I am using LanguageExt.

var errors = ImmutableArray.Create<ValidationError>();
var context = new ValidationContext<TRequest>(request);
foreach (IValidator<TRequest> validator in Validators)
{
    var validationResult = await validator.ValidateAsync(context, cancellationToken);
    if (!validationResult.IsValid)
    {
        errors = errors.AddRange(
            validationResult.Errors.
                Select(x => new ValidationError(Key: x.PropertyName, Message: x.ErrorMessage)));
    }

    if (cancellationToken.IsCancellationRequested)
        break;
}
if (errors.Any())
    return new BadRequestResponse(errors);
return SuccessResponse();
TylerH
  • 20,799
  • 66
  • 75
  • 101
Peter Morris
  • 20,174
  • 9
  • 81
  • 146
  • You can probably refactor to a `Select` or `SelectMany` expression followed or preceded by a `Where` expression. If that turns out to be impossible, one of the `Aggregate` overloads are likely to work. It's hard to tell, though, as I'm having to guess at the types and values of most of the symbols. If you post a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) I'll be happy to suggest some actual code. – Mark Seemann Feb 06 '22 at 13:38
  • 1
    Honestly if you replace the loop with functional code you're going to end up with something that's messy and harder to read. So why bother? – juharr Feb 06 '22 at 13:50
  • How about taking a monadic approach to what your code returns? In other words, make a response that entails both error and right response so that your function becomes more composable. Making pure functions is very important in functional programming, and you can achieve it using monads. – Sanghyun Kim Feb 06 '22 at 14:20
  • The issue is that you have an async operation in your foreach. You can't combine that with LINQ. You could consider using the reactive extensions as suggested here: https://stackoverflow.com/questions/50636612/is-there-a-way-to-combine-linq-and-async – jeroenh Feb 06 '22 at 14:24
  • @jeroenh That depends on what you mean by *LINQ*. [Async gives rise to both functor](https://blog.ploeh.dk/2018/09/24/asynchronous-functors) and monad, so you can definitely implement query syntax for it. It just doesn't come out the box. But now that you mention it, async *validation* looks quite odd. Why would validation be asynchronous? – Mark Seemann Feb 06 '22 at 14:46
  • 1
    There's a vote to close this question as *opinion-based*, which seems like the wrong reason to give. [It's possible to state objective criteria for whether or not code is functional](https://blog.ploeh.dk/2018/11/19/functional-architecture-a-definition), and that's what the question is about. – Mark Seemann Feb 06 '22 at 17:58
  • @MarkSeemann You are correct. I am not asking for opinions, I am asking for code :) – Peter Morris Feb 07 '22 at 15:20
  • The POB close vote's not mine, but Mark's link simply looks like a blog post giving an _opinion_ on what functional code is. From my skimming of the question, you appear to be asking how to make the code "_more_" functional, not _functional_, period. I think the confusion arose there; if you want to write the code above without a foreach loop, you should just focus on that. "How do write this code without a foreach loop" is objectively answerable; "How do I make this code more functional [in terms of functional vs OO]" is not. I've edited the question to make it more objective. – TylerH Feb 07 '22 at 17:15
  • @TylerH Thanks! – Peter Morris Feb 07 '22 at 17:43
  • 1
    This code is fine. Any rewrite would result in stilted code that nobody who's not also fluent in F# would appreciate. Speaking of which, if you want F#, you know where to get it. :P The only thing I would consider is extracting the `foreach` into its own method, whether of this class or as an extension method for `IValidator` (so you can have `var errors = await Validators.ValidateAsync(context, cancellationToken)`). The logic is worth encapsulating, but not (I think) worth "functionalizing". – Jeroen Mostert Feb 07 '22 at 19:32

0 Answers0