15

I’m creating an application where an unlimited amount of rules could be applied to an unlimited amount of nodes.

I'm planning on using core data as the datastore and creating a simple one to many relationship between node and rule.

In objective-c I would probably create classes for each of the rules and have them conform to a protocol.

NSArray *ruleClassNames = @[@"SimpleRuleA",@"SimpleRuleB",@"BigFatComplicatedRule"];

int ruleType = [someNode.rules firstObject];
Class class = NSClassFromString(ruleClassNames[ruleType]);

[(ruleClassProtocol*)class performSelector:@selector(runRuleOnNode:) withObject:someNode];

What would be the most elegant way of doing this in swift?

Chris
  • 2,727
  • 2
  • 27
  • 28
  • Could you define "elegant"? `enums` are made to work with `switch` so I don't really understand why you want to use an enum and avoid `switch`. – Sulthan Jul 17 '15 at 12:55
  • @Sulthan you obviously understand the idea of enums, but read the question again and see if you can come up with a solution... – Chris Jul 17 '15 at 12:59
  • Well, your Obj-C code can be easily written into Swift (of course, you would use types directly istead of using names of types). Whether that would be elegant is a matter of taste. – Sulthan Jul 17 '15 at 13:15

2 Answers2

32

Solution

If we want to add a closure to an enum first of all lets define the type of the closure.

typealias Logic = () -> (String)

Then the enum:

enum Rule {
    case SimpleRuleA(Logic)
    case SimpleRuleB(Logic)
    case BigFatComplicatedRule(Logic)
}

That's it! Let's see now how to use this.

Usage

Let's create a couple of Logic(s):

let logic0 : Logic = { return "Logic 0" }
let logic1 : Logic = { return "Logic 1" }

And now a function to process a Rule

func processRule(rule:Rule) -> String {
    switch rule {
    case .SimpleRuleA(let logic): return "Simple Rule A, logic: \(logic())"
    case .SimpleRuleB(let logic): return "Simple Rule B, logic: \(logic())"
    case .BigFatComplicatedRule(let logic): return "Big Fat Complicated Rule, logic: \(logic())"
    }
}

Finally let's combine every possible rule with every possible Logic...

let aWithLogic0 = Rule.SimpleRuleA(logic0)
let aWithLogic1 = Rule.SimpleRuleA(logic1)
let bWithLogic0 = Rule.SimpleRuleB(logic0)
let bWithLogic1 = Rule.SimpleRuleB(logic1)
let fatWithLogic0 = Rule.BigFatComplicatedRule(logic0)
let fatWithLogic1 = Rule.BigFatComplicatedRule(logic1)

... and let's test it

processRule(aWithLogic0) // "Simple Rule A, logic: Logic 0"
processRule(aWithLogic1) // "Simple Rule A, logic: Logic 1"
processRule(bWithLogic0) // "Simple Rule B, logic: Logic 0"
processRule(bWithLogic1) // "Simple Rule B, logic: Logic 1"
processRule(fatWithLogic0) // "Big Fat Complicated Rule, logic: Logic 0"
processRule(fatWithLogic1) // "Big Fat Complicated Rule, logic: Logic 1"

Is this solution close to what you had in mind?

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
-1
    enum FunctionEnum
   {
     case binaryOperation((Double,Double)->Double)
     constant(Double)
   }

1.you can associate values to enum cases , hence it also has type here for example binaryOperation is of type ((Double,Double)->Double) which means its of type a closure which accepts two doubles and return one

Sandy Rawat
  • 685
  • 7
  • 12