Defining functions using begin

I found that it is possible to define functions like this:

f(x, y) = begin
    x + y
end

I couldn’t find documentation for this style of function definition in the Julia manual. My question is thus: what differences does this style have over defining functions using the more oft-used function blocks.

Most people would use

f(x, y) = x + y

since function definitions already introduce a block (so begin here is redundant, but harmless).

See the docs at ?begin.

It’s a bit of a sneaky ‘abuse’ of short form (or ‘assignment form’) function definition. You can find it documented here: https://docs.julialang.org/en/v1/manual/functions/

While it doesn’t explicitly mention using begin ... end, it says

In the assignment form, the body of the function must be a single expression, although it can be a compound expression (see Compound Expressions). Short, simple function definitions are common in Julia. The short function syntax is accordingly quite idiomatic, considerably reducing both typing and visual noise.

Compound expressions can entail begin ... end.

While the manual says that that this form is idiomatic, I believe this is the case only for very short function bodies, typically a single line. Most of the style guides I’ve seen recommend using short form only for single line functions.

I guess some people use the short form anyway also for longer functions, because it reminds them of syntax in languages they are familiar with (I think R, in particular).

Personally, I would recommend to use short form only for single-line function definitions, I find the begin ... end trick less readable, and it also clashes with coding practices in almost all Julia code, such as Base, stdlib and most registered packages.

1 Like

I’ve recently started really liking the

f(x) = begin
    ...
end

form, mostly because it works really well in a list of methods where many are one-liners but a few are longer. As a short example from HAML.jl:

mapexpr(f, expr) = expr
mapexpr(f, expr::Expr) = begin
    res = Expr(expr.head)
    resize!(res.args, length(expr.args))
    map!(f, res.args, expr.args)
    return res
end

I wouldn’t be surprised if I find myself migrating 100% away from the function ... syntax, even.

6 Likes

Since function is such an vital and pervasive code block signifier, I would be unhappy if this were to become the common idiom (or even replacing the function keyword – I only worry since yours is apparently a popular opinion).

I see how it works well in the limited case that you mention (list of many one-liners with a few longer), but I think it really makes it hard to visually distinguish code blocks when the keyword isn’t at the beginning of the line, and doesn’t line up with the matching end.

For the same reason, I find that putting macros like @inbounds and @threads ahead of a for loop messes up the code quite a bit. I would love to be able to write

@inbounds
for i in eachindex(X)
    ...
end
5 Likes