This code works if let field1 is commented out, but with it it compiles returns test_deref.nim(19, 9) Error: type mismatch: got (untyped). It seems that the macro doesn't even run. Is this a bug?
import macros
type
B = object of RootObj
field1: int
type
A[T] = object
inner: T
macro `.`*(obj: A, v): untyped =
echo "running macro"
newDotExpr(newDotExpr(obj, newIdentNode("inner")), newIdentNode(v.strVal))
proc t1*() =
var f: A[B]
let field1 = 777 # <- if you comment this out, the code works
echo f.field1
t1()
Hmm, I think the macro gets confused somewhere along the line when you are trying to use field1 as the name for a local variable and the name of the field in your B object.
The macro would be working, however, the compiler notices that something is wrong and infers incorrectly the type of the f.field1 statement to be untyped and therefore fails to even hit the macro expansion because echo doesn't know how to print an untyped type.
To fix it, you can do this:
import macros
type
B = object of RootObj
field1: int
type
A[T] = object
inner: T
macro `.`*(obj: A, v): untyped =
echo "running macro"
newDotExpr(newDotExpr(obj, newIdentNode("inner")), newIdentNode(v.strVal))
proc t1*() =
var f: A[B]
f.inner.field1 = 777 # If you don't have a local variable named field1, then the code works as you expect
echo f.field1
t1()
But maybe it would help to understand why you were trying to use a local variable for field1.
I think overloading of . moves Nim beyond its breaking point and usually there are all sort of better designs, for instance simply writing foo["bar"] instead of foo.bar or coming up with a new operator like foo.?bar.
This whole feature needs to be in experimental.
@zielmicha
I'm using it to create a type that should behave like pointer/ref. pointer/ref types get automatic dereference automatically
I'm not sure if this is exactly what you need, and Araq would probably frown upon it, but I created a macro a little while ago that maybe does what I think you want. It's called subfield and you can look at the source here.
is there a better way to get this behaviour?
I think a converter would work too here.
Unfortunately it does not:
type
B = object
j: int
A = object
myB: B
converter toB(a: A): B =
return a.myB
var a: A
echo a.j # f.nim(13, 7) Error: undeclared field: 'j'
I think I will settle on autogenerating accessor procs.