Skip to content

Option<>.collect() calls PartialFunction even if it is undefined for particular argument #2579

@sleepytomcat

Description

@sleepytomcat

Expected behavior: Option<>.collect() calls PartialFunction passed as argument only for the value on which this PartialFunction is defined.

Observed behavior: PartialFunction called on values for which it is not defined, resulting in undesired behavior (i.e. unchecked exception thrown).

Example code which fails with arithmetic exception (division by zero):

@Test void collect() {	PartialFunction<Integer, Integer> undefinedFor0 = new PartialFunction<>() {	private static final long serialVersionUID = 1L;	@Override public Integer apply(Integer t) {return 1/t;}	@Override public boolean isDefinedAt(Integer value) {return value != 0;}	};	Option<Integer> zero = Option.some(0);	assertTrue(zero.collect(undefinedFor0).isEmpty()); } 

Using io.vavr:vavr:0.10.2

I've checked the code and this is what I've found:

  1. Optiona<>.collect() eventually calls PartialFunction.lift(), here

    return flatMap(partialFunction.lift());

  2. in turn, PartialFunction.lift() looks like this:

    default Function1<T, Option> lift() {
    return t -> Option.when(isDefinedAt(t), apply(t));
    }

— meaning apply(t) will be always called, no matter if isDefinedAt(t) returns true or false.

return t -> Option.when(isDefinedAt(t), apply(t));

The proposed fix: changing the code to

default Function1<T, Option<R>> lift() { return t -> Option.when(isDefinedAt(t), () -> apply(t)); } 

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions