Procedural type

A procedural type is internally a pointer to a procedure. nil is an allowed value for a variable of a procedural type.

Examples:

  1. proc printItem(x: int) = ...
  2. proc forEach(c: proc (x: int) {.cdecl.}) =
  3. ...
  4. forEach(printItem) # this will NOT compile because calling conventions differ
  1. type
  2. OnMouseMove = proc (x, y: int) {.closure.}
  3. proc onMouseMove(mouseX, mouseY: int) =
  4. # has default calling convention
  5. echo "x: ", mouseX, " y: ", mouseY
  6. proc setOnMouseMove(mouseMoveEvent: OnMouseMove) = discard
  7. # ok, 'onMouseMove' has the default calling convention, which is compatible
  8. # to 'closure':
  9. setOnMouseMove(onMouseMove)

A subtle issue with procedural types is that the calling convention of the procedure influences the type compatibility: procedural types are only compatible if they have the same calling convention. As a special extension, a procedure of the calling convention nimcall can be passed to a parameter that expects a proc of the calling convention closure.

Nim supports these calling conventions:

nimcall

is the default convention used for a Nim proc. It is the same as fastcall, but only for C compilers that support fastcall.

closure

is the default calling convention for a procedural type that lacks any pragma annotations. It indicates that the procedure has a hidden implicit parameter (an environment). Proc vars that have the calling convention closure take up two machine words: One for the proc pointer and another one for the pointer to implicitly passed environment.

stdcall

This is the stdcall convention as specified by Microsoft. The generated C procedure is declared with the __stdcall keyword.

cdecl

The cdecl convention means that a procedure shall use the same convention as the C compiler. Under Windows the generated C procedure is declared with the __cdecl keyword.

safecall

This is the safecall convention as specified by Microsoft. The generated C procedure is declared with the __safecall keyword. The word safe refers to the fact that all hardware registers shall be pushed to the hardware stack.

inline

The inline convention means the caller should not call the procedure, but inline its code directly. Note that Nim does not inline, but leaves this to the C compiler; it generates __inline procedures. This is only a hint for the compiler: it may completely ignore it, and it may inline procedures that are not marked as inline.

fastcall

Fastcall means different things to different C compilers. One gets whatever the C __fastcall means.

thiscall

This is the thiscall calling convention as specified by Microsoft, used on C++ class member functions on the x86 architecture.

syscall

The syscall convention is the same as __syscall in C. It is used for interrupts.

noconv

The generated C code will not have any explicit calling convention and thus use the C compiler’s default calling convention. This is needed because Nim’s default calling convention for procedures is fastcall to improve speed.

Most calling conventions exist only for the Windows 32-bit platform.

The default calling convention is nimcall, unless it is an inner proc (a proc inside of a proc). For an inner proc an analysis is performed whether it accesses its environment. If it does so, it has the calling convention closure, otherwise it has the calling convention nimcall.