Several times, when I think about it, I always ask myself: Why should I give up the go language? Is this decision correct? Is it wise and rational? In fact, I have been seriously thinking about this issue.
To open the door, I gave up the go language (golang) because of two "unpleasant" reasons: first, I was not happy with the go language itself; second, I was not happy with some people in the go language community. Undoubtedly, this is a subjective conclusion. However, I have enough detailed objective arguments to support this seemingly subjective conclusion.
Section 0th: My Go language experience
Let's talk about my experience first to avoid being regarded as a low-level hacker of the go language for no reason.
At the end of 2009, the first public version of Go language (golang) was announced, covering the halo of "made by Google", attracting many early adopters. I (liigo) was also in the middle, I read some documents about the Go language in general and learned the basic tutorial. I forgot it very quickly because I was not satisfied with the semicolons and curly braces in its syntax. I didn't take it as one thing.
Two years later, at the end of 2011, 1.0 of the Go language program was put on the agenda, and there were many reports. I followed it again, [another evaluation] [1] Later, I decided to go deep into the runtime and go languages. I subscribed to official contact lists such as users, nuts, Dev, and commits, insisted on reading emails every day, and every source code update submitted by developers, I submitted a lot of improvement suggestions to go, and even included [modifying the go language compiler source code] [2] direct coding and development tasks. This lasted for several months.
By the beginning of 2012, go 1.0 announced that the language and standard library had been basically finalized and could not be significantly improved. I failed to take a step further before the 1.0 finalized language to achieve self-breakthrough, even with a lot of obvious defects, I felt very disappointed and gradually alienated it (so I am very little concerned about things after go 1.0 ). Later, I saw the release note of Go 1.1, which was about to be announced. I found that the language layer has not changed much. I just repaired and improved it at the library and tool level, and I felt that it was still young and lost the motivation to grow, more disappointed. In addition, some people in the go language community also include some people in the Google company responsible for developing the go language. Their attitudes, words and deeds make me very disgusted, and I will never leave the go language.
Section 1st: Why am I uncomfortable with the go language?
The Go language is a lot of unpleasant things for me. Here I will list some of the items that I can remember today. The ranking is basically different. After reading it patiently, can readers calmly say "I don't care?
1.1 disagree with the left curly braces and start with another line
The placement of curly braces has been controversial for more than a decade in communities such as C, C ++, Java, and C #, and no consensus has been formed. In my opinion, this is a choice with a very strong subjective tendency. In the case that no violation of principles involves no right or not, we should not make a one-size-fits-all plan. It is enough for programmers or teams to choose on their own. The programming language itself imposes restrictions and imposes its preferences on others. Regardless of the casual one, it is bound to offend a group of people opposed to it. Although I am used to placing left curly braces at the end of a row, I feel very uncomfortable when I think of being banned from other choices. On the issue of the Go language, we didn't say "unite all the forces that can be united", and we still wanted to make enemies for ourselves, which was too bad.
1.2 The Compiler inexplicably adds a semicolon to the end of a line
For the go language itself, the semicolon at the end of the line can be omitted. However, in the implementation of its compiler (GC), in order to facilitate compiler developers, the semicolon at the end of the line is forcibly added in the lexical analysis phase, which in turn affects the language specification, make special rules on "How to add a semicolon. Such abnormal practices are unprecedented. When the left curly braces are accidentally placed at the beginning of the next line, it automatically adds a semicolon to the end of the last line, which may cause an inexplicable compilation error (before go 1.0 ), it cannot be clearly explained by itself. If it is difficult to handle semicolons, do not omit them. Or, scala and JavaScript compilers are open-source. How do you learn from them?
1.3. The compilation speed is greatly emphasized, and the functions that should be provided are not abandoned.
Programmers are not gods, and make mistakes due to carelessness or negligence in the coding process. Some of these errors are very easy to integrate. (I cannot remember the samples in the go language, the example in C ++ contains "the basic class destructor is not a virtual function "). At this time, the compiler should come up and do more checks, constraints, and checking, so as to prevent regular errors as much as possible and prevent code with potential errors from being compiled, if necessary, give some warnings or prompts so that programmers can pay attention to them. Isn't the compiler A machine, or is it necessary to do more dirty jobs and other jobs to reduce people's mental burden? The compiler does more than one check, which may prevent hundreds of thousands of programmers from making the same errors countless times in the years to come, saving countless times. This is a good thing. However, the authors of the Go compiler do not think so. They do not want to spend several hours to add new functions to the compiler. They think it is a loss, but it slows down the compilation speed. They refused many compiler improvement requirements on the grounds of affecting Compilation speed. The typical cause is waste. It is worth watching to emphasize the compilation speed, but I do not agree if I give up the necessary functions.
1.4 error handling mechanism beginning of Taiyuan
In the go language, the basic mode for error handling is: The function usually returns multiple values, and the last value is the error type, which indicates that the error type is extremely descriptive; each time the caller calls a function, the caller must check the error and handle the error accordingly. This mode is similar to the very primitive error handling in C language, and there is no substantial improvement. In practice, it is very easy to form a multi-layer nested if else statement. Think about this encoding scenario: first, infer whether the file exists. If the file exists, open the file. If the file is opened successfully, read the file, assuming that a piece of data is successfully read, and the file is closed, do not forget to handle errors in each step. How abnormal and ugly is the code written? In practice, it is common to infer that an error is returned in advance to avoid multi-layer curly braces nesting. But the consequence of this is that many error handling codes are placed in the prominent position, the conventional processing logic is buried behind it. In addition, the standard interface of the error object can only return an error text. Sometimes the caller even needs to parse the text to distinguish different error types. In addition, you can only manually forcibly convert the error type to a specific subtype. As for the panic-Recover mechanism, the fatal defect is that it cannot be used across the boundary of the database. It is destined to be a semi-finished product and can only play in its own PKG. Although Java Exception Handling also has its own problems (such as checked exceptions), it is still much better than go error handling.
1.5 garbage collector (GC) is not in good condition and has major defects
On the eve of Go 1.0, its garbage collector leaked memory in a 32-bit environment and had been dragging on to improve. The real fatal defect of the Go language garbage collector is that it can cause unpredictable intermittent pauses throughout the process. For example, some large backend service programs, such as game servers and app containers, have a large number of memory objects because they occupy a large amount of memory. The garbage collection cycle may take several seconds or even longer, during this period of time, the entire service process was congested and paused. in the outside world, it seems that the service was interrupted and there was no response, and the concurrent mechanism was no longer valid here. The garbage collector is regularly started, causing brief service interruption every time it is started. Do you dare to use it? This background server process is a key application area of the Go language. The above phenomenon is not what I did, but a real problem that exists in the facts. It is not a matter of two families that are seriously plagued (as of the beginning of 2014 ). In practice, you must reduce the number of objects in the process to control the intermittent pause caused by GC to an acceptable range. In addition, you have no choice (Do you still want to change the GC algorithm or even cut down the GC? Is it still the go language ?). I have been thinking about it recently. Do I need a garbage collector? Is it true that the garbage collector is not used in history? (A new blog article topic may be written .)
1.6 disable unused variables and redundant Import
The Go compiler does not agree to the existence of unused variables and redundant import. If so, compilation errors may occur. However, the reality is that during code writing, refactoring, and debugging, for example, temporarily staring at a line of code, very easy will cause unused variables and redundant import at the same time, and the compilation is incorrect directly. You must stare at the variable definition accordingly, go back to the file header and stare at the redundant import ,...... When things are done, it takes several troublesome steps to retrieve the code that you just stared. Another annoying problem is that when you write database-related code, if you import a database-driven PKG, it compiles an error to you, saying that you do not need to import this unused PKG; but if you listen to the compiler and delete the import, the compilation will pass, and an error will be reported during execution, saying that the database driver cannot be found. You can see that the program is not a human on either side, finally, I had to ask for help._
. To solve such a problem, a better solution than compile is to regard it as a compilation warning rather than a compilation error. However, go language developers are stubborn and do not accept such a compromise.
1.7 there are too many ways to create objects, which is confusing.
How to create an object: Call the new function, call the make function, call the new method, and use the curly brackets syntax to directly initialize the struct. Which one do you choose? It is hard to choose because there is no fixed mode. In practice, if you want to create an object with built-in language types (such as channel and map), you can often use the make function to create the object; suppose you want to create a standard library or a third-party library-defined type object. First, check whether there is a new method in the document. If there is a new method, you 'd better call the new method to create an object. If there is no new method, second, create an object by initializing the struct. This process is quite twists and turns out that it is not as straightforward new as C ++, Java, and C.
1.8 No constructor or destructor for the object
There is no constructor. After all, there is a new method defined by myself, which is basically a constructor. RaiI cannot be implemented without destructor. The extra manual processing of resource cleanup will undoubtedly increase the mental burden of programmers. It's not human. Do we still think our programmers are working less overtime? In C ++, there are destructor. in Java, although there are no destructor, there are other finally statements. What about go? Nothing. Yes, you have a defer, but the defer is more problematic. For more information, see the following.
1.9 The semantic setting of the defer statement is not reasonable
The Go language is designed with a defer statement. The "code" for releasing resources is placed near the place where resources are created, but the "Action" for releasing resources is postponed (defer) run before the function returns. Unfortunately, it seems that the runtime settings are not reasonable. Suppose there is a function that needs to run for a long time. There are infinite loop statements, and resources (or memory allocation) are constantly created in the loop body, and the defer statement is used to ensure the release. Since the function has never been run and no response is returned, all defer statements cannot be run, and a large amount of transient resources created during the loop process have been accumulated and cannot be recycled. In addition, the system also needs to occupy additional resources to store the defer list, which is also added continuously. In this case, the entire system will crash due to resource depletion in a short time. For such long-running functions, HTTP. listenandserve () is a typical example. In the key application fields of the Go language, it can be said that every background service program must have such a type of function, which is often the core part of the program. If the program ape accidentally uses the defer statement in these functions, it can be said that there are endless troubles. If the language designer sets the defer syntax to run at the end of the code block (rather than when the function is returned), is it better? However, go 1.0 has already published its stereotypes. To maintain backward compatibility, it is impossible to change the settings. Use the defer statement with caution! Do it accidentally.
1.10 many language built-in facilities do not support user-defined types
For in, make, range, channel, map, and so on only support language built-in types, and do not support user-defined types (?). User-Defined types cannot support the for in loop. Users cannot write functions that can change the number of values or even return value types and numbers like make and range, you cannot write data types that are similar to generics like channel and map. The language's built-in things are everywhere full of traces of axe. This reflects the limitations, closeness, and integrity of language design, such as the work of a newbie-no matter how authoritative its designers and implementers are.
1.11 No generic support, and common data type interfaces are ugly
Without generics, interfaces of the list, set, and tree basic data types can only be very ugly: the object to be put in is a detailed type, the data is untyped.interface{}
(Can be regarded as the basic type of all types), you have to force the type conversion before you can continue to use, it is speechless. The Go language lacks functions such as Min and Max. ABS only receives/returns double-precision decimals for the function to calculate the absolute value of a value. The sorting interface can only use sort. the interface does not have to be replaced by the struct object type, and so on. It is the result of no generics. Without generics, the interface is very difficult to elegance. Go developers do not understand how to reject generics. They just say that they have not found a good way to implement generics (can they learn open-source languages ). The reality is that go 1.0 has been finalized and generics are not yet available. Ugly interfaces must exist for a long time to maintain backward compatibility.
1.12 The declaration is not required to implement the interface
This item is generally promoted as an advantage of the Go language. Some people disagree, for example, me. Assuming that a type uses the go language to silently implement an interface, it is very difficult for the user and the code maintainer to find this point (unless the function signature of each method of this type is carefully checked, and compares them with all possible interface definitions). Naturally, you cannot think of applications related to this interface, which is very obscure and not intuitive. The supporter may argue that I can indicate in the document what interfaces It implements. The problem is that it is better to write data directly to the type definition in the document. At least the static type check of the compiler can be obtained. Without the support of the compiler, when the function signature of the interface type is changed, it may be hard for the implementer to realize that the type and method of the interface are accidentally changed, this type of implicit constraint for implementing this interface has actually been broken. Some people argue that I can use the unit testing to ensure that the type is correct and the interface is implemented. What I want to say is that you can clearly understand the Declaration implementation interface and enjoy the type check provided by the compiler, but you have to look for trouble by yourself and try to write unnecessary unit samples, is it great to find abuse? In addition to reducing the dependency on the library where the interface is located, the Go language has no other advantages and is worth the candle.
1.13 saving parentheses, but saving curly braces
The conditional expressions of the IF Statements in the go language do not need to be expanded with parentheses, Which is publicized as evidence that the code is more concise than the limit. However, you have saved parentheses, but you cannot save them. It takes at least three lines for a complete if statement, c, C ++, and Java can all be done in one row (which saves curly braces ). Othersx?a:b
The expression is also a line. Do you have to write at least five lines in the go language using if else? Where is it concise?
1.14 The size of the executable files generated by compilation is large
I remember that I wrote a very easy program that output the names and values of all system environment variables to the console. The core code is just like three or five lines, and the results are compiled to scare me: the size of the EXE file exceeds 4 MB. Suppose it is a program with the same function written in C language, and 0.04mb is large. I sent this information back to the official Community, and people don't care about it. Yes, I know that today's hard disk capacity is hundreds of GB, up to TB ...... The degree of optimization ...... How can I believe that you can do well in other places. (Once again, all my experience and data come from the eve of Go 1.0's announcement .)
1.15 dynamic loading of class libraries is not supported
The static Compilation Program is of course very good, and there is no additional dependency for execution, which is very convenient for deployment. But as we mentioned earlier, the size of the static compilation file is very large. Assuming that a software system is composed of multiple executable programs, the accumulation is very impressive. If dynamic compilation is used, the same dynamic library is included in the announcement, which can save a lot of capacity. More importantly, the dynamic library can be loaded and detached during execution, which cannot be implemented by the static library. Third-party C libraries with lgpl and other protocols are subject to copyright restrictions and do not agree to static compilation. To solve the version number management problem of a dynamic library, you can add a version number to all the symbols in the dynamic library. In any case, you should give programmers the option to decide whether to use static or dynamic libraries. One-size-fits-all denial of dynamic compilation is not suitable.
1.16 others
- Method and function overload are not supported)
- The rest of the Import Statement for PKG is actually text (Import "FMT ")
- Without the enum type, global constants are difficult to classify, and iota complicate simple tasks.
- When defining object methods, pointer or non-pointer should be used for the Cycler type
- Syntax for defining struct and interfaces is a little complex,
interface XXX{}
struct YYY{}
Isn't it more concise? Addtype
The keyword looks coorse.
- There is no assertequal function in the test class library testing, and the unit test code of the standard library is filled
if a != b { t.Fatal(...) }
.
- The language is so simple that you have to give up a lot of practical features. Keeping the language simple is often the reason for rejecting improvement.
- The implementation of the standard library is not ideal as a whole, and its code quality is generally "basically available". When it comes to enterprise-level application fields, many shortcomings are often exposed.
- The versions have all grown to 1.2, and the goroutine scheduler still uses only one system thread by default. The long term existence of gomaxprocs seems to imply that the Government has never had enough confidence to ensure that the scheduler runs securely and correctly in a multi-core environment. This is a fatal conflict with the positioning of the Go language based on concurrency.
The above lists the unpleasant things I can think of in the go language. After all, the time has passed for more than two years, and others have long forgotten about it. Some of them are not uncomfortable, and they may be able to endure it. However, it is difficult to feel self-abuse for a long time. The work and life of programmers are boring enough. Why.
I (liigo) tried to change most of the negative comments: before the release of Go 1.0, I have made a lot of comments and suggestions in my official contact list and tried my best to say that I have made great efforts, the objective is to make the finalized go language a relatively well-established programming language without obvious defects. The result is disappointing. I have a few simple words and a weak trend, which cannot affect the development of the entire language. Before 1.0, we were so sorry to miss the opportunity to deny ourselves and surpass ourselves. I finally found that many times it is not a technical problem, but a technical problem.
Section 2nd: Why am I unhappy with some people in the go language?
There are two main types of "some people" mentioned here: 1. Google employees who are responsible for full-time development of Go language; 2. Advocates of Go language and fans of brains. I have had many dealings with these two types of people. Once again, I mean "some" people, not all people. Please do not check the number.
Some members of Google's core development group responsible for full-time development of Go language tend to build cars behind closed doors and stick to their own opinions, so they do not pay attention to the suggestions made by third parties. Their mantra is: the existing practice is very good. We don't need that function. We developed the go language for Google. Google doesn't need that function. If you have to change it, please fork and change it yourself. submit the code for comments. Many words and deeds are "anti-Open Source. Through some detailed examples, you can see this layer more vividly. Leave it as a homework.
What I can't accept most is their diffuse processing of version 1.0. At that time, go had not reached 1.0, and primary school students had a lot of room for improvement. It was the best time to complete the renovation. When did they not change? 1.0 is the version number of the Foundation, and the foundation is not reliable. After the 1.0 is finalized, it will be restrained by backward compatibility everywhere, and it will be difficult to move forward. Eager to announce the announcement of 1.0, the early finalization left a lot of regrets, highlighting the strong utilitarian nature of developers and the lack of technical perfection.
Core developers of the Go language, whose daily development work is to use the C language-the go language compiler and execution time library, including the core data structure of the language map, channel, scheduler, all are developed in C-there are not many opportunities to actually develop large applications in the go language developed by myself, although the standard library is written by myself in the go language, however, they do not have a wide range of experience using the standard library. In fact, they lack hands-on development experience using the go language, and often do not know what the first line of development users really need, so they cannot put themselves in consideration of programmers. Lack of hands-on experience in using the go language also means that they cannot promptly discover and improve the deficiencies in the go language during daily development. This is why they often feel good about themselves.
In the go language community, there are a large number of advocates and fans of the Go language. They are satisfied with the status quo, do not think ahead, and maintain the "God" in their hearts everywhere, so they are not allowed to criticize their opinions, language Improvement requirements are not supported. I had a lot of criticism and Improvement Opinions on the go language and received little support from them. They not only gave support but also gave a blow, so I was puzzled, do they not want the go language to be better and better? I later realized that they are in the same line as the Apple fans of the Qiao bangzhu. They have an extreme religious tendency, and they have no efforts to turn their masters into gods and fight against their differences. Simple technical problems can be escalated to ideological contention. There are a lot of practical examples. If you are interested, go to the Internet to find them. It is precisely because of their existence that many other rational and sober go language users cannot truly integrate into the entire community.
If a project, team, or community is filled with praise, self-appreciation, self-satisfaction, and hard work, and rejects the acceptance of new solutions, I cannot think of any motivation to move forward. If you go against the boat, you will not go back.
Section 3rd: is there a better choice than the go language?
I have always insisted on a dialectical philosophical point of view: Before a better alternative emerged, the existing one is the best. Disappointment is not practical. complaints are not practical. either accept or escape. I tried to accept the go language before. After the failure, I was doomed to escape. Finding better alternatives will undoubtedly accelerate the escape process. Is there a better alternative than the go language? Of course. I should tell you what it is, but I will not. Now is not the time. I don't want to confront these two programming languages today, leading to another potential language war. This is not the intention of this article. Suppose you have to guess from the existing information what it is, it is your own business. If you wait for your original intention, it may be very fast and unknown.
Section 4th: written at the end
I do not mean to be represented by others or represent others. This article is written by me, liigo's post 80 diaosi programmers, and my own point of view. You can fully think of it as subjective or objective. In any case, it is your opinion.
This text is extracted from memory. Although some details are acceptable, they are not worth the test. -- I have been away, and I don't want to go back to the current scenario. Some details involved in this article may affect its accuracy due to some deviations, or its objectivity due to lack of source. Suppose someone is more real and has to verify it. I believe those things should still be there.
The Go language is not useless as described above. It certainly has its advantages and characteristics. Readers infer that a single thing should be both good and bad, and make a comprehensive analysis, so they cannot listen to my negative words alone. However, the unpleasant aspects of it always make me uncomfortable, and cannot be completely balanced from its excellent points. This is why I have to give up on it.