Thou shallt always google first!
Its because its defined as a function that takes a var:
window(var evt:Event)
Which most likely is buggy and Ill fix it. :)
Ok.. I dont get it:
template evConv(name, name2, ptype: expr; valid: set[EventType]): stmt {.immediate.}=
proc `name`* (event: var Event): ptype =
assert event.kind in valid
return cast[ptype](addr event)
proc `name2`* (event: var Event): ptype =
assert event.kind in valid
return cast[ptype](addr event)
with the var in the function parameter I need to make a var of anything I want to pass in before doing so, meaning overhead. But removing the var causes this me to fail when getting the addr of event.
There is most certainly a great explaination why this is so, but my small head doesnt get it.
Is it considered a nim "thing" to always shadow the in params in local vars and therefor this is mostly an non issue?
I need to make a var of anything I want to pass in before doing so, meaning overhead.
var parameter is a good choice if you have objects, maybe allocated on the stack. I think generally var parameters are much cleaner than pointers and it avoids the addr operator -- I have used var parameters often in the GTK3 related wrappers. Problem is of course, when you have to pass constant values, or maybe NULL pointer, which some GTK functions accept.
jgoodgive: with the var in the function parameter I need to make a var of anything I want to pass in before doing so, meaning overhead. But removing the var causes this me to fail when getting the addr of event.
You need to pass the parameter as a var so that it actually has an address. If it doesn't, it may be a temporary value and casting it to a pointer type is likely to blow up in your face, anyway. But honestly, the entire construct is extremely fragile to begin with. I'm not exactly sure what you are trying to do here, but there's no guarantee that the result will live long enough to be safely usable. I'd be worried about correctness before performance here myself.
Thanks for explaining it. I had a hunch that it had to do with the stack and how long things where alive. But I didnt know that var worked like this.
@jehan: its the sdl wrapper. It works fine with vars and it makes sense that is cant be a random pointer. But I agree that there is some sense of risk here. Who owns what and how long and whats going on. In C I would kind of know what to send and what to expect but I have to say that since nim is hiding alot of the pointer/variable/stack/heap stuff involved I inclined (for better or worse) that if nim isnt complaining it is doing something brilliant with my problem.
That is a bit of a nim problem. Should I care what is happening and does nim hide it from me in that case or should nim handle it and can I trust it?
That is a bit of a nim problem.
I don't see the problem. You happen to know how C maps to the hardware, but don't know yet how Nim does it. And yet it's simple enough: It seq, string that are not const live in the GC'ed heap, ref lives in the GC'ed heap, ptr can point to anything and var is a hidden pointer to anything for which the compiler nevertheless tries to prove safety. And it does so quite successfully; I've yet to get a single bug report about it. (Note that it's still slightly wrong https://github.com/Araq/Nim/issues/124)
I have never encountered a place where nim doesnt prove safety (newb I may be) but still I cannot quite see why a var is needed. Is it to guard from doing a addr on a ptr?
jgoodgive: I have never encountered a place where nim doesnt prove safety (newb I may be) but still I cannot quite see why a var is needed. Is it to guard from doing a addr on a ptr?
The simple explanation is that the semantics would be unclear even if it were safe. Consider the following example (hypothetical, because it won't compile):
proc f(x: int): ptr int =
addr(x)
let y = 1
let z = f(y)
What is the value of z? Is it the address of x or y? What if instead of an int we have a type with a {.bycopy.} or {.byref.} annotation? If it is {.byref.}, do you want to take the address of the pointer or the address of the thing being pointed to? Will code break in unexpected ways if you change from {.bycopy.} to {.byref.} or vice versa? Requiring var removes these ambiguities.
Note that we haven't even started to worry about the semantics of, say, f(1) or f(y+y).
@Jehan
How could I make your last example compile? Is it expected to anyway? The following modification does not compile:
proc f(x: var int): ptr int =
addr(x)
let y = 1
let z = f(y)
One more: is there any way to have this compile?
import tables
var someTable = initTable[string, tuple[list, adv: string]]()
proc doIt(descr: var tuple[list, adv: string]): seq[string] =
descr.list = "LIST"
descr.adv = "ADV"
discard doIt(someTable["bac"])
echo someTable["bac"]
@axben if you don't already know @jehan example would compile as:
proc f(x: var int): ptr int =
addr(x)
var y = 1
let z = f(y)
echo z[]
I see it like this: If I want to take the address of something it needs to have one :)
let y = 1
let a = addr(y) # Error: expression has no address
So what could "var" possibly do "in the background":
proc f(x: ptr int): ptr int =
x
var o = 1
let y = addr o
let z = f(y)
echo z[]
I strongly believe nothing should be "automatic" here. I do not want to say "let" and then the compiler suddenly makes this a "var".
I also think it is quiet logical that a "var" parameter needs to be a "var" and not a "let" just by how the stuff is called.
Imho a "var" parameter is about being able to modify it's contents inside the proc. Which is not possible with a "let" value anyway.
@jehan I think "making it compile" shows why the other form does not. With code instead of words.
As for def's sample: I overlooked the let, so sorry for the noise.
However the question rsp. mget() still stands.
axben: However the question rsp. mget() still stands.
What you are looking for is overloading based on the result type of a procedure. This is currently not possible, though I seem to remember Araq mentioning something about looking into it in the future. (I'm not positive that I remember that correctly, though.)
var someTable = initTable[string, tuple[list, adv: string]]()
proc doIt(descr: var tuple[list, adv: string]) = descr.adv = "ADV"
# The VAR is here ^
# Call as necessary now
doIt(someTable.mget("bac"))
# Call as it might be possible
doIt(someTable["bac"]) # someTable["bac"] is a non-constant tuple[list, adv: string]
axben: I just think that [...] could allow the second call of doIt() (please see below) compile
That's precisely what I mean. You need [] to have overloaded implementations for var T and T result types and then pick the correct implementation for the call. Currently, this is not possible, so we need a differently named function in lieu of [] for the var T result. Allowing overloading based on the result type (note that the semantics for that can be somewhat tricky) would permit us to use [] for both and doIt(someTable["bac"]) to work.
Overloading based on 'var T' ----------------------------
If the formal parameter f is of type var T in addition to the ordinary type checking, the argument is checked to be an l-value. var T matches better than just T then.
This means we can have a tables.[] that works with 'var' but unfortunately it's a breaking change as the semantics are different: currently mget raises an exception, but [] does not. For sanity we need to make both [] raise an exception. Which is probably a good idea anyway though.
Overloading based on 'var T'
This works for Table but not TableRef because you still can't overload based on return type.
Oh, right. My bad. I'll give it another try.
Edit: For CountTableRefs it's definitely a problem. You can't get 0 as the default value anymore.