開源日報 每天推薦一個 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/