开源日报 每天推荐一个 GitHub 优质开源项目和一篇精选英文科技或编程文章原文,坚持阅读《开源日报》,保持每日学习的好习惯。
今日推荐开源项目:《可视化调试 vscode-debug-visualizer》
今日推荐英文原文:《A Brief History of the Curly Brace in Programming》

今日推荐开源项目:《可视化调试 vscode-debug-visualizer》传送门:项目链接
推荐理由:这个项目是一个可以将调试过程可视化的 VSCode 插件,虽然 demo 里的特效着实有些花里胡哨,但是实用性依然非常突出,不需要整天在控制台上打印数据就能很好的把握当前数据的情况;目前对 JS 一族提供了完全支持,而 Go,Python 等语言也提供了基本支持,在使用前最好扫一眼自己使用语言的支持情况。
今日推荐英文原文:《A Brief History of the Curly Brace in Programming》作者:Michael McMillan
原文链接:https://medium.com/better-programming/a-brief-history-of-the-curly-brace-in-programming-5b3eacdc3f7a
推荐理由:现在天天用到的花括号为什么当初会被引入呢

A Brief History of the Curly Brace in Programming

We use them every day but where did the curly brace in our code come from?

When did the curly brace, that familiar symbol that marks the beginning and the end of a block of code, become part of programming? Perhaps more importantly, when did code blocks become part of program structure?

In this article, I’ll answer these questions.

First, An Example of a Non-block Language

All programmers familiar with C-style programming syntax are familiar with programming blocks. All of the major programming constructs in C, C++, Java, JavaScript, and other languages are block-structured. In other words, the bodies of these constructs are placed within blocks, which are delimited with open and closing curly braces.

It could be argued that this is not strictly true, since if statements and loops, to mention just two programming constructs, can be formed without blocks if their bodies are just one statement long. However, over the past several years, programming style experts have recommended that all construct bodies be placed in a block (see Douglas Cockroft’s “JavaScript: The Good Parts” for a particularly convincing argument for placing all if and loop bodies in blocks).

However, the first high-level programming languages did not have blocks.

I will demonstrate this using the FORTRAN language circa the late 1950s. Donald Knuth, in his excellent review article of early high-level programming languages, “The Early Development of Programming Languages,” reprinted in his book “Selected Papers on Computer Languages”, compares the features of several early programming languages. He does this by demonstrating how a certain computer program is implemented in the different languages. This program, which implements an algorithm called the TPK algorithm, looks like this in modern JavaScript:
function f(t) {
  return Math.sqrt(Math.abs(t) + 5 * Math.pow(t, 3));
}
let arr = [];
let y;
for (let i = 0; i < 11; i++) {
  putstr("Enter a number: ");
  arr[i] = parseFloat(readline());
}
for (let i = 10; i >= 0; i--) {
  y = f(arr[i])
  if (y > 400) {
    print(y,"is too large.");
  }
  else {
    print(i,y)
  }
}
Don’t worry about what the program does. The important point is that this program exercises all of the features that Knuth thought were important to test in a modern programming language.

As I mentioned, Knuth compared several programming languages with this algorithm. One of the last languages he looked at is now often considered the first real high-level programming language. Here’s how the TPK program looks in Fortran, as written by Knuth:
C   THE TPK ALGORITHM, FORTRAN STYLE
    FUNF(T) = SQRTF(ABSF(T))+5.0*T**3
    DIMENSION A(11)
1   FORMAT(6F12.4)
    READ 1, A
    DO 10 J = 1, 11
    I = 11 – J
    Y = FUNF(A(I+1))
    IF (400.0-Y) 4, 8, 8
4   PRINT 5, I
5   FORMAT(I10, 10H TOO LARGE)
    GO TO 10
8   PRINT 9, I, Y
9   FORMAT(I10, F12.7)
10  CONTINUE
    STOP 52525
I won’t go into the details of the Fortran syntax, but you can clearly see that the language does not contain blocks. The function is defined on one line, not as a block of code. The DO loop uses a line label to control the loop. High-level languages at this time did not have a concept of grouping compound statements into blocks and these languages still relied on gotos to control program flow.

This code was written by Knuth using the 1957 version of Fortran. Between 1957 and 1960 a new language was developed, ALGOL, that remedied many of the defects of languages such as Fortran and the other high-level languages of the time.

Blocks in Algol

The Algol programming language was first described in 1958, though the most popular version of the language is Algol 60. One of the features of Algol is the ability to group statements into compound statements, known as blocks. Every Algol program was considered a block, since a program usually contains one or more statements (hence compound statements). The developers of Algol recognized that many programming scenarios, such as conditionals and loops, require statements to be considered as a unit.

Algol marked the start and end of a block with the keywords begin and end. A block could be nested inside another block, with the outer block being considered the dominant block and the inner block being considered the subordinate block. For example, here is an Algol program that nests blocks:
begin real a;
     a := 1;
     begin real a;
          a := 2;
          print(a)
     end;
     print(a)
end
The numbers 2 and 1, in that order, are printed.

Here is an example of how a block is used in an if statement in Algol:
if x > -1 then
     begin
          if x ≠ 0 then
          x := 1/x
     end;
And here is an example of a for loop block in Algol:
begin
     real a0, a1, a2, a3, z, p;
     integer n, i;
     read(a0, a1, a2, a3);
     read(n)
     for i := 1 step 1 until n do
          begin
               read(z);
               p := ((a3 × z + a2) × z + a1) × z + a0
               print(p)
          end i
end
Now let’s look at the TPK program in Algol, to see how block structure helps that program, compared to the Fortran version:
TPK begin integer i, real y; real a[0:10];
     real procedure f(t); real  t; value t;
     f := sqrt(abs(t)) + 5 × t ↑ 3;
     for i := 0 step 1 until 10 do read(a[i]);
     for i := 10 step -1 until 0 do
          begin y := f(a[i]);
               if y > 400 then write(I, 'TOO LARGE')
               else write(i, y);
          end
end TPK
You should be able to tell that the block structure of the Algol version makes it much more like the code you and I are used to reading today.

Moving on to BCPL

The next change in the syntax of block-structured languages came with the BCPL language developed by Martin Richards at the University of Cambridge around 1967. In between the initial development of Algol in 1960 and 1967, compiler and system developers had been looking for ways to develop systems applications (such as operating systems) using languages other than machine and assembly languages. I am highlighting BCPL because C was developed as a refinement and improvement of BCPL, via an intermediate language developed by Ken Thompson called B.

Richards developed BCPL as a systems development language that was as efficient as assembly language but with syntax at a higher level to make coding easier and more efficient. This meant that many features of high-level languages such as Algol needed to be included in a language such as BCPL, but in a more efficient way.

One way to achieve this efficiency was to simplify the designation of a block of code from words (begin and end) to symbols. For compound statements and blocks, Richards chose the symbols $( for opening and )$ for closing. These symbols are called section brackets.

In BCPL, if $( and )$ are used with a construct such as an if statement or a loop, then they’re delimiting a compound statement. If the $( includes some declarations, then they’re delimiting a block.

For example, here’s how an if statement with compound statements is written in BCPL:
IF A < B
     $( LET T = A
          A := B; B := T
     $)
Here’s an example of a BCPL block:
GET "LIBHDR"
LET START() BE
     $( LET A, B, C, SUM = 1, 2, 3, 0
          SUM := A + B + C
          WRITES("Sum is ")
          WRITEN(SUM)
     $)
Here the opening section bracket is opening a block because a declaration immediately follows the bracket.

$( and $) Become { and } in C

Around 1968 or 1969, Ken Thompson and Dennis Ritchie at Bell Labs began experimenting with developing an operating system using a systems programming language. Thompson actually began this exploration by trying to use Fortran but quickly dropped it when he realized it wasn’t possible. He decided that he needed to modify BCPL to make a systems programming language more to his liking, and so developed B.

B, while closer to the systems development language Thompson and Ritchie wanted, still did not meet their needs completely, so Ritchie set out to develop yet another language, called NB, for New B. NB did not live very long and was eventually replaced by a completely new language, which they naturally called C. If you are interested in how C was developed from BCPL, B, and NB, I encourage you to read Dennis Ritchie’s History of the C Language.

One of the many things that Thompson fixed in B that carried over into NB and then C was abbreviated operators. These were necessary for the expanded language to fit into the memory limitations of the computers of the day. For example, Thompson created the compound assignment operators (+= for example) and the increment (++) and decrement ( — ) operators as ways to make the language more efficient. This move for efficiency lead to other operators from BCPL to be simplified — for example, $( and $) were replaced by { and }.

Where We are Today

The curly brace has been embraced as the primary symbol for blocks in many programming languages, especially those languages that most closely follow C-style, including C++, Java, C#, and JavaScript.

More interestingly, newer languages have adopted the use of curly braces, including Go and Rust. Go, in fact, requires curly braces for every conditional or looping construct, following the lead of programming experts who state that even when the language doesn’t require them, programmers should use curly braces for every construct that can use them.
下载开源日报APP:https://openingsource.org/2579/
加入我们:https://openingsource.org/about/join/
关注我们:https://openingsource.org/about/love/