• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Macros

Does anybody know why Gamemaker refers to constants as macros? To me, a macro is something that performs a particular of predefined action. A constant is one value that never changes.

This isn't stopping me working I'm just curious. It feels as though I have missed something fundamental in terms of my understanding.
 
  • Like
Reactions: Mut

gnysek

Member
There's are two costant types in GMS 2 - macros and enums, which are replaced to their values during compile. So macro is one of two constants, that's why it may referee.
 
I'm still a little confused. I thought enums were just to save time typing. What is the fundamental difference between.

enum rainbow_colors
{
red = 5,
orange = 6,
yellow = 15,
green = 20,
blue = 25,
indigo = 30,
}

and

#macro red 5
#macro orange 6

etc..

Another point with this. I noticed in the GMS example which I modified in order not to confuse the question. It was originally written like this.

enum rainbowcolors
{
red = 5,
orange = 5 * 2,
yellow = 15,
green = 20,
blue = 25,
indigo = 30,
}

What is orange = 5 * 2 about. It's a constant/enum. It's 10 not 2 * 5.

What is enum in this context and why do they use the syntax of red = 5 where, as constants are just #macro red 5

Not something I have needed to use in GMS. I make good use of constants, not so much enums. Just wondering how useful this actually is in practice. It's hard for me to visualize when I don't need to use them.

// SOUND CONSTANTS

#macro const_sound_checkbox_click_on snd_click_on
#macro const_sound_checkbox_click_off snd_click_off

is the same as

enum sounds
{
const_sound_checkbox_click_on = snd_click_on (Not to confuse things snd_click_on is techincally a constant in itself (Sort of (GMS asset)))
}
 
Last edited:

Nidoking

Member
To answer this question, let's look at the example you called out. Let's compare
GML:
#macro orange 5 * 2
to using
GML:
orange = 5 * 2
in an enum.

In the first case, the compiler will replace the token "orange" with the characters "5 * 2" (quotes added for clarity) anywhere it appears. In the second case, the compiler will evaluate 5 * 2 to a number (10) at compile time and store 10 as the value of orange in the enumeration.

Now, it might be silly to do this, but suppose that you did something like mycolor = 100 / orange. In the first case, this would expand to mycolor = 100 / 5 * 2, which would evaluate left to right and give you 40 rather than the expected 10. For this reason, you would want to define the macro as
GML:
#macro orange (5 * 2)
if you wanted to use it this way. But the point is that the macro is just a substitution of characters - there is no processing on them until they're put into place as part of another statement. The enumeration, on the other hand, is evaluated to a value at compile time, so using mathematical expressions is valid here. 100 / rainbowcolors.orange immediately becomes 100 / 10 as desired. Using 5 * 2 in a macro would mean that every time you use the macro, it has to multiply 5 * 2. In the enumeration, that happens only once, when it's defined.

In terms of use, I like using enumerations to make it clear that a particular set of values are all of the allowed values for a type. I could do a switch on a variable with a rainbowcolors value, and I know what all of the possible values are. If I'm using an integer and the values are macros, there might be other values. Since GML is not strictly typed, that's not as useful as it might be in other languages, but it's likely more comfortable for people who have worked with those languages. In practice, there's no difference between integer-valued macros and an enumeration other than notation.
 
Awesome thank you. I may have confused the situation when I said constant when I meant to say define. As I understand it, contents are not the same as 'define'.

But you confirmed what I thought in terms of Gamemaker at least. Enum is just a nice way to list '#macros' in an easy to read way.

It really makes no difference these days but I like to know these things. I don't like it when people just say 'ah computers are really fast these days who cares'.

I care a lot. Thanks for the considered reply. (Meaning that I could just use variables that never change, they don't cost much who cares.)
 
8

8BitCodeworks

Guest
The way that macros generally work in programming languages is that all macros are replaced before the program is compiled. So if you have a #macro X x+5 or something, everywhere X appears in the source code it will be replaced with x+5. What macros are really saying is "everywhere you see X, replace it with this text." So they're not constants per se, but they function like them if you use them for simple replacements.

Personally I like using them quite a lot. If you refer to sprSomeSprite in your script, even if you only refer to it once, it should get a macro at the top of the Create event to give that a name at the very least. If you use sprSomeSprite in two or more places then not only does it have a meaningful name in the script, but replacing that with another sprite doesn't require you to hunt down all the times you referenced that sprite. Similarly with any magic numbers, if it's not painfully obvious what the number is, it should get a macro giving it a name. This, again, also prevents bugs from occurring when you forget to change one instance of a magic number.
 
That's watered my ears some, what. Or my eyes in this case. I love to use constants for the same reasons as you do. I was going to relax a little and say only use them if it appears more than one time, but no, you are quite correct one time is enough.

In terms of redefining I do this at the beginning of every project.

// FORCE BOOLEAN VALUES

#macro true bool(1) // Redefine 1 as true
#macro false bool(0) // Redefine 0 as false

Unfortunate example as we should not have to do this but here we are.

show_debug_message(true + true); = 2 makes me want to shed a few tears.

And yes I use them to avoid magic numbers. Magic numbers can go to hell. I don't even use them for things I know to be a constant value. If I know for a fact that the transparency of an object is always equal to one I still use a variable or constant/define/macro to define it.

It's nice to know I'm not alone in this concept.
 

GMWolf

aka fel666
Magic numbers can go to hell, but the nly magic numbers should.
1 to mean 100% (alpha etc). 2 to mean 1/2 or double (binary trees, etc). 8 to mean 8 bits, 1024 to mean 1Kib, etc etc, none of those are magic. They have enough meaning by themselves.

Remember macros are not just for constants. They are essentially text substitution (although internally they work on the AST).
That means you can do a lot more than just do constants. Eh:
Code:
#macro keyframe if time == 

keyframe 0 {
  //Do stuff
}

keyframe 30 {

}

keyframe 60 {

}
 
Just to illustrate how macros are NOT constants, I use macros as shortcuts to common functions I use but don't always want to type out. One thing I use them for a lot is access to properties of the display, camera, and view. Like so:


GML:
///Views and Camera
#macro CAM view_camera[0]
#macro VIEW_BASE_W 960
#macro VIEW_BASE_H 540
#macro VIEW_FULL_W (DISP_W / ceil(DISP_W/VIEW_BASE_W))
#macro VIEW_FULL_H (DISP_H / ceil(DISP_H/VIEW_BASE_H))
#macro VIEW_W camera_get_view_width(CAM)
#macro VIEW_H camera_get_view_height(CAM)
#macro VIEW_L camera_get_view_x(CAM)
#macro VIEW_T camera_get_view_y(CAM)
#macro VIEW_R camera_get_view_x(CAM)+VIEW_W
#macro VIEW_B camera_get_view_y(CAM)+VIEW_H
#macro VIEW_CENTER_X VIEW_L + VIEW_W/2
#macro VIEW_CENTER_Y VIEW_T + VIEW_H/2
#macro DISP_W display_get_width()
#macro DISP_H display_get_height()
#macro GUI_CENTER_X display_get_gui_width()/2
#macro GUI_CENTER_Y display_get_gui_height()/2
#macro GUI_R display_get_gui_width()
#macro GUI_B display_get_gui_height()
#macro MOUSE_X_GUI device_mouse_x_to_gui(0)
#macro MOUSE_Y_GUI device_mouse_y_to_gui(0)
#macro ZOOM_IN .5
#macro ZOOM_NORMAL 1
#macro ZOOM_OUT 2
So now I have macros that represent my view's center ready at hand, or anything else I might need.
 
In C/C++/C#, this would be like the #define preprocessor directive. It's called a macro. Not exactly the same as a constant, although it can be used as such. Macros are much more powerful than traditional constants in that they can contain actual code. Constant variables can only contain values.
 
OK, I think I'm getting there. I think I'm struggling with terminology rather than understanding. If you could clarify which of the statements are true:-

1) A macro is exactly the same as an enum with the exception of quantity. (You can write things like a list and have the numbers automatically assigned numerically and respectively, 0 to infinity)

2) A macro in GMS terms is the same as a constant, not a define

3) A constant or a 'macro' can have code attributed to it but only runs once and once run (runtime) has a set value based on the initial parameters (this = 2 * 2). And this can't be changed.

4) A define (Not available in GML as far as I have conceived it) is a string of text that a human can read is attributed to a number that is set absolutely. (This = 4)

5) You can't modify a 'macro' once set post (runtime)
 

chamaeleon

Member
An enum represent values with given names, a macro represents textual replacement, which may or may not correspond to a value. For example, look at FrostyCat's OOP implementation code, https://github.com/dicksonlaw583/FakeOop/blob/master/scripts/o/o.gml.
GML:
#macro Begin { __fakeoop_seeking__ = false;
#macro End }
So for example, typing Begin in your code would expand to { __fakeoop_seeking__ = false;, and End would expand to }, neither of which are constant values, it's just blocks of code.
 
1) False. An enum can only be a whole number value. No 1.0321 or whatever. You also can't assign an enum to run a function like my macros above. That being said, I've completely stopped using enums in place of macros as they are more versatile, and the benefits of an enum are really only apparent in a strongly typed language.

2) False. A constant implies that it is always the same value forever. A macro is a "code snippet" that will be interpreted at run time. That's why my view position macros work. View position as a constant with a moving camera would be pointless.

3) false as explained above. Anywhere you use the macro it's like copying and pasting that code in place of the macro.

4) Again... false. That's more the purpose of an enum (enumerator). Instead of saying "if(facing_direction == 2)" you use an enum to say "if(facing_direction == Direction.west". 2 doesn't "mean" anything it's just a unique identifier for the different directions.

5) True. Again, think of it like when you press play and build your game, the compiler grabs the definition of the macro, and does a huge search and replace for everywhere that macro is used. It takes out the macro, and replaces it with the code.
 

samspade

Member
I think all of this has mostly been said above but I think it is easier to think of macros as simple text replacement. They are effectively copy and paste at compile time. Enums are pure numbers, specifically integers. They have some inherent values, such as starting at 0 automatically and increasing by 1, making them very useful for referencing positions in arrays and lists. Allowing, for example you to easily insert, remove, and rename variables without having to change anything else (not true with macros because you have explicitly said what a macro stands for).

I have more detailed explanations here:


 
I think I'm good. I like to be punished for misunderstandings. Gamemaker is not good at telling you when you have a problem. It's just like ok 'that's cool for now'. I'm like 'no' tell me I'm wrong.

What is the 'crack' with programming today? Is it like 'psychology today' or is there a good reason for these things?

Those videos did help explain by the way. I'm just undecided if I like it or not.
 
Last edited:

GMWolf

aka fel666
I don't really know in the GM world. But in the C world, macros are seen as somewhat taboo in modern programming.
They are usually used to obscure what is actually happening behind the scenes.
Often they are still used for convenience.


One place where macros are indispensable is configurations.
You can define a macro deffirently for different configurations.
This can be used to set different values, but more importantly is lets you substitute completely different code.

For instance, say you wanted to change object colours all over your code.
On most platforms you may like to use shaders, but on html5 you would use image_blend.

Rather than checking the platform with an if everytime, you could define the following macros:

Code:
#macro set_color:pc_mobile set_shader(shdColor)
#macro set_color:html5 image_blend = c_red
(My GML is very rusty, so the exact macro definition style might be a little different, but you get the gist)
 

gnysek

Member
In my opinion the only case when enum have difference with macros is that when you're relying on auto-indexing following elements from 0 to N, otherwhise, when giving them indexes manually, I see no difference with macros (ok, maybe it's easier to find them using code completion dropdown).

So - macros are "find & replace when compiling" and enums are "grouped macros, with integer indexes, either from 0 to N or other if manually assigned". Nothing more. If there's "constant" word used in manual, it's rather used in context that they will always give us constant value, there's no way to change their definition at some point of game (but in fact macros and enums aren't existing on compiled game). I think that word "literal" is better than "constant".
 

GMWolf

aka fel666
Enums have a different implicit meaning.
They are not really meant as a macro for numbers, but really as labels. Values that need to be differentiated from each other.
The fact they are internally represented as numbers should realy be a useful fact for implementing things around enums and not the primary way to think of enums.

For instance the for cardinal directions (up down left right). They are not numbers, nor are they strings etc.
You *could* represent them as vectors but I think enums lend themselves better.

You can, for instance, give each direction a different bit (1, 2, 4, 8), now you can use them as flags you can or together. This could let you describe sets of direction in a single value. Again this using enums as a way to represent values that otherwise don't have a numerical value, and using the fact they are represented numerically in order to implement concepts around them.


Most importantly it's clear to readers that enum values are related. That each entry describes a distinctive, unique value from a set.
 
Top