📜 ⬆️ ⬇️

Textbook on programming language D. Part 2

The second part of the translation is the D Programming Language Tutorial from Ali Çehreli . Most of the material is aimed at beginners, but since most of the audience already has a basic knowledge of programming, this material is removed under the name. This section covers the fundamental types, type properties, compilation basics, and imperative programming.



Other parts:

')
Base material

Compiler


Earlier, we saw that the most commonly used tools in D are a text editor and a compiler . D programs are written in text editors (for example, your CO).

When using compiled languages such as D, you need to understand the concept of compilation and the function of the compiler.

Machine codes


The brain of a computer is a microprocessor (or CPU, short for central processing unit ). Encoding is called specifying what exactly the CPU should do, and the instructions that are used in this are called machine codes .

Most CPU architectures use machine-specific codes. These machine instructions are determined by the constraints of the hardware during the design of the architecture. At the lowest level, these instructions are implemented as electrical signals. Since the simplicity of programming at this level is not the main goal, writing programs directly in machine CPU codes is a very difficult task.

These machine instructions are special numbers that represent the various operations supported by a particular CPU. For example, for an imaginary 8-bit CPU, the number 4 may represent a load operation, the number 5 is a save operation, and the number 6 is an operation of incrementing the value by one. Assuming that the first 3 bits on the left are the operation number and the 5 subsequent bits are the value used in this operation, the example program in the machine codes of this CPU may look like this:
Operation Value Meaning 100 11110 LOAD 11110 101 10100 STORE 10100 110 10100 INCREMENT 10100 000 00000 PAUSE 


Being so close to the hardware, machine codes are not suitable for representing high-level concepts such as playing cards or student records .

Programming languages


Programming languages ​​are designed to be an efficient way to program CPUs with the ability to represent high-level concepts. Programming languages ​​do not have to deal with hardware limitations; their main task is ease of use and expressiveness. Programming languages ​​are easier understood by people, they are closer to natural languages:
 if (a_card_has_been_played()) { display_the_card(); } 


However, programming languages ​​adhere to much stricter and more formal rules than any language spoken.

Compiled languages


In some programming languages, instructions must be compiled before becoming an executable program. Such languages ​​create fast-running programs, but the development process involves two basic steps: writing a program and compiling it.

In general, compiled languages ​​help in detecting errors even before a program starts to run.

D - compiled language.

Interpreted languages


Some programming languages ​​do not require compilation. Such languages ​​are called interpretable . The program can run directly from freshly printed source code. Some examples of interpreted languages ​​are: Python, Ruby and Perl. Since there is no compilation stage, program development for such languages ​​may be easier. On the other hand, since program instructions must be parsed for interpretation each time a program is launched, a program in such languages ​​is slower than their equivalents written in compiled languages.

In the general case for interpreted languages, many types of errors in the program cannot be detected until the moment they start execution.

Compiler


The purpose of the compiler is translation: it translates programs written in a programming language into machine code. This is a translation from the programmer's language to the CPU language. This translation is called compilation . Each compiler understands a particular programming language and is described as a compiler for that language, for example, “compiler for D”.

Compilation errors


Since the compiler compiles the program according to the rules of the language, it stops the compilation as soon as it reaches incorrect instructions. Invalid instructions - those that are out of the specifications of the language. Problems such as: mismatch brackets, missing semicolon, misspelled keyword, etc. - all cause compilation errors.

The compiler also generates compilation warnings when it sees a suspicious piece of code that may be disturbing, but not necessarily an error. However, warnings almost always indicate a real mistake or bad style, so the most common practice is to treat most or all warnings as errors.



Fundamental types


Earlier we found out that the brain of the computer is the CPU. Most program tasks are performed on the CPU, and the rest are distributed to other parts of the computer.

The smallest unit of data in a computer is called a bit , which can be 0 or 1.

Since a data type that can only contain values ​​of 0 or 1 would have very limited use, the CPU determines more data types that are combinations of more than one bit. For example, a byte contains 8 bits. The most productive data type is determined by the CPU bit rate: 32-bit CPU, 64-bit CPU, etc.

The types defined by the CPU are still not enough: they cannot describe high-level concepts like the name of a student or a playing card . D provides many useful data types, but even these types are not enough to describe many high-level concepts. Such concepts should be defined by the programmer as structures (struct) or classes (class), which we will see in the next chapters.

The fundamental types of D are very similar to the fundamental types of many other languages, as shown in the following table. The terms appearing in this table are explained below:
Type ofDefinitionInitial value
boolBoolean Truth / Falsefalse
byte8 bit signed0
ubyte8 bit unsigned0
short16 bit signed number0
ushort16 bit unsigned0
int32 bit cos number0
uint32 bit unsigned0
long64 bit signed0
ulong64 bit unsigned0
float32 bit floating point numberfloat.nan
double64 bit floating point numberdouble.nan
realthe largest floating point number supported by the equipmentreal.nan
ifloatimaginary part of a complex number for floatfloat.nan * 1.0i
idoubleimaginary part of a complex number for doubledouble.nan * 1.0i
irealimaginary part of a complex number for realreal.nan * 1.0i
cfloatcomplex floatfloat.nan + float.nan * 1.0i
cdoublecomplex double optiondouble.nan + double.nan * 1.0i
crealcomplex option realreal.nan + real.nan * 1.0i
charUTF-8 character (code point)0xFF
wcharUTF-16 character (code point)0xFFFF
dcharUTF-32 character (code point)0x0000FFFF


In the appendix to the above, the keyword void describes entities that do not have a type . The keywords cent and ucent are reserved for future use to represent signed and markless 128-bit values.

You can use int for most values, as long as there is no particular reason not to do this. Consider double for concepts that have a fractional part.

Explanations of the concepts presented in the table
Boolean : A boolean expression type that is true for true and false for false .

Signed type: A type that can take on negative and positive values. For example, byte can have values ​​from 0 to 255. The letter u at the beginning of the name of these types is taken from the word unsigned .

Floating-point number: A type can represent values ​​with a decimal fraction, as in 1.25. The accuracy of floating-point calculations directly depends on the number of bits in the type: the greater the number of bits, we obtain more accurate results.

Only floating point numbers can represent decimals; integer types (for example, int ) can hold only values ​​such as 1 and 2.

Complex types of numbers: These types can represent complex numbers from mathematics.

Imaginary Types of Numbers: These types can represent only the imaginary part of complex numbers. The letter i , which is in the initial value column, is the square root of -1 in math.

nan: An abbreviation of not a number, representing an incorrect floating point value .


Translator Comments
It may seem strange that floating-point numbers use NaN values ​​as initializers. The official explanation from the developers (although I do not agree with this position):

NaNs have an interesting property that in whatever operation they are used, the result is again NaN. Therefore, NaN will be distributed and will be the result of any calculation where it was used. This means that a suddenly appearing NaN is an unambiguous indicator that an uninitialized variable was used.

If 0.0 were used as the initial value, its consequences would have been easily overlooked at the output, so if the initialization was unintentional by default, the bug could go unnoticed.

It is not implied that the initializer should be a useful value by default, its purpose is to open the bugs. NaN is well suited for this role.

But, of course, can the compiler detect and generate an error about variables that have not been initialized? In most cases, it can, but not always, and the fact that it can depends on the complexity of the internal analysis of data streams. Therefore, the hope for this mechanism is an unbearable and unreliable solution.

Because of the implementation features of the CPU, NaN is missing for integers, so D instead uses 0. Zero value does not have such advantages for detecting errors as NaN has, but at least errors from unintended initialization will be repeatable and therefore more debugged.


Type Properties


In D, types have properties . To get the property value, you need to write the property name after the type through a dot. For example, the sizeof int property is called like this: int.sizeof . This chapter covers only the following four attributes:

The program that prints these properties for int
import std. stdio ;

void main ( )
{
writeln ( "Type:" , int . stringof ) ;
writeln ( "Length in bytes:" , int . sizeof ) ;
writeln ( "Minimum value:" , int . min ) ;
writeln ( "Maximum value:" , int . max ) ;
}



Translator's notes
Some types have other properties, for example, float and double do not have the min property, the -float.max and - double.max are used instead , more .


size_t


You will also encounter the type size_t , whose name is decoded as “size type”. It is not a separate type, but a pseudonym of a non-type, which is enough to represent all possible addresses in memory. Therefore, this type depends on the system: uint on 32-bit, ulong for 64-bit systems, etc.

You can use the .stringof property to see what type size_t refers to on your system:
Code
import std. stdio ;

void main ( )
{
writeln ( size_t . stringof ) ;
}


The output on my system:
 ulong 



Exercises
Print out other types of properties.

Note : You cannot use the reserved types cent and ucent in any program; as an exception, void does not have the properties .min and .max .

Decision
import std. stdio ;

void main ( )
{
writeln ( "Type:" , short . stringof ) ;
writeln ( "Size in bytes:" , short . sizeof ) ;
writeln ( "Minimum value:" , short . min ) ;
writeln ( "Maximum Value:" , short . max ) ;

writeln ( ) ;

writeln ( "Type:" , ulong . stringof ) ;
writeln ( "Size in bytes:" , ulong . sizeof ) ;
writeln ( "Minimum value:" , ulong . min ) ;
writeln ( "Maximum Value:" , ulong . max ) ;
}




Base material

Assignment operator and calculation order



The first two stumbling blocks that await programming students are the assignment operator and the calculation order.

Assignment operator

You will find similar lines in almost all programs, in almost all programming languages:
 a = 10; 


The value of this line is “make the value of a equal to 10”. Similarly, the following line means “make the value of b equal to 20”:
 b = 20; 


Based on the above information, what can be said about the next line?
 a = b; 


Unfortunately, this line does not contain a comparison operator from mathematics, which, I suppose, everyone knows. The expression above does not mean “a equals b”! When we use the same logic as in the previous two lines, the expression above should mean “make the value of a equal to the value of b ”.

The well-known symbol = in mathematics has a completely different meaning in programming: “make the value on the left equals the value on the right side”.

Calculation Order

Program operations are performed step by step in a certain order. The previous three expressions in the program can be seen in the following order:
 a = 10; b = 20; a = b; 


The meaning of these lines together is: “make the value of a equal to 10, then make the value of b equal to 20, then make the value of a equal to the value of b ”. Accordingly, after performing these three operations, both values a and b will be equal to 20.

Exercise


Learn how the following three operations interchange the values ​​of a and b . If at the beginning their values ​​were equal to 1 and 2, respectively, then after performing the operations, the values ​​become equal to 2 and 1:
 c = a; a = b; b = c; 


Decision
The values ​​of a , b, and c are printed on the right side of each operation:
   → a 1, b 2, c  c = a → a 1, b 2, c 1 a = b → a 2, b 2, c 1 b = c → a 2, b 1, c 1 

At the end, the values ​​of a and b are swapped.

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


All Articles