Search code examples
javafunctional-programmingfunctional-interface

combinator pattern, java Function <e, t>


public interface CustomerRegVali extends Function<Customer, ValidationResult>

static CustomerRegVali isEmailValid(){
    return customer -> customer.getEmail().contains("@") ?
            SUCCESS : EMAIL_NOT_VALID;
}

static CustomerRegVali isDobValid(){
    return customer -> Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
            SUCCESS : NOT_ADULT;
}
static CustomerRegVali isPhoneValid(){
    return customer -> customer.getPhone().startsWith("+0") ?
            SUCCESS : PHONE_NOT_VALID;
}

default CustomerRegVali and(CustomerRegVali other){
    return customer -> {
        ValidationResult result = CustomerRegVali.this.apply(customer);
        return result.equals(SUCCESS) ? other.apply(customer) : result;
    };
}


@Main method
    ValidationResult result = isEmailValid()
            .and(isPhoneValid())
            .and(isDobValid())
            .apply(customer);

Right so.. Looking back at an old uni project for functional java, I stumbled upon this combinator. Am I clueless or does .apply not get called twice on the primitives? Seems rather redundant.


Solution

  • You wrote

    ... during .and(isPhoneValid), is .this not referring to isEmailValid - and .other to isPhoneValid. With this in mind, next iteration would then be .this referring to isPhoneValid on which we will call .apply once again.

    I think you're confusing this with CustomerRegVali.this, which is different. You might be imagining that you're building a structure that looks like this:

    enter image description here

    but in fact it looks like this:

    enter image description here

    Within a call to apply, this points to one of these boxes, but as you can see, there's never a case in which this points to isEmailValid while a separate other link points to isPhoneValid.

    In the implementation of apply for and, you're not calling apply on this but rather on the captured value CustomerRegVali.this, which is the validator on which you invoked and.

    In setting up the validator, you:

    • Call isEmailValid.
    • Invoke and on the isEmailValid validator, passing the isPhoneValid validator. This creates a new and validator that retains a reference to the isEmailValid validator and other.
    • Finally invoke and on the result of the first and, passing a new isDobValid validator, building a new and validator just like the previous one.

    That process produces the structure in the second diagram.

    So there are five validators in total, and you call apply once on each.