The comprehensive evaluation of "turn" to go language

Source: Internet
Author: User
Tags garbage collection ocaml

I've written some negative reviews of the Go language before. Now it seems that although most of those evaluations are true, it is hard to convince certain people because of the intense rhetoric and the lack of specific questions. After a few months of actually using Go to construct the site, I think it's time to make some more "objective" comments about it.

Positioning and benefits

It is obvious that Go does have its advantages over C and C + +. It has a few advantages over Java, but it is more of a disadvantage. So my preference for Go is a little bit lower than Java.

The Go language is more than C,c++ 's strength, of course, its simplicity and garbage collection. Since the design of C and C + + has many legacy issues, Go seems to be more elegant and simple. The code for the Go language seems to be simpler than the Java code that uses a lot of design patterns. In addition, Go's garbage collection mechanism, compared to C and C + + 's full manual memory management, greatly reduces the programmer's mind burden.

Note, however, that the so-called "pros" here are relative to languages such as C. This advantage of Go may be insignificant, even a throwback to history, if compared to some other languages.

Grammar

The simplicity of Go is embodied in some aspects of its syntax and semantics. Go's syntax is slightly better than C, there are a few more convenient designs than Java, but there are also "backwards" places. And these setbacks are not considered by many to be regressive, but rather as progress. I now cite a few things I can think of temporarily:

  • Progress: Go has syntax to support a struct-like literal structure, such as you can write code to construct an S struct:

      S {x:1, y:2,} 

    This is a good convenience improvement over Java's use of constructors only to create objects. These things may be borrowed from the design of languages such as JavaScript.

  • Backwards: The type is placed behind a variable without a delimiter. If the variable and its type are written like Pascal, such as x:int , that might be fine. However, Go is written x int , without that colon, and allows the use of x, y int This is the notation. This syntax, combined with VAR and function parameters, creates the effect of disturbing the line of sight. For example, you can write a function that starts with this:

      func foo (s string, x, y, z int, c bool) {...}  

    Note that the position of x, Y, Z is really confusing. Because when I saw x I couldn't immediately see what type it was from that symbol (). So in Go I recommend the notation is to x and y completely separate, like C and Java That way, but the type is written in the following:

      func foo (s string, x int, y int, z int, c bool) {...}  

    This is clearer, although I would like to write some more colons. Each parameter is a "name type" format, so I see at a glance that x is int. Although a few more words, but save the "eye parse code" overhead.

  • Backwards: type syntax. Go uses syntax like []string to represent the type. Many people say that this grammar is very "consistent", but after a while I did not find out what they called consistency. In fact, this syntax is difficult to read, because there is no explicit delimited identifier between the parts of the type, and if you are paired with some other symbols, such as *, you need to know some priority rules and then do the "eye parse" with a lot of effort. For example, in the Go code you often see []*struct such a type, note *struct The is to be combined first and then as the type parameter of [] . This syntax lacks enough delimiters as a "boundary signal" for reading, and once the later types become complex, it is difficult to read. For example, you can have *[]*struct or *[]*pkg. A type such as Struct . So this is not as good as C + + VECTOR<STRUCT*> this way, it's less like Java or Typed Racket Type is clear and simple.

  • Backwards: Excessive "syntax overloading", such as switch, for and other keywords. The Switch keyword for Go actually contains two different things. It can be a normal switch (scheme case) inside C, or it can be a nested branch statement like scheme's cond. The two statements are semantically different, but the designers of Go are more confused in order to appear simple and merge them into one. This is because, even if you combine them, they are still two different semantic constructs. The result of merging them is that each time you see a switch you need to separate the two different structures from their "head" points, increasing the overhead of the human brain. The right thing to do is to separate them, just like Scheme. In fact, I design the language sometimes also make the same mistake, think two things "essence" on the same, so one, the result after a period of time, found actually is not the same. So do not underestimate the Scheme, many of the things you think of as "new ideas", in fact, it has long been the very strict committee to abandon in the river of history.

There are some other grammatical design problems in the Go language, such as forcing a line { after a row and not wrapping it, the IF statement can be nested in the beginning of the evaluation of the operation and so on. These attempts to make the program seem short, in fact, reduce the flow of program understanding.

So, in a nutshell, the grammar of Go is hard to call "simple" or "elegant", and its simplicity is actually under Java.

Tool chain

Go provides some handy tools. such as Gofmt,godef and so on, make Go code programming than the single Emacs or VIM to edit C and C + + is a progress. Using Emacs to edit the Go has been able to implement some of the functions of the IDE, such as the precise definition of jump and so on.

While these tools are useful, the gap is quite large compared to Ides like Eclipse, IntelliJ and Visual Studio. The Ide,go tool chain lacks the most basic functions, such as listing all the locations that reference a variable, renaming the Refactor function, and the use of debugger (GDB is not easy to use) and so on.

The tools of Go are not very mature, and sometimes you find that there are several different kinds of package to solve the same problem and it's unclear which one is better. And these things are not so reliable and simple configuration, all need to toss. Every little feature you have to look for package to configure from everywhere. There are times when a tool is configured that doesn't actually work, so you can find out where the problem is when you're groping long time. This non-organized, unplanned tool design is difficult to exceed the coherence of professional IDE vendors.

Go provides a handy package mechanism to import the go code directly from a GitHub repository. But I find that many times this package mechanism brings more trouble and dependency. So the Go advocates have designed some tools like GODEP to get around these problems, and the results godep themselves with some outlandish questions that sometimes the new code is not actually compiled, producing inexplicable error messages (probably due to godep bugs).

I've found that many people who see these tools are always crazy to think that they can make the Go language eminence, but it's really far off. And so many problems have arisen in such a young language that I feel that all these troubles have accumulated over the years.

Memory management

Go has a garbage collection (GC) mechanism compared to a completely manual memory management approach of C and C + +. This mechanism greatly reduces the programmer's mental burden and the chance of a program error, so Go is a step forward for C + +.

However, progress is also relative. Go's garbage collector is a very primitive mark-and-sweep, which is still in its infancy compared to language implementations like Java,ocaml and Chez Scheme.

Of course, if you really encounter GC performance problems, you can partially improve the efficiency of memory recycling by using a lot of tuning. I've also seen people write articles about how they do these things, but the existence of this article shows that Go garbage collection is still very immature. GC This kind of thing I think most of the time should not be for the programmer to worry about, or lose the GC compared to manual management of many advantages. So the go code wants to be in the high-real-time situation, still has a long way to go.

Because of the lack of advanced GC, but with advanced abstraction, Go does not actually replace C and C + + to construct the underlying system. The orientation of the Go language is becoming more and more obscure to me.

No "generics".

Go lacks generics compared to C + + and Java. While some people hate Java's generics, it is not a bad one in itself. Generics is actually Haskell and other functional language inside the so-called parametric polymorphism, is a very useful thing, but was copied by Java sometimes did not do all right. Because generics allows you to use the same block of code to handle many different types of data, it is convenient to avoid duplication and to easily replace complex data structures.

Since Go has no generics, you have to write a number of functions repeatedly, each with only a different type. Or you can use the empty interface {}, however this thing is actually equivalent to the void* pointer of C. After using it, the type of the code can not be static check, so in fact, it does not generics rigorous.

Many of the data structures in Java,go are "hard code" into the language, even creating special keywords and grammars to construct them (such as a hash table). Once you encounter a user who needs to define a similar data structure, you need to rewrite a lot of code. And because there's nothing like Java collections, it's not easy to replace complex data structures. These deletions of the Go language can be a big hurdle for constructing programs like Pysonar that require a lot of experimentation to choose the right data structure, and need to implement a special hash table.

The lack of generics is a problem, but the more serious problem is the blind rejection of the language features of Go designers and their communities. When you mention this, go supporters will tell you in a contemptuous manner: "I can't see what's the use of generics!" "This attitude is more harmful than the shortcomings of the language itself." After a long time, the go language designers began to consider joining Generics, and then because of the grammar design of Go jerry-building, coupled with the lack of generics due to the special case (such as Go Map grammar design) has been widely used, I think to join the generics The difficulty is already very large.

Go, like the Unix system, has a heavy historical burden on the early days of not absorbing the lessons of previous generations.

Multiple return values

Many people think that go's multiple return value design is a progress, but there are a lot of strange things. And not to say that this is nothing new (Scheme very early has a lot of return value let-values), Go's multiple return value is used in a lot of the wrong place-go use multiple return values to represent error messages. The most common structure in Go code, for example, is:

ret, err := foo(x, y, z)if err != nil {return err}

If foo the call produces an error, then err it is not nil. Go requires you to use it after you define the variable, otherwise it will be an error. This way it "happens" err to avoid situations where errors are not checked. Otherwise, if you want to ignore the error, you have to write

ret, _ := foo(x, y, z)

This way, when Foo goes wrong, the program will automatically fall in that position.

It must be said that this "fluke" approach, although seemingly feasible, from a type system point of view, is very not rigorous. Because it is not designed for this purpose at all, you can easily come up with a variety of ways to make it ineffective. And since the compiler checks only for " err use", it does not check if you have checked for "all" possible error types. For example, if Foo may return two errors Error1 and ERROR2, you cannot guarantee that the caller will not use the data until the possibility of the two errors is completely ruled out. So this error-checking mechanism is not as serious as Java's exception.

In addition, ret and err at the same time is defined, and each time only one is not nil, this "or" relationship is not by the compiler to protect, but by the programmer's "conventional". This is not err nil, in ret fact, it can not be nil. These combinations bring a lot of confusion so that every time you see a return, you're not sure whether it's going to return an error or a valid value. If you realize that this "or" relationship actually means that you should only represent them with a return value, you know that go has misused multiple return values to represent possible errors.

In fact, if a language has a "union type" type system like Typed Racket and Pysonar, this multi-return value is meaningless. Because if you have union type, you can use only one return value to represent valid data or errors. For example, you can write a type called {string, filenotfound}, which indicates that a value is either a string or a filenotfound error. If a function is likely to return an error, the compiler will force the programmer to check all possible errors before it can use the data, thus avoiding all of the above confusion altogether. People interested in union type can look at Typed Racket, which has the most powerful type system I have seen so far (beyond Haskell).

So it can be said that the go of this multi-return value, in fact, "crooked dozen" hit half, and then change the way to continue to beat, rather than aiming at the bull's eye.

Interface

Go uses an interface (interface)-based object-oriented design, and you can use interfaces to express some of the concepts you want to abstract.

However, this interface design is not without problem. First, unlike Java, implementing a Go interface does not require an explicit declaration (implements), so you might "happen" to implement an interface. This uncertainty is counterproductive to understanding the process. Sometimes you modify a function to find that the compilation does not pass, complaining that a location is not a required interface, but the error message can not tell you the exact reason. It takes a few groping to find out why your struct no longer implements an interface defined previously.

In addition, some people use interfaces, many times just to pass some functions as parameters. I sometimes do not understand that this is a simple function of the language, and why in the Go language to define a different interface to achieve. This makes the program less clear than the functional language, and it is inconvenient to modify. There are a lot of redundant names to define, redundant work to do.

A related example is the Sort function of Go. Each time you need to sort an array of some kind, T for example []string , you need to

    1. Define another type, usually called TSorter , such asStringSorter
    2. StringSorterdefine three methods for this type, called, respectively Len , SwapLess
    3. Put your type, like []string castStringSorter
    4. Call sort.Sort to sort this array

Think about how easy it is to sort in a functional language? For example, Scheme and OCaml can be written directly like this:

(sort ‘(3 4 1 2) <)

This Scheme passes the function < directly as a parameter to the sort function, without wrapping it in any interface. Did you find out that the three methods in the Go interface, in fact, should have been passed directly to Sort as three parameters, but because of the limitations of the design pattern, Go's designers put them "packaged" as interfaces to pass. And because Go does not have generics, you cannot write these three functions as a functional language, accept the "elements" of the comparison as arguments, and must use their "subscript". Because these methods only accept subscript as parameters, sort can only be sorted on an array. Also, because Go is designed to be "bottom", you need two more parameters: Len and swap.

In fact, this interface-based design in fact, compared to functional language, the gap is very large. Compared to Java interface design, it can also be said to be a setback.

Goroutine

Goroutine can be said to be the most important feature of Go. Many people use Go to hear that goroutine can support so-called "big concurrency."

First of all, this big concurrency is not something new. Everyone who understands the theory of programming language knows that Goroutine is actually some user-level "continuation". System-level continuation are often referred to as "processes" or "threads." Continuation is something that functional language experts can understand, like my former mentor Amr Sabry is one of the top experts on continuation.

node. JS's kind of "callback hell", in fact, is a commonly used method of functional language, called continuation passing Style (CPS). Because Scheme has a call/cc, it can theoretically be implemented without the CPS-style code to achieve large concurrency. So as long as the functional language support continuation, it will be easy to achieve large concurrency, perhaps more efficient, better use some. For example, an implementation of Scheme gambit-c can be used to achieve large concurrent things. Chez Scheme may also be possible, but it has yet to be confirmed.

Of course there may be a difference in the efficiency of the implementation, but I'm just saying that Goroutine is not a new, revolutionary, unique thing as many people think. As long as there is enough motivation, other languages can add this thing.

Defer

Go implements the defer function to avoid forgetting to clean up the mess after a function error (cleanup). However, I find that this defer function has a tendency to be abused. For example, some people do not cleanup the action is also made defer, to accumulate a few defer later, you can no longer see exactly which piece of code to run first and then run. The code in front of the location can actually run later, violating the natural positional order of the code.

Of course this can blame the programmer for not understanding the real purpose of defer, but once you have this kind of thing someone will want to abuse it. People who are eager to use every kind of feature in a language are particularly fond of doing such things. It may take years of experience for this kind of problem to be written to educate people. I predict that defer will still be heavily abused before a unified "code Specification" is formed.

So we should think about, in order to avoid the possible resource leakage, defer brought to the end is droperidol or more harm.

Library code

Go's standard library is designed with a strong Unix flavour. Its library code has a lot of inconvenient places than languages like Java. Sometimes the way of functional language is introduced, but because of the limitation of Unix thinking, not only can not play the advantages of functional language, but also lead to a lot of understanding complexity.

An example is the way Go handles strings. The characters contained in each string in Java are the Unicode "code point" by default. In Go, however, each element in the string type is a byte, so each time you have to cast it as a "rune" type to correctly traverse each character and cast it back. This way of thinking of everything as Byte is the way Unix thinks, which causes excessive underlying and complex code.

HTML Template Library

I have used the Go template library to generate some Web pages. This is a "basic available" template, but it is quite inadequate compared to many other mature technologies. To my surprise, the code inside the go template is not actually the go language itself, but rather a very weak expression of the language, a bit like a degenerate Lisp, just replace the brackets with { {...} } such things.

For example, you can write Web templates like this:

{ {define "Contents"} }{ {if .Paragraph.Length} }<p>{ {.Paragraph.Content} }</p>{ {end} }{ {end} }

Since each template accepts a struct as a fill of data, you can use .Paragraph.Content such code, however this is not only ugly, but also makes the template inflexible and difficult to understand. You need to put all the data you need into the same structure to access them from within the template.

Any more than one line of code, although perhaps the language can be expressed, the average person in order to avoid the weakness of the language, or in the. go file to write some "help function." Use them to generate data into the structure and then to the template to be able to express some of the information required by the template. Each of these help functions requires a certain "registration" information to be found by the template Library. So these complexities add up, making Go HTML template code quite cumbersome and confusing.

I heard someone is making a new HTML template system that can support direct Go code embedding. The work is just starting, and it's hard to say what it will look like at the end. So to do the site, I am afraid it is best to use other languages more mature framework.

Summarize

Elegance and simplicity are relative. Although the Go language in many ways than C and C + +, but also in some ways better than Java, but it is actually not compared with the elegance of Python, and python in many ways is not as good as Scheme and Haskell. So all in all, the simplicity and elegance of Go is lower than average.

Because there is no obvious advantage, but there are a variety of other languages do not have problems, so in the actual project, I am now more inclined to use the Java language. I don't think that the Go language and its toolchain can help me to quickly write code that is as sophisticated as Pysonar. I also heard that some people use Java to achieve large concurrency, and did not find any obvious shortcomings than Go.

"Language design should not be about piling up functions, but trying to reduce weaknesses," says Alan Perlis. From this point of view, the Go language introduces one or two new features, while introducing a considerable number of weaknesses.

Go may temporarily have special strengths in some individual situations that can be used to optimize parts of the system alone, but I do not recommend using Go to implement complex algorithms and the entire system.

The comprehensive evaluation of "turn" to go language

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.