📜 ⬆️ ⬇️

Paul Graham, “Hackers and Artists”, chapter 10: “Programming Languages ​​Explained”

image The book "Hackers and Artists", chapter 10.

This chapter is only in the book, on the website of Paul Graham it is missing.
By the way, only a little bit of the last chapter remains and the last chapter of the book will be ready, thus there will be a complete Russian hacker translation of Hackers and Artists. (The previous translation is Paul Graham: "The Other Road Ahead . " )

Thanks for the help with the translation, thanks to Yana Schekotova, for the help with the publication, thanks to Edison .
')

Programming languages ​​"in section"


Any machine has a set of actions that can be performed on it.
Sometimes this set is very limited. With my electric kettle, I can only do two things: turn it on and off. My CD player will be more complicated. In addition to turning it on and off, I can raise and lower the volume on it, play and pause the songs, go to the next or previous song, and play it all in random order.

Like any other device, a computer has a list of actions that it can perform. For example, on each computer you can add two numbers. A complete list of permissible computer operations is enclosed in its machine language.

Machine language


When computers were invented, all programs had to be written as a sequence of machine instructions. Soon, they began to write in a somewhat more convenient form called assembly language. In assembly language, the list of commands is the same, only more convenient names for programmers are used. Instead of referring to the addition instruction as 11001101, although this is how the machine calls it, you need to write add.

The problem with machine language / assembly language is that most computers can only do very simple things. For example, suppose you want your computer to play a short beep 10 times. I doubt that the computer has an instruction for performing any action n times. Therefore, if you needed a computer to do something 10 times using real machine instructions, you would have to write something like:

put the number 10 in memory location 0
a if location 0 is negative, go to line b
beep
subtract 1 from the number in location 0
go to line a
b ... rest of program ...

If you have to do so much work just to make the machine ping 10 times, then just imagine how much work it takes to write something like a word processor or spreadsheet program.

And by the way, take another look at the program. Will she really play a short beep 10 times? Nope, 11. In the first line, I had to specify 9 and not 10. I deliberately placed an error in our example in order to demonstrate an important aspect about languages. The more you have to write to perform certain actions, the harder it is to see the errors.

High level languages


Imagine that you need to create programs in assembly language, but you have some assistant to do all the "dirty" work. So you can just write something like

do times 10 beep,

and your assistant will write it for you in assembly language (but without errors).
In fact, this is how most programmers work. Except that the helper is not a person, but a compiler. A compiler is a program that translates programs written in a convenient form, like the one-line program mentioned above, into simple language that is understandable for hardware.

This more convenient language that you “feed” to the compiler is called high-level. It allows you to write programs based on powerful commands, such as “do something n times” instead of the notorious “add two numbers.”

When you create programs based on more generalized concepts, you do not need to use all of them. The length of the program written in our fictional high-level language is only one fifth of the length of the original one. And if a mistake was made in it, then it would be easy to find.

Another advantage of high-level languages ​​is that they make your program more portable. Machine languages ​​are slightly different on different computers. As a rule, you cannot take a program written in machine language for one computer and run it on another. If you write programs in machine language, you have to rewrite them all in order to be able to run them on a new computer. If you use a high-level language, then all you need to rewrite is the compiler.
But compilers are not the only ones who can work with high-level languages. You can also use an interpreter that scans one program segment at a time and executes the corresponding machine instructions, instead of immediately translating the entire piece into machine language and running it.

Open source


The high-level language that you “feed” to the compiler is also known as source code, and the result of its translation into machine language is called object code. When you buy commercial software, you are usually only provided with an object code. (The object code is so hard to read because it is well encrypted to protect the company's trade secrets). But recently, an alternative approach has emerged: open source software (open source), when you are provided with the source code of the program, which can be modified if desired.

The difference between these two models is significant. Open source gives you much more control. When you use open source software and want to understand what it does, you can read the source code and find out. And if you wish, you can even make changes to the program and recompile it.

One of the reasons why you want to do this is to fix the bug. For example, you can not fix errors in Microsoft Windows, because you do not have the source code. (Theoretically, you could crack the object code, but in practice it is quite difficult to implement. And it is also prohibited by the license agreement). This can be a real problem. When you discover a new security hole in Windows, you have to wait for Microsoft to release patches. And the holes in the defense at least quickly corrected. If this bug paralyzes your computer from time to time, then you may have to wait until the next patched release is released.

But the benefits of open source are not limited only to the fact that you have the opportunity to make corrections if necessary. This can all. Open source software is like a document submitted for peer review. Many smart people have studied the sources of open source Linux and FreeBSD operating systems and have already found most of the errors. While Windows is only as reliable as the QA department in large companies can provide.

Open source devotees are sometimes perceived as freaks who oppose the very idea of ​​ownership in general. Some are. But I definitely do not oppose this right, but I would be very reluctant to install software, the source codes of which I would not have. The average end-user may not need the source code of his word processor, but when you really need reliability, this is a good reason to use open source.

Language wars


Most programmers, most of the time, write in high-level languages. Only a few now use assembly language. Computer time has become much cheaper, while the programmer’s time is more expensive than ever, so rarely do situations arise when the time spent on solving problems that have arisen when writing programs in assembly language pays off in the future. This is sometimes necessary in some critical parts, such as a computer game, where you need to control equipment at the micro level to squeeze the last bits of power to accelerate.

Fortran, Lisp, Cobol, Basic, C, Pascal, Smalltalk, C ++, Java, Perl, and Python are all high-level languages. And these are the only ones that are best known. There are literally hundreds of different high-level languages. And unlike machine languages, which all offer a similar set of instructions, these high-level languages ​​provide you with quite different principles for building programs.

So which one to use? Well, a lot of controversy is underway on this. Part of the problem lies in the fact that if you use the language for quite a long time, you start to think on it. Therefore, any significantly different language seems terribly awkward, even if in essence there is nothing wrong with it. Often the judgments of inexperienced programmers about the relative advantages of programming languages ​​are distorted by the action of this impression.

Some computer scientists, perhaps out of a desire to appear more experienced, will tell you that all languages ​​are essentially the same. “I programmed in languages ​​of all types,” said the stern old hacker behind the bar, “and it doesn't matter which one to use.” What really matters is whether you think correctly. ”Or something like that.

Of course, this is nonsense. There is a huge difference between, say, Fortran I and the latest version of Perl. Or, for that matter, between the early and the latest versions of Perl. But the stern old hacker may himself believe in what he says. You can write the same primitive paskalep-like applets in almost every language. If you eat only in McDonald's, then you will find that the food in each country is the same.

Some advanced programmers prefer the language they are accustomed to and dislike all others. Others say that all languages ​​are the same. But the truth is somewhere between these two extremes. Languages ​​really differ from each other, but it's hard to say for sure which one is better. The situation is still in development.

Level of abstractions


As higher-level languages ​​are more abstract than assembly languages, some of these higher-level languages ​​are more abstract than others. For example, C is a rather low-level, practically portable assembly language, while Lisp has a very high level of abstraction.

If programming in higher-level languages ​​is better than in assembly language, then we can expect that the higher the language level, the better it is. Usually yes, but not always. A language can be very abstract, but it offers the wrong abstractions. I think that this is exactly what happens, for example, in Prolog. It implemented incredibly powerful abstractions to solve about 2% of problems, and the rest of the time you are very diligently trying to use these abstractions in an inappropriate way, and write programs like in Pascal.

Another reason you would like to use a low-level language is productivity. If you need a super-fast code, it’s best to stick to machine instructions. Most operating systems are written in C, and this is not a coincidence. As the hardware is getting faster, creating applications in languages ​​as low as C is no longer so critical and important, but everyone still wants operating systems to run as quickly as possible. (Or, probably, everyone wants to always be on the alert for a possible buffer overflow attack. [1])

Seat belts or handcuffs?


The biggest debate in the field of language design is probably the one between those who think that language should protect programmers from doing stupid things, and those who believe that programmers should be allowed to do what they want. Java refers to the first camp, and Perl to the second. (And no wonder, because the US Department of Defense is obsessed with Java.)

Proponents of liberal languages ​​ridicule the camp of opponents, calling such languages ​​"B & D" (bondage and discipline - slavery and discipline), with a rather audacious hint that those who like to program in such languages ​​are simply unlucky. I don't know how the opposing party calls languages ​​like Perl. Perhaps they are not one of those people who come up with offensive nicknames for opponents.

This controversy boils down to several smaller ones, because there are several ways to protect programmers from doing stupid things. One of the most actively discussed issues at the moment is static and dynamic typification. In languages ​​with static typing, you need to know the types of values ​​that each variable can take at the time of writing the program. In dynamic typing, you can assign any value to any variable you want.

Proponents of static typing argue that it helps prevent errors and helps compilers generate fast code (both arguments are true). Proponents of dynamic typing believe that static typing limits you in what programs you can write (which is also true). I prefer dynamic typing. I hate language that tells me what to do. But it seems that some smart people like static typing, so the question is still open.

OO


Object-oriented programming is another big topic at the moment. It is another way of organizing programs. Suppose you want to write a program to find the area of ​​two-dimensional figures. At first, the program will have an idea only about the circle and the square. One of the ways to implement it is to write one piece of code, within which you check what is being asked for: a circle or a square. And then use the appropriate formula to find the area. An object-oriented way of writing programs involves creating two classes, a circle and a square, and then attaching a code fragment (called a method) to each class to find the area of ​​a given type of figure. When you need to calculate the area of ​​something, you ask which class it belongs to, extract the corresponding method, and run it to get the result.
These two cases may seem very similar. And in fact, what actually happens when you run code is pretty similar. (It is not surprising, since you are solving the same task) But the code may look different in the end. In the object-oriented version, the code for calculating the area of ​​a square and a circle can even be represented in different files, one file contains everything connected with a circle, and the other one contains everything connected with a square.

The advantage of the object-oriented approach is that if you want to change the program for calculating the area, for example, a triangle, then you simply add another piece of code for this, and you will not even need to think about everything else. The disadvantage, as critics would say, is that adding without taking into account what has already been implemented will lead to the same results in programming as in construction.

The debate about OO programming is not as clear as it is about static and dynamic typing, where you just have to choose one of the two. And when discussing the object-oriented language, you can only talk about its degree. Indeed, there are two OO values: some languages ​​are object-oriented, since they allow you to program in this style, and others, because they force you to do that.

In the latter version there are few advantages. Undoubtedly, the language that allows you to make x is at least as good as the one that forces you to do this way. Therefore, regarding languages, we can at least circumvent this issue. Of course, use a language that allows you to write OO programs. And whether you really want this is another question.

Revival


I think everyone who is connected with languages ​​will agree that a great number of new programming languages ​​have recently appeared. Until 1980, only universities could afford the equipment necessary to develop such languages, and therefore many languages ​​were designed by professors or researchers in large companies. Now even a schoolboy can afford the necessary "iron".
Inspired mainly by the example of Larry Wall, the creator of Perl, many computer scientists think, why can't I design my own language? Those who manage to curb the power of the open source community have access to a huge amount of code written in a short time.

The result is a type of language that can be called unstable: a language whose core is not very well designed, but which has extremely powerful libraries for solving specific problems. (Imagine a car brand "Zastava" (also known as "Yugo") with a jet engine bolted to the roof). For minor, daily tasks that programmers spend a lot of time solving, libraries are probably more important than the core language. Therefore, such strange hybrid solutions are quite useful, and, accordingly, are becoming popular. A “Zastava” car with a jet engine bolted to the roof might have worked, until you tried to turn on it [2].

Also, as a result, we get a huge variety, which has always been observed in program languages. Fortran, Lisp, and APL differ from each other as much as a starfish, bear, and dragonfly, and all were created before 1970. And the new open languages ​​naturally continued this tradition.

It seems that I learn about the new language every two days. Jonathan Erickson called it “the era of the revival of programming languages.” And people sometimes use the phrase "language wars". But there is no contradiction here. In the Renaissance there was a bunch of wars.

Indeed, many historians believe that these wars were a by-product of the forces that created the Renaissance [3]. The cause of these forces in Europe may have been the fact that it was divided into a number of small, competing states. They were located close enough to each other so that ideas could wander from one to another, but at the same time were independent enough so that no ruler could impose a ban on innovations, as the Chinese court once did, banning the development of large ocean ships.

Therefore, perhaps all of this is for the better that programmers live in a post-biblical world. If we all used the same language, it would probably not be the best.

Notes to chapter 10


1 The most common way to hack computers uses some features of the C language. In C, when you allocate a chunk of memory (buffer) for input data, you assume that it will be located next to the memory containing the return address of the currently running code. The return address is an area in the code memory that will be executed when the current code completes its work. This is essentially the next item on the computer's to-do list.

Therefore, if someone wants to hack your computer, and finds out that you are using a 256-byte buffer to store some input data, then just sending more than 256 bytes, it can rewrite the return address. When the current code is completed, control will transfer to any memory area that was previously determined by the attacker. And the area that he defines will be the beginning of the buffer containing the program in machine language of his choice. Bingo: now his program is running on your computer.

In high-level languages, this would not be possible, but in C, every time you accept input from outside and do not check for a valid length, you create a security breach. An attack that exploits this vulnerability is called a buffer overflow attack.
There are other ways to gain access to computer management through a buffer overflow attack, but rewriting the return address is a classic.

It is curious that the hijackings of aircraft are also attacks on buffer overflow. In a typical airliner, the passenger room and the cockpit are located side by side, just like the data and code areas are located in adjacent areas in the C program. Carrying out the “overflow” towards the cockpit, the hijackers actually facilitate the transition from the data area to the code area.

2 Note for hackers: this is just a metaphor. Do not attempt to drive a Zastava car with a jet engine bolted to the roof. Perhaps the phenomenon of the jet machine is far from new. Fortran also owes its popularity mainly to its libraries.

3 Cipolla, Carlo, Guns, Sails, and Empires: European Expansion 1400-1700, Pantheon, 1965.




Hackers and artists
image
Chapters and translations
www.paulgraham.com/hptoc.html
  1. Why Nerds Are Unpopular
    Their minds are not on the game.
    original translation part 1 part 2
  2. Hackers and painters
    Hackers are makers like painters or architects or writers.
    original , translation part 1 , part 2 , alternative
  3. What you cant say
    How to think with them.
    original translation
  4. Good bad attitude
    Like Americans, hackers win by breaking rules.
    original translation
  5. The other road ahead
    Web-based software offers the largest since the arrival of the microcomputer.
    original translation part 1
  6. How to Make Wealth
    The best way to get rich. And startups are the best way to do that.
    original translation
  7. Mind the gap
    Could "unequal income distribution" be less than a problem than we think?
    original translation
  8. A plan for spam
    Till recently most experts thought spam filtering would not work. This proposal has changed their minds.
    original translation
  9. Taste for Makers
    How do you make great things?
    original translation
  10. Programming Languages ​​Explained
    What is a programming language?
  11. The Hundred-Year Language
    How will we program in a hundred years? Why not start now?
    original translation
  12. Beating the Averages
    For web-based applications. So can your competitors.
    original translation
  13. Revenge of the Nerds
    In technology, "industry best practice" is a recipe for losing.
    original translation 1 , 2 , 3
  14. The dream language
    A good programming language is hackers have their way with it.
    original translation part 1 part 2
  15. Design and Research
    Research has to be original. Design has to be good.
    original translation

Source: https://habr.com/ru/post/281561/


All Articles