Hi!
I'm trying to make a simple interface:
type
# Variant 1
#Widgetable* = concept w
# w.`x=`(x: int) # <- properties do not seem to work with old concepts
# w.`y=`(y: int)
# w.x() is int
# w.y() is int
# w.draw()
# Variant 2
Widgetable* = concept
proc `x=`(self: var Self, x: int) # <- mutable self does not work in converter
proc `y=`(self: var Self, y: int)
proc x(self: Self): int
proc y(self: Self): int
proc draw(self: Self)
type
WidgetInterface = object
`x=`: proc(x: int)
`y=`: proc(y: int)
x: proc(): int
y: proc(): int
draw: proc()
converter toWidgetInterface(w: var Widgetable): WidgetInterface =
result.`x=` = proc(x: int) = w.`x=`(x)
result.`y=` = proc(y: int) = w.`y=`(y)
result.x = proc(): int = w.x()
result.y = proc(): int = w.y()
result.draw = proc() = w.draw()
type
Position = tuple[x: int, y: int]
Widget* = object
fgcolor*: int
bgcolor*: int
pos*: Position
proc `x=`(self: var Widget, x:int) =
self.pos.x = x
proc `y=`(self: var Widget, y:int) =
self.pos.y = y
proc x(self: Widget): int =
return self.pos.x
proc y(self: Widget): int =
return self.pos.y
proc draw(self: Widget) =
echo("drawing widget")
var
w: Widget
wi: WidgetInterface
wseq = newSeq[WidgetInterface]()
wi = toWidgetInterface(w)
wseq.add(toWidgetInterface(w))
wseq[0].draw()
When compiling with variant 1, the following error shows:
/home/sei/projects/nugfx/tests/test.nim(73, 23) Error: type mismatch
Expression: toWidgetInterface(w)
[1] w: Widget
Expected one of (first mismatch at [position]):
[1] converter toWidgetInterface(w: var Widgetable): WidgetInterface
/home/sei/projects/nugfx/tests/test.nim(6, 6) Widgetable: undeclared field: 'x='
/home/sei/projects/nugfx/tests/test.nim(6, 6) Widgetable: type expected
/home/sei/projects/nugfx/tests/test.nim(6, 11) Widgetable: object constructor needs an object type [error]
/home/sei/projects/nugfx/tests/test.nim(7, 6) Widgetable: undeclared field: 'y='
/home/sei/projects/nugfx/tests/test.nim(7, 6) Widgetable: type expected
/home/sei/projects/nugfx/tests/test.nim(7, 11) Widgetable: object constructor needs an object type [error]
Are old style concepts not compatible with properties?
With variant 2 a different error shows:
/home/sei/projects/nugfx/tests/test.nim(35, 32) Error: 'w' is of type <Widget> which cannot be
captured as it would violate memory safety, declared here: /home/sei/projects/nugfx/tests/test.nim(34, 29);
using '-d:nimNoLentIterators' helps in some cases. Consider using a <ref T> which can be captured.
Are converters not possible with a mutable argument?
How would I implement the suggestions to use a <ref T>?
Thanks!
I found a workaround:
type
Widgetable* = concept
proc `x=`(self: var Self, x: int)
proc `y=`(self: var Self, y: int)
proc x(self: Self): int
proc y(self: Self): int
proc draw(self: Self)
type
WidgetInterface = object
`x=`: proc(x: int)
`y=`: proc(y: int)
x: proc(): int
y: proc(): int
draw: proc()
converter toWidgetInterface(w: Widgetable): WidgetInterface =
let
w_ptr = w.addr # <- use a pointer here to work around compiler error
result.`x=` = proc(x: int) = w_ptr[].`x=`(x)
result.`y=` = proc(y: int) = w_ptr[].`y=`(y)
result.x = proc(): int = w_ptr[].x()
result.y = proc(): int = w_ptr[].y()
result.draw = proc() = w_ptr[].draw()
type
Position = tuple[x: int, y: int]
Widget* = object
fgcolor*: int
bgcolor*: int
pos*: Position
proc `x=`(self: var Widget, x:int) =
self.pos.x = x
proc `y=`(self: var Widget, y:int) =
self.pos.y = y
proc x(self: Widget): int =
return self.pos.x
proc y(self: Widget): int =
return self.pos.y
proc draw(self: Widget) =
echo("drawing Widget")
var
w: Widget
wi: WidgetInterface
wseq = newSeq[WidgetInterface]()
wi = toWidgetInterface(w)
wseq.add(w)
wseq[0].draw()
It's probably a bit dirty to use a pointer there, but I can continue with this for now :)
Update: The workaround does not like properties, but this here works:
type
Widgetable* = concept
proc setx(self: var Self, x: int)
proc sety(self: var Self, y: int)
proc getx(self: Self): int
proc gety(self: Self): int
proc draw(self: Self)
type
WidgetInterface = object
setx: proc(x: int)
sety: proc(y: int)
getx: proc(): int
gety: proc(): int
draw: proc()
converter toWidgetInterface(w: Widgetable): WidgetInterface =
let
w_ptr = w.addr # <- use a pointer error to work around compiler error
result.setx = proc(x: int) = w_ptr[].setx(x)
result.sety = proc(y: int) = w_ptr[].sety(y)
result.getx = proc(): int = w_ptr[].getx()
result.gety = proc(): int = w_ptr[].gety()
result.draw = proc() = w_ptr[].draw()
type
Position = tuple[x: int, y: int]
Widget*[T] = object
fgcolor*: T
bgcolor*: T
pos*: Position
proc setx(self: var Widget, x:int) =
self.pos.x = x
proc sety(self: var Widget, y:int) =
self.pos.y = y
proc getx(self: Widget): int =
return self.pos.x
proc gety(self: Widget): int =
return self.pos.y
proc draw(self: Widget) =
echo("drawing Widget at " & $self.pos.x & " " & $self.pos.y)
var
w: Widget[int]
wi: WidgetInterface
wseq = newSeq[WidgetInterface]()
wi = toWidgetInterface(w)
wseq.add(w)
wseq[0].draw()
wseq[0].setx(10)
wseq[0].draw()