📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Я изучал программирование 10 лет, чтобы сделать это видео

Winderton13:21

Transcription

[Music]

Let's take a couple of simple programs as an example to break down the entire computer science of interactivity. I've created a difficulty indicator for you: green means it's very simple, even if you don't know it yet, it's easy to learn. Yellow means it's more complex and you'll need to think. And red, here I will be very careful with my words because I might not know something myself.

So, about 100 years ago, a man named Alan Turing was born. He was one of the most influential mathematicians in the world who invented the so-called machine that, in theory, could execute any computational algorithm, or simply put, any program in today's world.

To understand this, for a programming language, whether it's Python, JavaScript, etc., to be what Turing called "Turing complete," it shouldn't need popular features like exception handling, a standard library, a bunch of data types, and other characteristics of modern programming languages. That is, hundreds of features that have been added to languages since their release.

To put it simply, for a language to be Turing complete, it must only have the following: the concept of a variable, reading and writing to it, conditional statements, and the concept of memory.

Fast forward to our time, in operating systems, this is handled by the virtual memory mechanism, which allows any process, or roughly speaking, your program, to think that all the memory in the system belongs only to it.

The closest programming language, in my humble opinion, is C. Compared to C++, Java, C#, Python, and others, it has a ratio of 1:10 or even less. It has no features except those that must be Turing complete, plus a few others like functions, data types, arrays with pointers, and a miniature standard library.

So, in essence, you should be able to write everything yourself. But these are the simplest programs.

In Python, for example, printing "Hello, World!" is easy to understand. The print function outputs to the standard output, which is the terminal, the phrase "Hello, World!" is quite simple. But understanding that there is a standard interpreter that reads your source code, checks for errors, and translates it into intermediate bytecode that runs on a virtual machine, which is essentially a simulator, is a bit more complex.

Inside it, the bytecode is translated into machine code that can run on your processor. Yes, this is a bit more complicated, and we are somewhat abstracted from it. We just press run, and everything works.

In Python, you can skip understanding why you don't need to import anything at all. That is, an empty file can call some standard built-in functions like print. But if you go down a level of abstraction, for example, to C, skipping even that is unlikely.

So, we have a high-level language, Python, and above it is Scratch, which, by the way, is also Turing complete. In theory, you could write an operating system for a Boeing with Scratch.

Anyway, like many languages, it has everything you need to write any programs. So initially, we study various variables for storing any values, the so-called control structures, which literally manage your program, loops, and so on.

Data structures for storing a set of data in one place, exception handling, which deals with moments after which the program continues to work, for example, if someone divides by zero, we throw an exception and move on.

Of course, we can create objects that interact with each other and a number of other features of programming languages that are our tools for solving problems.

We could talk for a long time about hundreds of such points that each of us studies when we use any programming language.

But if you need a specific reason, let me say a few words about it.

Currently, one of the most popular languages used in production by major companies like Netflix and Google is Python. Half of the web is written in it. It's an ideal language for beginners.

So, if you've decided to learn it, I recommend checking out the online school SkillFactory, specifically the Full Stack Developer course in Python. Here, both complete beginners and those who have already tried to do something can participate.

After 16 months of online training, in addition to the basics of the programming language, you will also learn backend development with all the necessary perks like the Django framework, REST API, databases, and everything you see on the screen that is actively used when you write a service or website.

But since this is Full Stack, you will also program the frontend part of the application, where there will be HTML, CSS, JavaScript, creating SPAs with React and Angular for contrast, working with developer tools, and everything else.

You will also learn the basics of the hype around DevOps, where you will discover deployment, containers like Docker, plus support from experienced mentors, nine practical projects, and one final project focused on social media oriented towards video content.

In short, become programmers! Finally, follow the link in the description and enter the promo code WINTER to make your training 45% cheaper.

When choosing a programming language, we choose the level of abstraction we will work at. But if you started with a high-level language and have more or less figured out how everything works, it makes sense to go and get acquainted with C, where everything that other languages like Java or Python do for you automatically, you have to do yourself.

The simplest example here is a dynamic array, one of the most popular data structures that solves 80% of your problems and is in the standard library of any modern language.

Here’s how one of its implementations looks in Python: elegant and simple.

And here’s how it looks, for example, in C.

When you program, you constantly use some data structures and algorithms depending on your tasks.

And of course, if you use some popular structure, like a dynamic array, and understand how it works, you should be able to write it from scratch.

Such tasks are usually solved by people preparing for interviews.

There is a common belief that you don't need to know how to write a binary search to be a good programmer. What do you think about this?

Personally, I believe you should just be able to solve problems. Writing a binary search is just one of them.

In life, we always want everything to improve everywhere. I believe this applies to faster computers, phones, cars, and getting to university or work faster, as well as completing tasks faster.

In programming, there are also certain metrics to ensure that programs run better and faster.

When writing data structures and algorithms, and indeed any programs, performance analysis techniques help, which is called Big O notation.

The essence is very simple. You have, say, a data structure, a dynamic array, that can work with data, for example, saving, deleting, searching for data, and so on.

And all you need to know is whether your program is slow or fast in terms of memory or time usage.

I also want to point out that the more you understand how everything works at a lower level, the more efficient code you can write.

The simplest optimization examples that the compiler does for you include loop unrolling, which is eliminating loops, dead code elimination, where the code you wrote is ignored by the compiler, constant folding, and constant propagation, which is evaluating some expression during compilation rather than at runtime.

Popular inlining is done to avoid function calls, and so on.

All of this relates to the compilation stage of the program, but there are also other optimizations, like linking or profiling.

The compiler, linker, and profiler are part of the standard set of tools you use when writing a program, say, in C++.

This is called a toolchain, a chain of tools, and understanding how to use these tools helps you write code at least.

Yes, I understand that I sound like a geek right now, but why are we even here?

Let's put it this way: if you want a video where we write our own minimal programming language, give me 10 likes, and I'll drop a 5-hour video where we write everything from scratch.

Well, dialogues are all about this. You condemn yourself to understand everything that happens at the level of your toolchain, then at the operating system level, and of course, at the hardware level, plus the hardware for which you are writing.

And look, how do you feel about side quests in games? Like, you play the main storyline in any game, but you can also complete some side tasks.

So, a small side quest or subway of this video is the story of the creation of the OpenCore bootloader for Hackintosh users.

To give you an idea, the main developer is only 25 years old. He writes operating systems for airplanes at work and, as a side project, creates this OpenCore bootloader with open-source code, which allows us to run and use macOS on almost any hardware.

Before that, there was Clover, which was written by a 60-year-old programmer, but this guy surpassed him.

I mean, to acquire such skills in creating software, you need to understand everything, which almost immediately provokes you to understand all of this.

I myself have installed various hardware several times just for testing and learning about operating systems and hardware. I recommend trying it; it's more fun than you might believe.

So, we are gradually descending down the abstraction canyon, and in a couple of minutes, we will almost reach the depths of despair.

But before that, a little about the OS.

These two guys invented everything 50 years ago, and it was all meant to be a low-level system programming language inside Unix.

Unix is a family of operating systems from which macOS, Linux, and Android eventually emerged.

The syntax and capabilities of the language are designed in such a way that it assumes you understand how your computer works at a fundamental level.

When we say "computer," we usually mean the processor and memory, plus output. This is the foundation of every computer and is called the von Neumann architecture.

And of course, unlike Python, which is an interpreted language, C is a compiled language.

When you run code, it is translated into bytecode, and then compiled into machine code once for specific hardware.

At each program launch, there is no recompilation.

Probably the most hyped thing that exists and distinguishes it from other languages is manual memory management.

The most accessible technical analogy between C and, say, Python is the difference between OpenGL and Vulkan.

These are graphics APIs that allow us to see images on monitors. The difference lies in the fact that with OpenGL, we don't manage memory; it does it automatically, allocating and deallocating memory.

The complexity of Vulkan, as you might have guessed, is that everything must be done manually, just like everything else.

So, it's easier to start learning graphics programming with OpenGL.

When you start writing in C, you get acquainted with memory from all its sides.

What you hear most often are the stack, heap, and so on.

These are memory segments that every program has, and when you launch an operating system, it creates a process for you that contains all these segments for storing different data.

The heap is for dynamic memory storage, the stack is for local variables of functions, and so on.

There is also a segment for storing constant data, both initialized and uninitialized, and segments for storing your program's code, and so on.

So, it results in a certain memory layout.

I talked about this in more detail in this video.

Let's take an example of memory management in C.

A function rarely returns a pointer to a number of bytes somewhere in memory that we request, and then we free that memory using free.

But we don't tell free how many bytes to free; it knows that because when we allocate memory, we write the size in the first byte, and then it retrieves it from there.

A few years ago, I had a stream creating a malloc, and there we also wrote the size in the first byte.

By the way, all useful links about what I'm talking about and a more detailed breakdown of everything we discuss will be in the description.

So, you probably see the pattern: we should think not just about how to write code that does something, but about how to write code understanding what happens underneath.

How deep can we go? Below C is assembly language.

I constantly want to make a video about why assembly is needed in 2023.

If in C there are at least functions, in assembly, there are none.

I’m not even talking about features like pointer arithmetic or just expressions.

So, this is code in Python for an array where we access its elements.

It's simple.

This is the same code in C, where a pointer to the array in memory appears.

And of course, pointer arithmetic, where we add a number to the pointer, and it starts pointing to that element of the array.

And of course, the darkness of assembly has nothing of this, but we gradually get rid of all these features of C until we reach the minimal syntax that will relate one-to-one to assembly mnemonics, which in turn have a one-to-one correspondence with machine instructions.

So, below is only the abyss.

First, we eliminate pointer arithmetic, then we get rid of the concept of expressions, and it looks something like this in assembly: a shift by this number from adding the pointer with this variable.

So, we have come to assembly language.

Specifically, this example is x86 assembly, roughly for desktops and consoles.

ARM is for phones; its characteristics are much greater, but this is just the most popular one you will likely work with.

In your resume, you write in Python, studying all the high-level basics of how to write programs.

Then, any high-level language is based on C, where you manage memory manually.

Memory management is essentially moving through it by adding addresses in memory, pointer arithmetic.

Code in C is compiled into assembly, going through several stages, including optimizations.

The assembler assembles the code into an executable file, say, on Windows, with all the memory sectors like stack and heap that can be launched by the operating system.

How this code will work at a lower level, that is, at the hardware level, depends on the microarchitecture of your processor or what level of abstraction you are currently at and what level you would like to be.

Wishing everyone the best!