diff --git a/doc/src/manual/style-guide.md b/doc/src/manual/style-guide.md index 8e863e866b366..3a94f263e9e65 100644 --- a/doc/src/manual/style-guide.md +++ b/doc/src/manual/style-guide.md @@ -134,6 +134,32 @@ a = Vector{Union{Int,AbstractString,Tuple,Array}}(undef, n) In this case `Vector{Any}(undef, n)` is better. It is also more helpful to the compiler to annotate specific uses (e.g. `a[i]::Int`) than to try to pack many alternatives into one type. +## Prefer exported methods over direct field access + +Idiomatic Julia code should generally treat a module's exported methods as the +interface to its types. An object's fields are generally considered +implementation details and user code should only access them directly if this +is stated to be the API. This has several benefits: + +- Package developers are freer to change the implementation without breaking + user code. +- Methods can be passed to higher-order constructs like [`map`](@ref) (e.g. + `map(imag, zs))` rather than `[z.im for z in zs]`). +- Methods can be defined on abstract types. +- Methods can describe a conceptual operation that can be shared across + disparate types (e.g. `real(z)` works on Complex numbers or Quaternions). + +Julia's dispatch system encourages this style because `play(x::MyType)` only +defines the `play` method on that particular type, leaving other types to +have their own implementation. + +Similarly, non-exported functions are typically internal and subject to change, +unless the documentations states otherwise. Names sometimes are given a `_` prefix +(or suffix) to further suggest that something is "internal" or an +implementation-detail, but it is not a rule. + +Counter-examples to this rule include [`NamedTuple`](@ref), [`RegexMatch`](@ref match), [`StatStruct`](@ref stat). + ## Use naming conventions consistent with Julia `base/` * modules and type names use capitalization and camel case: `module SparseArrays`, `struct UnitRange`.