How do you feel about braces and semicolons?

Joe Clay on March 26, 2018

I'm (slowly) working my way through Crafting Interpreters, and trying to put together a design for my little interpreted language. Thinking about... [Read Full]
markdown guide
 

Braces defining scopes and braces defining objects have different effects, but I'd question whether the meanings of the braces themselves are that distinct. A scope encloses process in order to execute it conditionally, iteratively, later, or in particular contexts; an object literal encloses information so it can be referenced, destructured, and otherwise operated on. Object literals can also execute code intra-declaration, blurring the semiotic lines further:

const obj = {
  one: whateverThisReturns(),
  two: three ? four : five
};

The significance of braces isn't an either-or of scope vs declaration. It's that the contents -- whatever those may be -- represent an interruption in the top-to-bottom flow of execution. Enclosure is enclosure, no matter what you're doing inside it.

Personally, I like braces and you can take my semicolons from my cold dead hands.

 

Aah, that's an interesting way of thinking about it that I hadn't considered!

 

Genuinely curious, but why do you like semicolons? You seem to use a style of code which can be interpreted without them, yet you still want them.

 

I've been writing JavaScript more than anything else for the past five years but my background is all Java and C# and old habits die hard.

Also, JS being explicit about statement terminators would have saved me more time than I'd like to admit trying to figure out what was going on with

return
  someComplexConstruction;

Without the fear of JS wackiness, would you be comfortable with semi-colon-less code?

I grew up on semi-colons as well. I don't use them in JS either now -- I'd rather play with fire than see them anymore. :)

It'd depend. In C-family languages, I wouldn't, at least initially. But I could probably get used to it. I still don't like Groovy but there's a lot more going on there than the lack of semicolons.

Other languages, anything goes.

 

No braces and semicolons (I'm not actually sure anyone does this?)

Ruby has braces but are usually reserved for single-line declarations. This is the common block syntax.

@people.each do |person|
  person.say("hello")
end

if something
  do("something")
elsif something_else
  do("something else")
else
  do("nothing")
end

Ruby looks like Python but does not use significant whitespace. It's definitely an interesting case study for language syntax design.

 

Ah, slightly confusing wording on my part - I meant 'no braces, yes semicolons' for that option :) Will rephrase that.

Either way, I really like Ruby's syntax! Lua has a similar thing going for it where it looks like a Python-ish language, but its grammar doesn't care about whitespace/line breaks.

 

I also have the feeling that using a delimiter might be easier for designing a new language, might be wrong though.

Definitely no semicolons :P

 

Some other wacky design I've not thought of...

Lisp-style S-Expressions, make parsing very easy.

In Erlang a function body starts after a an arrow, ends with a colon and
expressions are seperated by commas.

I profoundly dislike the Python's paternalism regarding significant whitespace. On the other hand, in Haskell you have it as syntactic sugar for braces and semicolons, with which I can live very well.

Wirth-style languages use keywords (begin, end) for denoting blocks, which I find to be a bit verbose.

 

Ah yeah, totally forgot about Lisps. I really like them in theory (especially from a parsing standpoint), but in practice I don't tend to enjoy writing them that much ):

Not hugely familiar with Erlang beyond writing a bit of Elixir - will look into that further!

And yeah, can't say I'm a big fan of significant whitespace myself.

 

it's unfortunate that all main lisps (common lisp, scheme, racket, clojure, ...) needlessly use an excessive amount of parenthesis

it gives the impression that lisp is inherently a 'syntactically verbose' language, which is totally false

take scheme:
(let ((a 1) (b 2)) (f a b))

now take a 'syntactically sane' lisp:
(let a 1 b 2 (f a b))

s-expressions were originally conceived as an internal representation for programs to be parsed by computers, not by humans, and so justifying the verbosity

but then programmers started to find s-expressions extremely convenient to use (expecially because they trivially allowed metaprogramming by treating code as data) that no one cared to build the human readable m-expression syntax that lisp were originally supposed to have

that was a fortunate accident, but the excessive parens sticked instead of being reduced to the absolute minimum which would bring lisp to a better place than most currently used languages in which parenthesis, brackets, braces and punctuation abound

I totally agree, and I think this is why Clojure is one of the only lisp-y languages I've sunk any time into. A little bit of syntax sugar goes a long way!

I also find the design of Julia very interesting - they have a Python-like syntax, but parse it into s-expressions. This gives them some of the benefits of a lisp (easy meta-programming, code-as-data, etc) without being quite as painful to write. I think Elixir does something similar, too.

 

No-semicolons are a problem IFF expressions can be statements (not sure about the terminology here).

For example

foo = bar
  - baz

could be read as either

foo = bar - baz

or

foo = bar;
-baz;

but -baz could be forbidden as a statement (Go rejects it, but neither Kotlin or JavaScript do).

No semicolons also means you sometimes have to end your lines with \ to have them parsed correctly, or make sure you put binary operators at EOL (see above, also applies to . or ->, or logical operators).

Also, braces, definitely! Less typing, and lighter-weight visually than end keywords (or similar, please don't make context-dependent keywords like in shell: if …; then …; fi, while …; do …; done, case … in … ;; esac, etc.), and significant whitespace, well… (nothing against Python, but there must be reasons other mainstream languages didn't copy this facet of it)

 

Yeah, that's definitely a problem with parsing languages without semicolons - I quite like the solution that the developer of Wren (who, incidentally, is also the author of Crafting Interpreters) went for:

Newlines (\n) are meaningful in Wren. They are used to separate statements:

// Two statements:
System.print("hi") // Newline.
System.print("bye")

Sometimes, though, a statement doesn’t fit on a single line and jamming a newline in the middle would trip it up. To handle that, Wren has a very simple rule: It ignores a newline following any token that can’t end a statement.

System.print( // Newline here is ignored.
    "hi")

I find that a bit easier to keep in my head than JavaScript/Go's automatic semicolon insertion rules.

 

AFAICT, this is basically what Go does too (golang.org/ref/spec#Semicolons, expressed as a whitelist rather than blacklist) except -baz by itself, while a valid expression, is not a valid statement, so code wouldn't compile rather than most probably creating a bug.

Of course, it's not actually equivalent, but the rule is easy. By this rule, the following wouldn't compile, but would be accepted in Wren (Go doesn't have ternary operator either though)

foo(bar
    ? baz : qux)

I suppose the choice also depends whether you want a "lenient" language (like JS) or a stricter one (like Go). It's hard to create subtle bugs in Go due to parsing alone, it's way too easy in JS, which is why people add ESLint or similar to tell them when they likely did it (though it probably cannot detect everything).

Automatic formatting (Prettier) also helps detecting such bugs ("why did it un-indent that -bar?"), but that's still left to the developer to "decide" whether he introduced a bug or not.

I, for one, prefer strictness over "format your code the way you want it". Python is good in this respect if significant whitespace is your thing; otherwise, lean towards Go rather than JS (when it comes to semicolons)

 

The way Swift handles this is interesting.

let x = 10
- 1
// is
let x = 10
- 1;

let x = 10
-1
// is
let x = 10;
-1;

let x = 10 - 1
// is
let x = 10 - 1;

let x = 10 -1
// is
let x = 10; -1;
// Error two statements on the same line must be separated by a semicolon

The rule is basically [space][op][space] or [nospace][op][nospace] is an infix operator, [space][op][nospace] is a prefix operator, and [nospace][op][space] is a postfix operator.

 

In Leaf I went for braces without semicolons. I dislike giving whitespace significant meaning (as in Python) as it can be hard to debug, and may not support the desired code structure. I also prefer having an explicit end notation on blocks.

There is also no ambiguity with {} blocks in Leaf, they are always code blocks. Tuples (objects) are denote with [] blocks. I'm debating whether the commas in tuples should also be optional, as it's common to list the items on multiple lines.

 

Both braces and semicolons were used to simplify language parser. In most of the time they have no value for code readability. However I would agree that in some rare cases optional brackets could improve readability of a complex code structure.

I believe the next generation programming lang will get rid of under_score or cameCase style to look more like a natural human language


def find public ip(self):  # instead of def find_public_ip(self):
      ....
 

Natural-language style programming is definitely interesting - I think the coolest example I've seen of it is Inform 7, a language used for writing text adventures which is designed to look like normal (if somewhat stilted) English prose:

"Hello World" by "I.F. Author"

The world is a room.

When play begins, say "Hello, world."

Whether you could (or should) create a general-purpose programming language in that style, I'm not sure - it's interesting to think about, though :)

 

My initial reaction to JS was negative in part because of lines like this:

});

I hate that. Especially seeing consecutive lines containing nothing but braces and semicolons. Ugly and hard to read IMO.

 

I really don't understand, from a user point of view, why a programming language should have braces and semi colons. We can do without them very well (Python is the living proof).

Pros

  • looks less "crouded"
  • less typing
  • lighter files (with js especially)

Cons

  • tend to make typo (oh, i forgot an other f*** semi colon on line 239. Go back, add a semi colon, and reload).

For bracket, you indent your code anyway, no? What's wrong with not having an explicit separator?

Something funny I saw a year ago I think in a screencast, from a bracket loving guy.

def some_function(): # {
    some = code()
# }

I think argumentation with that guy would have been a nice waste of time :D

 

Significant whitespace (indentation defining blocks) can cause a lot of unintended trouble. Minor formatting errors, which can arise during merges, can completely change the meaning of the code. Unintended editor setting variations (also common) can also change the meaning of the code.

Similar whitespace can also come from different unicode characters, resulting in code that looks visually correct, but is wrong. Copy-and-paste from different sources can give rise to such a problem.

The lack of closing notation can also lead to a visual anomoly of dangling code. It can also be unclear in nesting which former block is continued. Closing markers can help identify the ends of blocks -- it's visually more distinct than unindenting.

Relying on whitespaces for blocks can also complicate situations where inline objects or closures are neede.

 

Semicolons and no braces (I'm not actually sure anyone does this?)

Ocaml does this. It uses semicolons to terminate an expression.

let f greeting = 
    print_string greeting; 
    greeting 
in let g = f "hello"
 

I'm very fond of the C programming style, maybe because I started with it, although python code generally looks very elegant as well.

Personally, I keep the old (but awesome) K&R indent style due to the considerations for the Linux kernel development

 
 

No braces, no semicolons, lots of parentheses (Lisp, Scheme, Clojure).

Braces and no semicolons can also cite JavaScript, because of the magic of JavaScript's automatic semicolon insertion. The flamewar between Crockford's SEMICOLONS, DAMMIT! camp, versus Eich's SEMICOLONS ARE UNNECESSARY camp will go down in the annals of history along side tabs-vs-spaces and emacs-vs-vi and curly-brace-indentation holy wars.

My favorite languages are: D, Python, Lua, F#. So what I syntactically prefer is all over the map.

Having tried my hand at creating my own programming language, I can give a few bits of advice.

Firstly, write a short but non-trivial program in your proposed language. Get a feel for it. Tweak it.
Before you actually begin to implement the interpreter.

My second bit of advice you already have covered: look at other languages, and see what you like or don't like.

My third bit of advice you probably won't like, so I will refrain for now. So as not to dampen your enthusiasm.

 

Is the third bit of advice "don't"? Having spent way too long designing an "implementing" a toy language of my own, my first advice to anyone looking to make a toy language would be "don't".

 

lol ... the third bit of advice is: it's hard, and takes a long time. And if by some miracle the language becomes popular then you'll end up doing hard time and manual labor (i.e., you'll have to write the manual).

I lifted the manual labor joke from Bjarne Stroustrup.

 

My ideal programming language would have explicit do/end markers for blocks and it would require you to indent it correctly. It serves as redundancy to detect merge-introduced bugs.

def my_function do
  something()
    something_else() # This should be a parse error
end

You can bundle another CLI app with it to use the delimiters to fix up the indentation, like gofmt.

Semicolons, on the other hand, seem like an excessive amount of ceremony unless you're doing something like Rust where omitting them carries meaning. So I guess I'm in the "braces but no semicolons" camp?

 

Semicolons and braces. I also like the explicitness of it plus I can put a line break almost anywhere in a statement. I guess it comes down to remembering to either end every statement with a character or remembering to put some this-continues-on-the-next-line character like in VBA. 🤔

 

I like braces and semi-colons because I don't want the language parser to do magic behind the scenes and guess what I meant.

 

Yeah, I feel like my problem isn't with significant whitespace, it's with opaque parsing rules - I need to be able to keep a mental model of where exactly each line/block ends without having to stop and get a ruler out!

 

I totally HATE all these braces and semicolons. I think languages that use them were designed in such way to increase self-importance feeling in those douchebag geeks.
I absolutely love Python because you do not waste your time on all these awful punctuation marks and just concentrate on the important stuff

 

I've written enough Java, that I'm ready to give up braces and semicolons, especially when doing things with functions.

 
 

Groovy: no semicolon and no braces (optional!), but curly brackets. Love it!

 

shouldn't brackets be square and braces be curly? :-)

 

I think I like #2 best, at least it feels the most natural when I use it. Flipping back to Java from Kotlin, I tend to forget the semicolons until my IDE/compiler yells at me.

 

You usually indent code between braces anyway, so why not leave them out (Python style), at least for scopes. I'd just use them for object/dict literals.

 

Hate em. I think the ideal language would be something along the lines of Lisp, Haskell, and Ruby having a baby.

code of conduct - report abuse