What is and what is not in Go. Part 2

Hello! Today we share the final part of the translation of the article โ€œWhat is and what is not in Goโ€. We remind you that in the first part we talked about the elements that are in Go, today weโ€™ll talk about what is not in Go.



The translation of this material was prepared in anticipation of the start of a new stream at the Golang Developer course.







Go was created with a look back, and its basic configuration is really well-composed: it has garbage collection, packages, first-class functions, lexical scope, system call interface and immutable lines, the text of which is usually encoded in UTF-8. But it has relatively few features and is unlikely to increase their number. For example, it has no implicit numerical conversions, no constructors or destructors, no operator overloads, no default parameter values, no inheritance, no generics, no exceptions, no macros, no function annotations, and no local stream storage.










Items not found in Go



Implicit number conversion



In programming, type conversion involves changing the data type of an object to another. Implicit conversion means that this change is made automatically by the interpreter or compiler. For example, assigning an int value to a variable that was previously assigned a floating point value. This conversion is not available in Go. When a type is not mentioned when declaring a variable, it is assigned a suitable type, for example, int, float, string, etc., based on the syntactic composition of the literal. In the example below, Go will throw an error because it will find two different data types and will not be able to work with them. This happens because the Go compiler implicitly converts int



to float64



.



 a := 1.0 // same as float64(1.0) b := 1 // same as int(1) fmt.Printf("%f", a*b) // invalid operation: a * b (mismatched types float64 and int)
      
      





Constructors and destructors



The task of the designers is the primary processing and initialization of the object, and the destructor is to destroy the object after its service life and free memory. Unlike other object-oriented paradigms, there are no classes in Go. Therefore, the concept of constructors and destructors also does not exist.



Operator Overload



Operator overloading is a way in which operators can perform user-defined operations. Operators behave according to the arguments passed. For example, in C ++ +



operator can be used to combine strings, as well as add two integers. The value โ€œ+โ€ can also be defined by the user and changed according to the needs of the program. In JavaScript, an operation of type '1' + 1



will result in the output of the string "11"



due to the higher priority of the strings. Such definitions are not allowed in Go, the operators work strictly and perform operations only with certain data types of arguments.



Default values



Go does not allow defaults in function prototypes or when functions are overloaded. The Go language specification is unusually small and specifically supported as such to simplify parsing. Unlike other languages, where you can pass default values โ€‹โ€‹/ optional parameters to a function, in Go you can only check if a value has been passed. A different approach to the default values โ€‹โ€‹in Go would be something like this.



 func Concat1(a string, b int) string { if a == "" { a = "default-a" } if b == 0 { b = 5 } return fmt.Sprintf("%s%d", a, b) }
      
      





Inheritance



Because Go does not follow the familiar hierarchy of object-oriented programming classes, structures in Go are not inherited from each other. In general, inheritance is a procedure in OOP languages โ€‹โ€‹in which one class inherits the properties and class method of its parents. Inheritance can go deep into several levels. However, in Go, a structure can be simply constructed by providing a pointer or embedding in collaborative structures. An example composition on Go is given below. Classes can be replaced by interfaces in Go. Interfaces exist in other languages, but Go interfaces are implicitly satisfied.



 type TokenType uint16 type Token struct { Type TokenType Data string } type IntegerConstant struct { Token *Token Value uint64 }
      
      





General programming



Generic programming is the form in which we plug in patterns known as generics, which are not really the true source code, but are compiled by the compiler to convert them to source code. Let's try to understand the patterns in a simple way. Think of patterns in programming as a form. We create a form in which important details of the template are left blank and need to be filled in later during compilation. Then, when we need to create something from this template, we simply specify the details, for example, type.



 template<typename T> class MyContainer { // Container that deals with an arbitrary type T }; void main() { // Make MyContainer take just ints. MyContainer<int> intContainer; }
      
      





The above snippet is written in C ++. The template is not provided with a type, but it is provided when MyContainer is initialized. We can also specify other types, such as float



, double



, etc., according to our needs. Generalized templates are useful when running algorithms on a set of data of several types.



Exceptions



An exception indicates a reasonable condition that the application might want to intercept. Through exceptions, we can resolve situations in which the program may not work. A checked exception does not lead to a complete stop of execution; it can be intercepted and processed. Go has no exceptions; it only has errors like interfaces and built-in errors. The key difference between errors and exceptions is that they indicate a serious problem and should be resolved immediately, so Go programming becomes more stringent. Errors in Go need to be checked explicitly as they occur.



Macros



Macros are macro commands. This is a way to minimize repetitive programming tasks by defining a predefined output for a given set of inputs. For example, if we want to get the square of a number in C, we can simply write x * x



, where x



is a variable, but we can also define a macro that returns the square of the number every time we need it. Macros are not functions. Macros are not available in Go.



 #define square(x) ((x) * (x)) int main() { int four = square(2); // same as 2 * 2 return 0; }
      
      





Feature Annotations



Annotations are a way to associate metadata with function parameters. In Python, annotations are syntactically supported and are completely optional. Let's look at a small example to describe annotations in Python.



 def foo(a: int, b: 'description', c: float) -> float: print(a+b+c) foo(1, 3, 2) // prints 6.0 foo('Hello ', , 'World!') // prints Hello World!
      
      





In the above code, parameters a



, b



and c



annotated with some metadata. a



and c



annotated c



int



and float



types, while b



provided with a string description. foo



print specific output, despite the type of arguments mentioned in the annotations.



Local stream storage



Local stream storage is a computer programming method that uses static or global memory localized to a stream. This is a static area where data is copied for each stream in the program. When multiple streams use the same static data for the same task, they can copy them from the local stream storage, rather than store them on their own.



Conclusion



Go has focused on simplicity and elegance. It has fast, small, and simple syntax. Unlike other OOP languages, it has fewer concepts that should be deposited in the head. The creators of Go chose the simplicity of the language without adding multiplicative complexity to adjacent parts of the language. Consequently, Go does not have features that make the parser slower and larger. Simplicity is the key to good software.

NOTE. The code snippets in this article are copied from various articles on the Internet.
That's all.



Read the first part




All Articles