hoping to confirm my use of Option

115 views
Skip to first unread message

fdaoud

unread,
May 2, 2012, 3:52:58 PM5/2/12
to Functional Java
Hi all,

First of all, thank you for FunctionalJava, I have been putting it to
good use to use functional programming principles in my Java code.
Java being Java, there is still a lot of code noise, but at least I
can move that noise and hide it away somewhere, and clean up the
"main" part of my code.

My use so far had been mostly using F, List, map, filter, etc. Now, I
used Option to hopefully clean up some noisy code I had that involved
a lot of null checking. It works but I'm hoping that someone can have
a look and tell me if I could be doing this in an easier way still,
because I am not sure whether I've made things more complicated than
need be.

My original code was:

PlanOfCareType[] orderRequestArray = plan.getOrderRequestArray();

if (orderRequestArray != null) {
for (PlanOfCareType orderRequest : orderRequestArray) {
Goals goals = orderRequest.getGoals();

if (goals != null) {
GoalType[] goalArray = goals.getGoalArray();

if (goalArray != null) {
for (GoalType goal : goalArray) {

section.addToMultilineDataCell(CcrUtils.getText(goal.getDescription()));
}
}
}
}
}

Nothing complicated, but all those null checks are annoying.

My cleaned up code has become:

Option.fromNull(plan.getOrderRequestArray()).bind(getGoals).bind(getGoalArray).foreach(addGoalsToSection(section));

Much nicer! However, to achieve that, I have the following (very
noisy) code. Is there a simpler way?

private F<PlanOfCareType[], Option<Array<Option<Goals>>>> getGoals =
new F<PlanOfCareType[], Option<Array<Option<Goals>>>>() {
@Override
public Option<Array<Option<Goals>>> f(PlanOfCareType[]
orderRequestArray) {
return Option.some(Array.array(orderRequestArray).map(new
F<PlanOfCareType, Option<Goals>>() {
@Override
public Option<Goals> f(PlanOfCareType orderRequest) {
return Option.fromNull(orderRequest.getGoals());
}
}));
}
};

private F<Array<Option<Goals>>, Option<Array<Option<GoalType[]>>>>
getGoalArray = new F<Array<Option<Goals>>,
Option<Array<Option<GoalType[]>>>>() {
@Override
public Option<Array<Option<GoalType[]>>> f(Array<Option<Goals>>
goals) {
return Option.some(goals.map(new F<Option<Goals>,
Option<GoalType[]>>() {
@Override
public Option<GoalType[]> f(Option<Goals> optionGoal) {
return optionGoal.map(new F<Goals, GoalType[]>() {
@Override
public GoalType[] f(Goals goals) {
return goals.getGoalArray();
}
});
}
}));
}
};

private Effect<Array<Option<GoalType[]>>> addGoalsToSection(final
CcrSection section) {
return new Effect<Array<Option<GoalType[]>>>() {
@Override
public void e(Array<Option<GoalType[]>> goals) {
goals.foreach(new Effect<Option<GoalType[]>>() {
@Override
public void e(Option<GoalType[]> goalTypes) {
goalTypes.foreach(new Effect<GoalType[]>() {
@Override
public void e(GoalType[] goalArray) {
for (GoalType goal : goalArray) {

section.addToMultilineDataCell(CcrUtils.getText(goal.getDescription()));
}
}
});
}
});
}
};
}

Any help would be appreciated -- thanks in advance!

Fred

Andreas Joseph Krogh

unread,
May 2, 2012, 4:55:20 PM5/2/12
to functio...@googlegroups.com
You have to live with this noise as JAVA doesn't have type-inference and
you want type-safety...

--
Andreas Joseph Krogh<and...@officenet.no> - mob: +47 909 56 963
Senior Software Developer / CEO - OfficeNet AS - http://www.officenet.no
Public key: http://home.officenet.no/~andreak/public_key.asc

fdaoud

unread,
May 2, 2012, 5:21:43 PM5/2/12
to Functional Java
> You have to live with this noise as JAVA doesn't have type-inference and
> you want type-safety...

Indeed. However I thought that perhaps there was a simpler solution
than mine, for example with respect to Option vs Array, Option<Array>
vs Array<Option>.. i.e., a potentially null array vs an array of
potentially null items.
I created several functions to dig through all that. Have I missed a
part of the FunctionalJava API that does some of that work already?

Thanks,
Fred

Robin P

unread,
Jul 26, 2012, 11:05:02 AM7/26/12
to functio...@googlegroups.com
Actually your code can be refactored pretty fine. Here are some general comments extracted from the code, and the code itself later.

- get from Java types (Array, util.List, etc) to fj counterparts as soon as you can
- never return Option<A> if the only way you make an option is Option.success(a)
- the above generalizes for other Contexts + lifting methods too
- also, never create manually a F<List<A>, List<B>> or any other F<C<A>, C<B>> for C in the fj contexts, rather use F<A, B>.mapContext, like .mapList, .mapArray, .mapOption which lift the F<A, B> to work in the given context
- if possible refactor anonymous functions to classes, bit nicer

The code is substantially cleaner this way.

    void x() {
        final Plan plan = new Plan();
        final Section section = new Section();
        Option.fromNull(plan.getOrderRequestArray())
                .map(Array.<PlanOfCareType>wrap()) // get from Java raw type to fj type as soon as you can
                .map(getGoals.mapArray())
                .map(getGoalArray.mapOption().mapArray())
                .foreach(addGoalsToSection(section));
    }

    // Lift using Option.some is to be avoided + map instead bind
    private F<PlanOfCareType, Option<Goals>> getGoals =

            new F<PlanOfCareType, Option<Goals>>() {
                @Override
                public Option<Goals> f(PlanOfCareType planOfCareType) {
                    return Option.fromNull(planOfCareType.getGoals());
                }
            };

    // again don't use Option.some() just for fun
    //
    // dont write a new  F<Array<A>, Array<B>>, instad use F<A, B>.mapArray
    // dont write a new  F<Option<A>, Option<B>>, instad use F<A, B>.mapOption
    private F<Goals, GoalType[]> getGoalArray = new F<Goals, GoalType[]>() {

        @Override
        public GoalType[] f(Goals goals) {
            return goals.getGoalArray();
        }
    };

    private Effect<Array<Option<GoalType[]>>> addGoalsToSection(final Section section) {

        return new Effect<Array<Option<GoalType[]>>>() {
            @Override
            public void e(Array<Option<GoalType[]>> optionalGoalTypeArray) {
                for (Option<GoalType[]> maybeGoalTypes : optionalGoalTypeArray) {
                    for (GoalType[] someGoalTypes : maybeGoalTypes) {
                        for (GoalType goalType : someGoalTypes) {
                            section.addToMultilineDataCell(goalType.getDescription());
                        }
                    }
                }               
            }
        };
    }

BR,
Robin

Robin P

unread,
Jul 26, 2012, 11:07:53 AM7/26/12
to functio...@googlegroups.com
A comment to this line:


> never return Option<A> if the only way you make an option is Option.success(a)

Sometimes you have an F<A, B>, but you need to pass in an F<A, C<B>>. In this case you can use F<A, B>.contextK-like methods, like F<A, B>.optionK = F<A, Option<B>>. This is kalled Kleisli and lifts only the result of the function into the context (vs. the mapXyz, which lifts the whole function).

Robin
Reply all
Reply to author
Forward
0 new messages