• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

invenia/BlueStyle: A Julia style guide that lives in a blue world

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

invenia/BlueStyle

开源软件地址:

https://github.com/invenia/BlueStyle

开源编程语言:


开源软件介绍:

Blue: a Style Guide for Julia

Code Style: Blue

This document specifies style conventions for Julia code. These conventions were created from a variety of sources including Python's PEP8, Julia's Notes for Contributors, and Julia's Style Guide.

A Word on Consistency

When adhering to this style it's important to realize that these are guidelines and not rules. This is stated best in the PEP8:

A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important.

But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask!

Synopsis

Attempt to follow both the Julia Contribution Guidelines, the Julia Style Guide, and this guide. When convention guidelines conflict this guide takes precedence (known conflicts will be noted in this guide).

  • Use 4 spaces per indentation level, no tabs.
  • Try to adhere to a 92 character line length limit.
  • Use upper camel-case convention for modules and types.
  • Use lower case with underscores for method names (note: contrary to this, it is a common stylistic choice in the Julia base code to use lower case without underscores).
  • Import modules with using, with one module per line and at the top of the file when possible.
  • Comments are good, try to explain the intentions of the code.
  • Use whitespace to make the code more readable.
  • No whitespace at the end of a line (trailing whitespace).
  • Avoid padding brackets with spaces. ex. Int64(value) preferred over Int64( value ).

Contents

Code Formatting

Module Imports

Module imports should occur at the top of the file or right after a module declaration. Files loaded via an include should avoid specifying their own module imports and should instead add them to the file in which they were included (e.g. "src/Example.jl" or "test/runtests.jl").

A module import should only specify a single package per line. The lines should be ordered alphabetically by the package/module name (note: relative imports precede absolute imports).

# Yes:
using A
using B

# No:
using A, B

# No:
using B
using A

Imports which explicitly declare what to bring into scope should be grouped into: modules, constants, types, macros, and functions. These groupings should be specified in that order and each group's contents should be sorted alphabetically, typically with modules on a separate line. As pseudo-code:

using Example: $(sort(modules)...)
using Example: $(sort(constants)...), $(sort(types)...), $(sort(macros)...), $(sort(functions)...)

If you are only explicitly importing a few items you can alternatively use the following one-line form:

using Example: $(sort(modules)...), $(sort(constants)...), $(sort(types)...), $(sort(macros)...), $(sort(functions)...)

In some scenarios there may be alternate ordering within a group which makes more logical sense. For example when explicitly importing subtypes of Period you may want to sort them in units largest to smallest:

using Dates: Year, Month, Week, Day, Hour, Minute, Second, Millisecond

Explicit import lines which exceed the line length should use line-continuation or multiple import statements for the same package. Using multiple import statements should be preferred when creating alternate groupings:

# Yes:
using AVeryLongPackage: AVeryLongType, AnotherVeryLongType, a_very_long_function,
    another_very_long_function

# Yes:
using AVeryLongPackage: AVeryLongType, AnotherVeryLongType
using AVeryLongPackage: a_very_long_function, another_very_long_function

# No:
using AVeryLongPackage:
    AVeryLongType,
    AnotherVeryLongType,
    a_very_long_function,
    another_very_long_function

# No:
using AVeryLongPackage: AVeryLongType
using AVeryLongPackage: AnotherVeryLongType
using AVeryLongPackage: a_very_long_function
using AVeryLongPackage: another_very_long_function

Note: Prefer the use of imports with explicit declarations when writing packages. Doing so will make maintaining the package easier by knowing what functionality the package is importing and when dependencies can safely be dropped.

Prefer the use of using over import to ensure that extension of a function is always explicit and on purpose:

# Yes:
using Example

Example.hello(x::Monster) = "Aargh! It's a Monster!"
Base.isreal(x::Ghost) = false

# No:
import Base: isreal
import Example: hello

hello(x::Monster) = "Aargh! It's a Monster!"
isreal(x::Ghost) = false

If you do require the use of import then create separate groupings for import and using statements divided by a blank line:

# Yes:
import A: a
import C

using B
using D: d

# No:
import A: a
using B
import C
using D: d

Function Exports

All functions that are intended to be part of the public API should be exported. All function exports should occur at the top of the main module file, after module imports. Avoid splitting a single export over multiple lines; either define one export per line, or group them by theme.

# Yes:
export foo
export bar
export qux

# Yes:
export get_foo, get_bar
export solve_foo, solve_bar

# No:
export foo,
    bar,
    qux

Global Variables

Global variables should be avoided whenever possible. When required, global variables should be consts and have an all uppercase name seperated with underscores (e.g. MY_CONSTANT). They should be defined at the top of the file, immediately after imports and exports but before an __init__ function. If you truly want mutable global style behaviour you may want to look into mutable containers or closures.

Function Naming

Names of functions should describe an action or property irrespective of the type of the argument; the argument's type provides this information instead. For example, submit_bid(bid) should be submit(bid::Bid) and bids_in_batch(batch) should be bids(batch::Batch).

Names of functions should usually be limited to one or two lowercase words separated by underscores. If you find it hard to shorten your function names without losing information, you may need to factor more information into the type signature or split the function's responsibilities into two or more functions. In general, shorter functions with clearly-defined responsibilities are preferred.

NOTE: Functions that are only intended for internal use should be marked with a leading underscore (e.g., _internal_utility_function(X, y)). Although it should be much less common, the same naming convention can be used for internal types and constants as well (e.g., _MyInternalType, _MY_CONSTANT). Marking a function as internal or private lets other people know that they shouldn't expect any kind of API stability from that functionality.

Method Definitions

Only use short-form function definitions when they fit on a single line:

# Yes:
foo(x::Int64) = abs(x) + 3

# No:
foobar(array_data::AbstractArray{T}, item::T) where {T<:Int64} = T[
    abs(x) * abs(item) + 3 for x in array_data
]
# Yes:
function foobar(array_data::AbstractArray{T}, item::T) where T<:Int64
    return T[abs(x) * abs(item) + 3 for x in array_data]
end

# No:
foobar(
    array_data::AbstractArray{T},
    item::T,
) where {T<:Int64} = T[abs(x) * abs(item) + 3 for x in array_data]

When using long-form functions always use the return keyword:

# Yes:
function fnc(x::T) where T
    result = zero(T)
    result += fna(x)
    return result
end

# No:
function fnc(x::T) where T
    result = zero(T)
    result += fna(x)
end
# Yes:
function Foo(x, y)
    return new(x, y)
end

# No:
function Foo(x, y)
    new(x, y)
end

When using the return keyword always explicitly return a value, even if it is return nothing.

# Yes:
function maybe_do_thing()
    # code
    return nothing
end

# No:
function maybe_do_thing()
    # code
    return
end

Functions definitions with parameter lines which exceed 92 characters should separate each parameter by a newline and indent by one-level:

# Yes:
function foobar(
    df::DataFrame,
    id::Symbol,
    variable::Symbol,
    value::AbstractString,
    prefix::AbstractString="",
)
    # code
end

# Ok:
function foobar(df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString, prefix::AbstractString="")
    # code
end

# No: Don't put any args on the same line as the open parenthesis if they won't all fit.
function foobar(df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString,
    prefix::AbstractString="")

    # code
end

# No: All args should be on a new line in this case.
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString,
    prefix::AbstractString=""
)
    # code
end

# No: Indented too much.
function foobar(
        df::DataFrame,
        id::Symbol,
        variable::Symbol,
        value::AbstractString,
        prefix::AbstractString="",
    )
    # code
end

If all of the arguments fit inside the 92 character limit then you can place them on 1 line. Similarly, you can follow the same rule if you break up positional and keyword arguments across two lines.

# Ok:
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString; prefix::String=""
)
    # code
end

# Ok: Putting all args and all kwargs on separate lines is fine.
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString;
    prefix::String=""
)
    # code
end

# Ok: Putting all positional args on 1 line and each kwarg on separate lines.
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString;
    prefix="I'm a long default setting that probably shouldn't exist",
    msg="I'm another long default setting that probably shouldn't exist",
)
    # code
end

# No: Because the separate line is more than 92 characters.
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString; prefix::AbstractString=""
)
    # code
end

# No: The args and kwargs should be split up.
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol,
    value::AbstractString; prefix::AbstractString=""
)
    # code
end

# No: The kwargs are more than 92 characters.
function foobar(
    df::DataFrame, id::Symbol, variable::Symbol, value::AbstractString;
    prefix="I'm a long default setting that probably shouldn't exist", msg="I'm another long default settings that probably shouldn't exist",
)
    # code
end

Keyword Arguments

When calling a function always separate your keyword arguments from your positional arguments with a semicolon. This avoids mistakes in ambiguous cases (such as splatting a Dict).

# Yes:
xy = foo(x; y=3)
ab = foo(; a=1, b=2)

# Ok:
ab = foo(a=1, b=2)

# No:
xy = foo(x, y=3)

Whitespace

  • Avoid extraneous whitespace immediately inside parentheses, square brackets or braces.

    # Yes:
    spam(ham[1], [eggs])
    
    # No:
    spam( ham[ 1 ], [ eggs ] )
  • Avoid extraneous whitespace immediately before a comma or semicolon:

    # Yes:
    if x == 4 @show(x, y); x, y = y, x end
    
    # No:
    if x == 4 @show(x , y) ; x , y = y , x end
  • Avoid whitespace around : in ranges. Use brackets to clarify expressions on either side.

    # Yes:
    ham[1:9]
    ham[9:-3:0]
    ham[1:step:end]
    ham[lower:upper-1]
    ham[lower:upper - 1]
    ham[lower:(upper + offset)]
    ham[(lower + offset):(upper + offset)]
    
    # No:
    ham[1: 9]
    ham[9 : -3: 1]
    ham[lower : upper - 1]
    ham[lower + offset:upper + offset]  # Avoid as it is easy to read as `ham[lower + (offset:upper) + offset]`
  • Avoid using more than one space around an assignment (or other) operator to align it with another:

    # Yes:
    x = 1
    y = 2
    long_variable = 3
    
    # No:
    x             = 1
    y             = 2
    long_variable = 3
  • Surround most binary operators with a single space on either side: assignment (=), updating operators (+=, -=, etc.), numeric comparisons operators (==, <, >, !=, etc.), lambda operator (->). Binary operators may be excluded from this guideline include: the range operator (:), rational operator (//), exponentiation operator (^), optional arguments/keywords (e.g. f(x=1; y=2)).

    # Yes:
    i = j + 1
    submitted += 1
    x^2 < y
    
    # No:
    i=j+1
    submitted +=1
    x^2<y
  • Avoid using whitespace between unary operands and the expression:

    # Yes:
    -1
    [1 0 -1]
    
    # No:
    - 1
    [1 0 - 1]  # Note: evaluates to `[1 -1]`
  • Avoid extraneous empty lines. Avoid empty lines between single line method definitions and otherwise separate functions with one empty line, plus a comment if required:

    # Yes:
    # Note: an empty line before the first long-form `domaths` method is optional.
    domaths(x::Number) = x + 5
    domaths(x::Int) = x + 10
    function domaths(x::String)
        return "A string is a one-dimensional extended object postulated in string theory."
    end
    
    dophilosophy() = "Why?"
    
    # No:
    domath(x::Number) = x + 5
    
    domath(x::Int) = x + 10
    
    
    
    function domath(x::String)
        return "A string is a one-dimensional extended object postulated in string theory."
    end
    
    
    dophilosophy() = "Why?"
  • Function calls which cannot fit on a single line within the line limit should be broken up such that the lines containing the opening and closing brackets are indented to the same level while the parameters of the function are indented one level further. In most cases the arguments and/or keywords should each be placed on separate lines. Note that this rule conflicts with the typical Julia convention of indenting the next line to align with the open bracket in which the parameter is contained. If working in a package with a different convention follow the convention used in the package over using this guideline.

    # Yes:
    f(a, b)
    constraint = conic_form!(
        SOCElemConstraint(temp2 + temp3, temp2 - temp3, 2 * temp1),
        unique_conic_forms,
    )
    
    # No:
    # Note: `f` call is short enough to be on a single line
    f(
        a,
        b,
    )
    constraint = conic_form!(SOCElemConstraint(temp2 + temp3,
                                               temp2 - temp3, 2 * temp1),
                             unique_conic_forms)
  • Assignments using expanded notation for arrays or tuples, or function calls should have the first open bracket on the same line assignment operator and the closing bracket should match the indentation level of the assignment. Alternatively you can perform assignments on a single line when they are short:

    # Yes:
    arr = [
        1,
        2,
        3,
    ]
    arr = [
        1, 2, 3,
    ]
    result = func(
        arg1,
        arg2,
    )
    arr = [1, 2, 3]
    
    # No:
    arr =
    [
        1,
        2,
        3,
    ]
    arr =
    [
        1, 2, 3,
    ]
    arr = [
        1,
        2,
        3,
        ]
  • Nested array or tuples that are in expanded notation should have the opening and closing brackets at the same indentation level:

    # Yes:
    x = [
        [
            1, 2, 3,
        ],
        [
            "hello",
            "world",
        ],
        ['a', 'b', 'c'],
    ]
    
    # No:
    y = [
        [
            1, 2, 3,
        ], [
            "hello",
            "world",
        ],
    ]
    z = [[
            1, 2, 3,
        ], [
            "hello",
            "world",
        ],
    ]
  • Always include the trailing comma when working with expanded arrays, tuples or functions notation. This allows future edits to easily move elements around or add additional elements. The trailing comma should be excluded when the notation is only on a single-line:

    # Yes:
    arr = [
        1,
        2,
        3,
    ]
    result = func(
        arg1,
        arg2,
    )
    arr = [1, 2, 3]
    
    # No:
    arr = [
        1,
        2,
        3
    ]
    result = func(
        arg1,
        arg2
    )
    arr = [1, 2, 3,]
  • Triple-quotes and triple-backticks written over multiple lines should be indented. As triple-quotes use the indentation of the lowest indented line (excluding the opening quotes) the least indented line in the string or ending quotes should be indented once. Triple-backticks should also follow this style even though the indentation does not matter for them.

    # Yes:
    str = """
        hello
        world!
        """
    cmd = ```
        program
            --flag value
            parameter
        ```
    
    # No:
    str = """
    hello
    world!
    """
    cmd = ```
          program
              --flag value
              parameter
          ```
  • Assignments using triple-quotes or triple-backticks should have the opening quotes on the same line as the assignment operator.

    # Yes:
    str2 = """
           hello
       world!
       """
    
    # No:
    str2 =
       """
           hello
       world!
       """
  • Group similar one line statements together.

    # Yes:
    foo = 1
    bar = 2
    baz = 3
    
    # No:
    foo = 1
    
    bar = 2
    
    baz = 3
  • Use blank-lines to separate different multi-line blocks.

    # Yes:
    if foo
        println("Hi")
    end
    
    for i in 1:10
        println(i)
    end
    
    # No:
    if foo
        println("Hi")
    end
    
                          

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap