Style Guide

Style guide and design principles

Style guide

This section describes the coding style rules that apply to JuMP code and that we recommend for JuMP models and surrounding Julia code. The motivations for a style guide include:

In some cases, the JuMP style guide diverges from the Julia style guide. All such cases will be explicitly noted and justified.

The JuMP style guide adopts many recommendations from the Google style guides.

Info

The style guide is always a work in progress, and not all JuMP code follows the rules. When modifying JuMP, please fix the style violations of the surrounding code (i.e., leave the code tidier than when you started). If large changes are needed, consider separating them into another PR.

Formatting

Julia unfortunately does not have an autoformatting tool like gofmt. Until a reliable autoformatting tool is available, we adopt the following conventions.

Whitespace

Julia is mostly insensitive to whitespace characters within lines. For consistency:

Good:

f(x, y) = [3 * dot(x, y); x']

Bad:

f(x,y) = [ 3*dot(x,y) ; x' ]

Good:

module Foo

function f(x)
    return x + 1
end

end # module Foo

TODO: Line breaks

Syntax

Julia sometimes provides equivalent syntax to express the same basic operation. We discuss these cases below.

for loops

Julia allows both for x = 1:N and for x in 1:N. Always prefer to use in over =, because in generalizes better to other index sets like for x in eachindex(A).

Empty vectors

For a type T, T[] and Vector{T}() are equivalent ways to create an empty vector with element type T. Prefer T[] because it is more concise.

Trailing periods in floating-point constants

Both 1.0 and 1. create a Float64 with value 1.0. Prefer 1.0 over 1. because it is more easily distinguished from the integer constant 1.

Naming

module SomeModule end
function some_function end
const SOME_CONSTANT = ...
struct SomeStruct end
some_local_variable = ...

Use of underscores

The Julia style guide recommends avoiding underscores "when readable", for example, haskey, isequal, remotecall, and remotecall_fetch. This convention creates the potential for unnecessary bikeshedding and also forces the user to recall the presence/absence of an underscore, e.g., "was that argument named basename or base_name?". For consistency, always use underscores in variable names and function names to separate words.

Use of !

Julia has a convention of appending ! to a function name if the function modifies its arguments. We recommend to:

Note that ! is not a self-documenting feature because it is still ambiguous which arguments are modified when multiple arguments are present. Be sure to document which arguments are modified in the method's docstring.

See also the Julia style guide recommendations for ordering of function arguments.

Abbreviations

Abbreviate names to make the code more readable, not to save typing. Don't arbitrarily delete letters from a word to abbreviate it (e.g., indx). Use abbreviations consistently within a body of code (e.g., do not mix con and constr, idx and indx).

Common abbreviations:

TODO: add more

Miscellaneous

(TODO: Rethink categories.)

User-facing MethodError

Specifying argument types for methods is mostly optional in Julia, which means that it's possible to find out that you are working with unexpected types deep in the call chain. Avoid this situation or handle it with a helpful error message. A user should see a MethodError only for methods that they called directly.

Bad:

internal_function(x::Integer) = x + 1
# The user sees a MethodError for internal_function when calling
# public_function("a string"). This is not very helpful.
public_function(x) = internal_function(x)

Good:

internal_function(x::Integer) = x + 1
# The user sees a MethodError for public_function when calling
# public_function("a string"). This is easy to understand.
public_function(x::Integer) = internal_function(x)

If it is hard to provide an error message at the top of the call chain, then the following pattern is also ok:

internal_function(x::Integer) = x + 1
function internal_function(x)
    error("Internal error. This probably means that you called " *
          "public_function() with the wrong type.")
end
public_function(x) = internal_function(x)

Design principles

TODO: How to structure and test large JuMP models, libraries that use JuMP.

For how to write a solver, see MOI.