GML Programming Patterns: Naming Standard 2k18

Part 1 of GML Programming Patterns Series

Motivation

A consistent, thorough naming standard has some huge advantages for us as programmers. If we’re consistent with our naming standard, then we have guidelines on how to write code that looks like everything else in our project - this makes a project much easier to read and much easier to maintain. Why? Simply because you’re not learning a new style or wondering what a variable is - the consistency is familiar so you immediately can understand _oh_this_variable_was_declared_in_this_file or ThisMustBeAnObject.

The Naming Standard that our Rousr projects strive to follow:

  • Resource names (i.e., an object, a sprite, a tileset) are PascalCase.
  • Instance variables use snake_case without a prefix.
  • Script function names are snake_case_and_all_lower_case (an exception to the Resource Name rule).

    • All Scripts include a function header.
    • Script / Event local variables are prefixed with a single underscore and use _snake_case:

      1
      var _test_var = 1;
    • “Private” Script Functions are prefixed with 2 underscores and still __snake_case. “Private” scripts are scripts intended to be internal… as-in, used by systems but not expected to be called by anything outside of the system’s own functions. You’ll see this in every single one of our extensions, for example.

  • Enums use PascalCase for each element, while enums are Pascal with the first character a capital E: ECapitalLetters.EnumCase
    • With rare exceptions, enums should have a final element called Num
      1
      2
      3
      4
      5
      6
      7
      enum EFruit {
      Apple = 0,
      Banana,
      Num
      };
      // if we're iterating fruit, we can use EFruit.Num as the exit condition in a for loop.

Some Conflicts?

A few issues do plague the naming standard, but it’s an ever evolving document for Rousr. At this point, any “major” change to the naming standard is heavily considered before implementing - we have many projects in the wild!

The biggest conflict we’ve got is that script_function_names can look like instance_variables and this can sometimes lead to some confusion with naming instance variables in particular… fortunately, the GameMaker Studio 2 parser helps us greatly with color coding things so a script function should mostly be identifiable by IDE theming. This is most likely something that’ll be revisted.

The Function Header Comment

To expand upon the final big chunk of our naming standard, in every rousr project all script_resources begin with a function header that looks like this:

1
2
3
4
5
///@function test_function(_required_param, [_optional_real=10])
///@desc a description of what test_function does
///@param {Real} _required_param this parameter is required
///@param {Real} [_optional_real=10] this parameter is optional, and defaults to `10`
///@returns {Real} _some_num returns a real
  • @function: This line is the function signature, the way it looks to be called, including (and denoting) optional parameters. Note that the return value isn’t included here.
  • @desc: Desc is simply a description of what the function does, and any use-notes. This can be multiple lines.
  • @param: param has a few rules, depending on what the parameter is, and is used to describe a parameter.
    • {type} The type is required, as is parameter name, with valid types being:
      • {Real}
      • {String}
      • {Boolean}
      • {Array} an array object
      • {Real:ds_list} Indicates the real represents a list (ds_map ds_priority_queue etc)
      • {Real:script_index} it expects the real to represent something likely to be script_executed
      • {Real:EEnumType} Real, but its represents a value in EEnumType
      • {Array:EArrayObject} Array that represents an array object
      • {Real|String} Real OR String
      • {*} Any
    • _param_name is next
      • [_optional_params] are surrounded with square brackets ([]) and can optionally include what its default value is (undefined assumed if omitted). [_option_real=10] is a real with a default value of 10.
    • Finally, there’s 3 spaces and then an optional written description of the param.

Rousr uses a tool we call the “Extensionizer” that parses all of the script functions in our projects to generate the various docs pages (see imguigml, dissonance, or LuaRousr for some examples!), so it’s important for all of our scripts to follow this pattern in order to be parsed and documented… but, like one of the major benefits of Naming Standards, the consistency also helps engineers working in our projects automatically know where to go to find information about how to use a script function, with the programmer contract as explicitly described as possible with what the parameters and returns are expected to be and how they’re used.