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?
Maybe you want to take a look at my Go like interfaces. http://forum.nim-lang.org/t/2422#14994
The difference between Go like interfaces and Java like interfaces, is that object that implement that interface does not need to be a ref object or inherit from root in any way. That object can be a plain old data object. The vtable pointer is not stored in the object at all, but a pointer that is stored in an interface is actually a tuple with the pointer to that object, and the pointer to the vtable that implements the interface for that object.
https://github.com/zielmicha/collections.nim
Joy! Great link.
@Krux02, thanks for your ideas too. Very interesting discussion, but too long for tonight. Do you have a GitHub repo I can "star"?