Return value of `begin ... end`

I understand the expression will be evaluated to a value. So

a = 1

will be evaluated to 1 where as a=1; will not

However, I expect

begin a = 1; end

to evaluate to nothing as well. Why does it evaluate to 1? Intuitively I would expect the value of begin ... end expression be value of the last expression in the block.

1 Like

The ; just supresses showing the value in the REPL, it doesn’t affect evaluation:

julia> (a = 1;)
1

That’s the same thing as begin a = 1 end. Actually, begin ... end is not much different that just using parentheses, except in readability. These are the same:

begin
    f()
    g()
end
begin f(); g() end
(
    f();
    g()
)
(f(); g())
3 Likes

If ; only suppresses value, does that mean

b = (a = 1);

and

b = (a = 1;)

are the same?

If so, may I also ask what the reasoning behind this design is?

Yeah. The trailing semicolon at the end of an expression doesn’t affect semantics (except in different contexts, such as in a call with keyword arguments). It serves merely to supress display in the REPL, nothing to do with evaluation semantics.

1 Like

I guess I would ask the opposite: why wouldn’t it work this way?

4 Likes

I guess, to answer my own question, there are a few “theories of semicolons” you could have. We’re all on the same page that semicolons can be used to separate multiple expressions on the same line (instead of a newline) or optionally terminate complete expressions before the newline.

One theory is that they don’t change the meaning or behavior of the surrounding expressions or insert any invisible expressions. This is the way Julia works. There’s a heuristic in the REPL that if the input expression ends with a semicolon, we suppress printing, but that’s just a heuristic, the behavior of expressions doesn’t change.

Another theory is the “Matlab theory”, which is that statements (Julia doesn’t really have statements, so this would already start to strain the theory) are implicitly surrounded by a print call and putting a semicolon at the end either removes that print call, or maybe causes the statement to evaluate to a value like Julia’s nothing that doesn’t output anything when printed. Of course, Julia doesn’t have this—things are not printed by default.

This question seems to be coming from an intermediate theory where a semicolon at the end of an expression implicitly inserts nothing after the semicolon, turning an expression that would evaluate to some value into a chain that evaluates to nothing instead. If we wanted to bake the “semicolon to suppress printing” thing into the language deeper than being a REPL feature, we could have done this. However, that’s not how it works.

7 Likes

I think a common “misfeature” to this design would be

julia> if (a = true) print("true!") else print("false!") end
true!

Such “typo” would be errored in language like Rust where a=true evaluates to () and cannot be used as a condition.

I feel this weird because I am more mentally inclined to Rust’s design where adding an ; to the end of expression makes the expression evaluate to (), so it’s more than a surgar at REPL level

This is not very common in practice, I think. If you want to test whether a variable is true, you would normally do simply if a rather than if a == true, so there is less danger of accidentally typing if a = true. I’ve never seen the latter mistake in real code.

(Contrast this with C, where almost anything can be used as a conditional value, and accidental assignments in branches are such a common error that most compilers have a warning for this.)

4 Likes

There is no semicolon here, so how would that help?

1 Like

Yeah, it’s a separate issue where the assignment returns the value assigned instead of nothing. But here even with semicolons, one couldn’t suppress this side-effect.

I agree it’s not very common and probably easy to spot. I am just in general not very satisfied with the side-effect on these expression evaluation (and not able to disable them with ;)

Sometimes such design is useful as in a = b = 1.

But anyway, I think my original question has been answered. Thanks guys!

1 Like

An expression having a value is not a side effect.

2 Likes

Sorry for calling the name wrong.

I think my point is:

  1. In Julia the assignment is an expression instead of a statement.
  2. I cannot make assignment into a statement through ; or begin end.

And I believe sometimes ensuring assignment is a statement is worthwhile (more context language agnostic - What is the benefit of having the assignment operator return a value? - Software Engineering Stack Exchange)

Julia, like Lisp (and most functional programming languages), is an expression-oriented language and doesn’t have statements. You’ll note that in Python, assignment is a statement. But then they eventually felt compelled to add the := operator just so that you can do an assignment that is an expression. Of course, why have assignment be a statement in the first place? So that you can’t accidentally do if x = 123 and have it evaluate to true. But Julia doesn’t have truthiness, which is a fundamentally broken concept, so this isn’t a big issue in the first place.

8 Likes

A few years ago I wrote a blog post about the return value of assignment and consideration of possible problems in conditionals (coming to similar conclusions as above): Returned value of assignment in Julia

3 Likes