How do I do it in Ceylon

75 Views Asked by At

I've the following code in Java and would like to port it in Ceylon.

public interface Condition {
    Condition FALSE = facts->false;
    Boolean evaluate(Fact<?> fact);
    default Condition and(Condition other) {
        return fact -> this.evaluate(fact) && other.evaluate(fact);
    }
}

@Test void test() {
   String str = "A String";
   Condition a = fact -> !str.empty();
   Condition b = fact -> str.contains("tr");
   Condition both = a.and(b);
   //expect(both(Fact('fact', str)), true);
}

So far I've tried using alias for the given code

shared alias Condition => Boolean(Fact<out Anything>);
Condition falseCondition = (Fact<out Anything> fact) => false;
shared interface ConditionComposer {
    shared formal Boolean eval(Fact<out Anything> fact);
    shared default Condition and(Condition other)<--**I want to pass a Condition here for the below to work** {
        return (Fact<out Anything> fact) => this.eval(fact) && other.eval(fact);
    }
}

I want to pass a Condition as a parameter to and() but as the eval() is part of ConditionComposer, the return statement won't compile. And how will I write a test case for this in Ceylon?

1

There are 1 best solutions below

0
On

@Voiteh on gitter: ceylon/user advised the given solution.

shared interface Condition<Fact> {
    shared static Condition<Fact> falseCondition => object satisfies Condition<Fact> {
        shared actual Boolean evaluate(Fact fact) => false;
    };

    shared static Condition<Data> create<Data>(Boolean(Data) eval) => object satisfies Condition<Data> {
        shared actual Boolean evaluate(Data fact) => eval(fact);
    };

    shared formal Boolean evaluate(Fact fact);

    shared default Condition<Fact> and(Condition<Fact> other) => object satisfies Condition<Fact> {
        evaluate(Fact fact) => this.evaluate(fact) && other.evaluate(fact);
    };

    shared default Condition<Fact> or(Condition<Fact> other) => object satisfies Condition<Fact> {
        evaluate(Fact fact) => this.evaluate(fact) || other.evaluate(fact);
    };

    shared default Condition<Fact> not() => object satisfies Condition<Fact> {
        evaluate(Fact fact) => !this.evaluate(fact);
    };
}

shared void testConditions() {
    value a = Condition.create<String>((String fact) => !fact.empty);
    value b = Condition.create<String>((String fact) => fact.contains("str"));
    value result = a.and(b).evaluate("A string");
    assert (result);
    print(result);
}

He further advised, "It could be simplified a bit if You would not pass condition to and and or but function reference like in create so it would be: "

interface Condition<Fact>{

    shared static Condition<Fact> falseCondition => object satisfies Condition<Fact> {
        shared actual Boolean evaluate(Fact fact) => false;
    };
    shared static Condition<Data >create<Data>(Boolean(Data) evala)=> object satisfies Condition<Data>{
        shared actual Boolean evaluate(Data fact) => evala(fact);
    };

    shared formal Boolean evaluate(Fact fact);

    shared default Condition<Fact> and(Boolean(Fact) other)=> object satisfies Condition<Fact>{
        shared actual Boolean evaluate(Fact fact) => this.evaluate(fact) && other(fact);

    };

    shared default Condition<Fact> or(Boolean(Fact) other)=> object satisfies Condition<Fact>{
         shared actual Boolean evaluate(Fact fact) => this.evaluate(fact) || other(fact);
    };

    shared default Condition<Fact> not=> object satisfies Condition<Fact>{
        shared actual Boolean evaluate(Fact fact) => !this.evaluate(fact); 

    };

}
shared test void testConditions(){
    value a=Condition.create<String>((String fact) => !fact.empty);
    value b=((String fact)=> fact.contains("A"));
    value result=a.and(b).evaluate("A string");
    assert(result);
}

He further commented, "the second option wont work if You would b.and(a) because b is now just a function and not Condition probably there is a way to make it less verbose but i don't know the syntax"