Search code examples
cjuliacompile-time-constant

Equivalent of C programming syntax "#define" in Julia language


In the C Programming Language, the #define directive allows the definition of macros within the source code. These macro definitions allow constant values to be declared for use throughout the code.

Macro definitions are not variables and cannot be changed by the program code like variables. We generally use this syntax when creating constants that represent numbers, strings or expressions. like this

#include <stdio.h>

#define NAME "Jack"
#define AGE 10

int main()
{
   printf("%s is over %d years old.\n", NAME, AGE);
   return 0;
}

The beauty is that if I have multiple functions in my code I don't need to input the constant variable into every function, and the compiler simply replaces the defined expression with proceeding value.

Now my question is: Is there any equivalent command in Julia programming for this?

for example

density = 1 # somehow a defined variabe.
function bar(g)
    t =  density +g
end
function foo()
     r = dencity + 2
end 

main()
   g = 10;
   foo()
   bar(g)
end

Solution

  • You can emulate the C #define behavior with a macro in Julia.

    macro NAME()
        return :("Jack")
    end
    
    macro AGE()
        return :(10)
    end
    

    In the Julia REPL, typing @NAME will return "Jack".

    julia> @NAME
    "Jack"
    
    julia> @AGE
    10
    

    Remember to enclose the macro call in parentheses for safety, e.g.,

    julia> println("Hello ", (@NAME))
    Hello Jack
    
    julia> println(@NAME * " is " * repr(@AGE) * " years old")
    ERROR: syntax: "*" is not a unary operator
    
    julia> println((@NAME) * " is " * repr(@AGE) * " years old")
    Jack is 10 years old
    

    But is this really necessary? The idiomatic way in Julia is to define global const variables. Although the documentation discourages the use of global variable for performance reasons, a macro like this does not help you on performance, and you can tell it from the LLVM code.

    macro NAME()
        return :("Jack")
    end
    
    const name = "Jack"
    
    function f_hello_global()
        println("Hello ", name)
    end
    
    function f_hello_macro()
        println("Hello ", (@NAME))
    end
    

    For trivial functions like these, you'll find that the LLVM codes look exactly the same (too long; not shown here).

    julia> @code_llvm f_hello_global()
    . . . 
    
    julia> @code_llvm f_hello_macro()
    . . .
    

    Edit: By the way, I would argue that if you have a need to use the global variable, then use it. The argument made in the Julia documentation (current stable version: 0.6.2) is that it may slow down the performance sometimes. However, imagine if a constant is used in 100 functions spread in 20 modules, would you prefer to write the same line of code 100 times and painstakingly check if the numbers are consistent across modules, or would you define it once and use it in all places? I'd think that the proper use of global constants makes the code clean and easy to maintain, and this concern often prevails over a small gain in performance.