One of my favorite things from C#/Java are interfaces and I've been trying to 
work on writing some macros can generate an interface and allow you to 
implement it. So far I've played around with getting some sort of "toy 
interface," working as well as some of the macros too.

Here is my initial prototype code:
    
    
    type
      # The interface
      IWorker* = object
        obj*: ref RootObj
        setup_proc*: proc(obj: ref RootObj, a, b: float)
        run_proc*: proc(obj: ref RootObj)
        getResult_proc*: proc(obj: ref RootObj): float
      
      
      # A base type
      MathOperation = object of RootObj
        result: float
      
      Adder = ref object of MathOperation
        first, second: float
      
      Subtracter = ref object of MathOperation
        initial, subtraction: float
    
    #  Multiplier = ref object of MathOperation
    #    value, multiplier: float
    #
    #  Divider = ref object of MathOperation
    #    numerator, divisor: float
    
    
    #=== Procs for the IWorker ===#
    proc setup(worker: IWorker; a, b: float) =
      worker.setup_proc(worker.obj, a, b)
    
    proc run(worker: IWorker) =
      worker.run_proc(worker.obj)
    
    proc getResult(worker: IWorker): float =
      return worker.getResult_proc(worker.obj)
    
    
    #=== Procs for the Adder ===#
    proc Adder_setup(obj: ref RootObj; a, b: float) =
      var this = cast[Adder](obj)
      this.first = a
      this.second = b
    
    proc Adder_run(obj: ref RootObj) =
      var this = cast[Adder](obj)
      this.result = this.first + this.second
    
    proc Adder_getResult(obj: ref RootObj): float =
      var this = cast[Adder](obj)
      return this.result
    
    
    #=== Procs for the Subtractter ===#
    proc Subtracter_setup(obj: ref RootObj; a, b: float) =
      var this = cast[Subtracter](obj)
      this.initial = a
      this.subtraction = b
    
    proc Subtracter_run(obj: ref RootObj) =
      var this = cast[Subtracter](obj)
      this.result = this.initial - this.subtraction
    
    proc Subtracter_getResult(obj: ref RootObj): float =
      var this = cast[Subtracter](obj)
      return this.result
    
    
    var
      worker: IWorker
      
      # Slap together the interface
      add = IWorker(
        setup_proc: Adder_setup,
        run_proc: Adder_run,
        getResult_proc: Adder_getResult
      )
      
      sub = IWorker(
        setup_proc: Subtracter_setup,
        run_proc: Subtracter_run,
        getResult_proc: Subtracter_getResult
      )
    
    
    # Assign an object (the objects in this case really don't have any special 
data)
    add.obj = new(Adder)
    sub.obj = new(Subtracter)
    
    
    # Try out the workers
    worker = add
    worker.setup(10.0, 2.0)
    worker.run
    echo worker.getResult   # Should be 12in
    
    worker = sub
    worker.setup(10.0, 2.0)
    worker.run
    echo worker.getResult   # Should be 8
    
    

Right now I've got a macro called INTERFACE that acts like the one below and 
can produce the type object.
    
    
    INTERFACE IWorker ACTS_ON MathOperation:
      proc setup(a, b: float)
      proc run()
      proc getResult(): float
    
    # Produces this specifically:
    #type
    #  # The interface
    #  IWorker = object
    #    obj: ref MathOperation
    #    setup_proc: proc(obj: ref MathOperation; a, b: float)
    #    run_proc: proc(obj: ref MathOperation)
    #    getResult_proc: proc(obj: ref MathOperation): float
    
    

But I've been doing some thinking and wondering if I should have the interface 
actually act on an object. This would get rid of the obj field and remove the 
insertion of the ref RootObj`s from the generated `type object interface. This 
way an interface isn't tied to working on one type of object, but instead an 
interface could be a "collection of functions (stored in an object) that can 
act on any types," instead of a "contract for operations on a specific type."

I'm wondering which road I should go down. The "contract," way would closely 
represent how interfaces work in C#/Java, but I feel that the "collection," 
idea would give more flexibility to Nim. What's your input?

Reply via email to