Hi. What is the best way to get variable value in nim that was previously declared in c/cpp code (or inside "emit")? are there a lot of bugs or i'm just use it wrongly?
look here for different variants tried by me https://github.com/nim-lang/Nim/issues/16890#issuecomment-1089709161
one example:
proc getint*():cint =
var i {.nodecl}: cint
{.emit:"int i; i = 14;"}
return i
echo getint()
in manual we see: "The nodecl pragma can be applied to almost any symbol (variable, proc, type, etc.) and is sometimes useful for interoperability with C: It tells Nim that it should not generate a declaration for the symbol in the C code. " I assume this pragma should not generate a declaration of any symbol, but manual says "ALMOST" any symbol. what does it mean? :)
(Also return and result has strange behaviour too. look at examples at the url above.)
As I said in the issue, at least one thing that's immediately obvious is the fact that you haven't used backticks so that Nim can actually name the variable the same way - Nim mangles variable names when compiling to C, so you need to do that:
proc getint*():cint =
var i {.nodecl}: cint
{.emit:"int `i`; `i` = 14;"}
return i
echo getint()
Sorry for bringing confusion and for being so unclear with describing the issue.
To understand what I mean let's stick to "nodecl" pragma. (we don't need to discuss "backticks" or "emit array" because they are serving a different purpose.)
Manual says, "It tells Nim that it should not generate a declaration". but in fact it does, at least while used inside local scope (in a proc, for example).
this works correctly:
{.emit:"int i; i = 14;"}
var i {.nodecl importc}: cint
echo i
put code inside a proc and nodecl has no effect:
proc getint() =
{.emit:"int i; i = 14;"}
var i {.nodecl importc}: cint
echo i
getint()
So, in my opinion the Manual has to be updated like this:
This can shine light on how things actually work. am I right?
nodecl/cdecl/fastcall/nimcall are function calling convention. They are not for variables.
nodecl main use-case is to wrap compiler builtin functions that are not defined in any header.
as for return vs result, i found the difference in generated c code. new scope is created when using return.
example:
int i;
...
{ // <---- this
int i;
...
goto BeforeRet_; // <---- this
}BeforeRet_: ; // <---- this
return result;
this is not an issue of itself but in my case it had lead to confusion why two variables with the same name were not colliding with each other when using return, but they collided when i changed return i to result = iIt was my preferred way of getting value out of emit body to nim side. That was working with global variables for me and using it in local scope seemed not against the rules of the Manual.
Now with your help i know how it works in reality, so I must use another way (declare variable before the emit and pass it inside with help of emit-array notation, though i think it's a bit ugly to use all that square-brackets/commas/quotes(single or triple)).
it is more simplier to just write something like:
so Nim will not declare it but will assume that it was already declared somewhere above. It will allow to write simpler and clearer code.
I'm not asking to implement it. :-) I understand that using emit pragma is already very ugly by itself. I just think that the Manual is not clear enough on how to use decl pragma with variables correctly. for me it was just a simple logic - "nodecl" always means "no declaration", in other words "tell nim to assume that variable was already declared"
The hack I've found to do this:
proc foo() =
proc cleanup(p:pointer){.used.} =
echo "cleanup"
var x {.codeGenDecl:"",nodecl,noinit.}: seq[int]
{.emit:[typeof(x)," ",x," __attribute__((cleanup(",cleanup,"))) =",@[5],";"].}
echo x
foo()
sorry for conflating my experiment with this post's question, which was, how do you nodecl a variable.
My experiment was exploring whether theres a way to supply a finally block when unwrapping a Result
That's one of the workarounds. Another is to make it a fake glabol, thus {.nodecl.} applies.
proc main =
{.emit: "int x = 1;".}
var x {.importc, global, nodecl.}: cint
echo x
main()