8,99 €
Learn Programming Language Concepts instead of just Programming Languages! It will help you to think in a more powerful, abstract but solution-oriented way about the problems you have to solve every day as a Software Developer. Knowing Concepts is much more powerful than knowing a specific Programming Language. Being able to identify a Concept in a Programming Language not only helps writing code in a more powerful style, it also makes you think about a given problem in a more abstract way. Additionally, it aids you in recognizing that very same Concept in other Languages that you might once use, and thus helps you when learning new Languages. Modern Programming Languages keep coming up with more and more new Concepts that make writing software more efficient and less error prone. However, most of us still try to solve all tasks in that verbose style we've known for ages. This results in too much (boilerplate) work that takes too long to write and introduces too many nasty bugs. But we're doing all that although there are so many helpful Programming Language Concepts around these days. Smart people have worked out these tools for us, so we should benefit from them, in order to make our lives as Software Developers easier, our software better in terms of quality and maintainability and thus make our customers happier. This book tries to shed light on modern Programming Language Concepts. It won't teach you a specific Language. Instead it makes the Concepts clear that the powerful Programming Languages of today lay their foundation on and what these are beneficial for. Many code examples in arbitrary Programming Languages as well as many illustrating figures help to get the ideas across. Covered topics are for example: Closures, Currying, Algebraic Datatypes, Type Classes, Immutability, Macros, Monads, Coroutines, Continuations, Lazy Evaluation, Destructuring, plus a chapter about basics that lays the foundation for being able to understand advanced topics.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Veröffentlichungsjahr: 2018
Programming Language Concepts Improving your Software Development Skills Oliver Wegner Email: [email protected] Web: http://lambda-startup.com Twitter: @ow1976 Unabridged second edition April 2018
For software developers, programming software is usually more than just a job. It is something interesting that challenges your intellect, that lets you improve your skills continuously. Something that you can use to produce useful things with, to solve problems, to simplify tasks, to make other people’s lives easier. It lets you express your creativity, ideas and visions.
For many it is something that you could call a passion.
From an educational point of view, most software developers start off with learning a common programming language like Java for example. The first time you learn a programming language it seems to be pretty difficult to get your head around it and really understand what you are doing.
This difficulty however doesn’t arise from learning some syntax that is specific to the language. Instead, the difficult part is grasping the abstract concepts that lay the foundation for that language. It is not so hard to understand the if construct of a language. But if you’ve never heard about the concept called object orientation before, you can have a quite hard time to get your head around that.
That is why learning a new programming languages becomes easier the more languages you’ve known before - you’ve probably seen most concepts that are also present in that new language you want to learn. Most abstract ideas behind this language are already familiar to you.
However, there are programming languages that comply to an entirely different paradigm than the ones you’ve seen before. Learning such a language will feel much more difficult again, if you’ve never seen a language that follows the same paradigm. Learning a functional language may be rather difficult if you’ve exclusively worked in imperative languages before. That is because functional languages often focus on quite different concepts than imperative languages do - learning these new concepts makes it difficult.
My experience is that it’s usually easy to find literature for when you want to learn a specific programming language. However, as I feel that learning the concepts behind a language is the real difficult part and the fact that there is not much literature treating language concepts as concepts, independently of a specific implementation, I decided to write this book in order to fill this gap a tiny bit.
I hope this book will help you understanding the concepts on their own and identify a concept when coming across it in another language. This in turn is beneficial because it helps you think about problems in a more general way. You don’t think about how to solve problem x in language y, but you think about which concepts would be of greatest use to solve that problem.
Naming and explaining these general concepts will also let you identify them in the language you are currently working in - a process that might otherwise take a very long time, because you won’t be able to identify a general concept as such as long as you’ve not come across another languages that also uses this concept.
So in this book I want to describe and explain several basic, but also not-so-basic programming language features that I consider important. Important means that these features help you write code that tends to be
concise. You have to write less code for a certain functionality. This also includes writing less boilerplate code (i.e. code that does not express your business logic, but just has to be there for “preparing” the program for your business logic). Conciseness is a desirable feature, because less code for the same functionality means you have less code to maintain, thus fewer opportunities to introduce bugs and have simply less to type for reaching your goal.
reusable. Code is modular, or at least not tied too much to it’s surrounding code or environment, so you are able to take it and place it into another program for reusing it there.
free of bugs, e.g. managing state and concurrency in a clear and predictable way that avoids race conditions and other sources of erroneous program behavior.
Software developers and other people who have to decide which specific programming language to use are facing a problem today: There are like a zillion different programming languages, all slightly or vastly differing from each other. So it is a major problem to choose one for your project and use case. For taking a decision that has chance to make the project successful, one needs to understand the fundamental differences between different programming languages, in order to be able to finally assess whether concept A in language X is more valuable for oneself (and especially the current task at hand) than concept B in language Y. And is there a language that maybe features both A & B?
This decision even grows in importance when you consider that you cannot simply revert the decision, once you got going and are way into the project. This is because it’s a huge deal of non-trivial work to transform a piece of software from one programming language to another.
Besides making a good choice regarding the programming language, you’d often also be well advised not to build one giant monolithic block of software, but to think cleverly about at which interfaces you can separate that software into smaller pieces. This way, you maintain options to write one functionality of the software in one language and another in a different language, should it seem necessary or beneficial.
This book does not aim to teach you a specific programming language. Instead, I’ll try to explain concepts, not languages. Implementations in programming languages are just the manifestations of these concepts and I’ll try to make clear what the specific concept is about, so you can identify it when you see it in a language that you come across in the future.
However, I will present code examples to make the specific concept clear. I think learning by example is often very powerful and much easier than just trying to explain in words what a topic is all about.
This book does not try to explain every detail and aspect of each concept, as this would bloat the extent of this book and distract from the goal I’m aiming at. I will rather try to explain just enough to get the basic idea of a concept across and make you understand the benefit that it provides. In case you want to really delve into a certain topic, I recommend searching the internet, as for example Wikipedia and StackOverflow are valuable resources to learn about most concepts in detail.
I am someone who’s always been interested in computers. It’s all started with a Commodore C64 back in the 80’s. After playing around with it a bit, I discovered programming quite early and started writing my first programs in BASIC.
Around 1990, I left the C64 and went over to the Commodore Amiga 500. On this machine, I not only continued programming in BASIC, but also got my feet wet in Assembler and C programming.
About 5 years later I switched over to a Pentium 75, my first IBM-compatible PC. That’s also the time in which I discovered Linux, a new and novel operating system back then, that I instantly liked.
In the late 90’s and early 2000’s, I’ve studied Computer Science (although without graduating) and have since then worked not only self employed, but also as DevOp and Software Developer in several jobs. I’ve come across quite a few programming languages and have even written a compiler myself, though mainly for fun and to learn about compiler internals, as that’s a topic that greatly attracts my interest.
My conviction is that today, programming languages too often have a divisive effect on people. Often enough, people seem to look at programming languages with an almost religious passion. That’s fine, but I am convinced that not the programming languages are important, but the concepts they provide (or don’t provide) are.
Although those programming languages are called General purpose programming languages, I think that not every language is as well suited for a problem as others. So it’s a good idea to think about which language provides more concepts that may be of help for a certain task than another language.
In my opinion, knowing those concepts in general is more important than knowing a specific programming language in detail. Knowing concepts allows you to asses which one of those is most important for the task you will have to solve and thus you can choose the best fitting tool for the work to be done.
You can contact me via [email protected]. Feedback is greatly appreciated. Also have a look at my blog at lambda-startup.com and follow me on Twitter: ow1976 .
Thanks go to David Kamphausen for helping a great deal with spotting errors and suggesting improvements.
Thanks go to Dirk Schlütter for designing the cover page.
In this chapter I’ll cover the basics that, well all programming languages lay their foundations on, in one form or another. However, each of these concepts often exists in several variations, so that the creator of a programming language has to choose between one of them. Sometimes it is possible to include multiple variations of a concept into a language.
If you find that you are already familiar with these basic topics, feel free to skip straight ahead to the Advanced Programming Language Concepts chapter.
Symbols are what most software developers might call variables. Symbols are names that are given to individual entities in your source code to identify them within their scope (see Scope), so you are able to reference the very same entity in multiple locations.
This allows your program to read the value that the symbol is bound to at a specific time, for example in order to make some computations in which this value is involved. Or you might want to print the value to the screen.
A value however is not the same as a symbol. A symbol refers to a value and a value can be referred to by one or more symbols. You can imagine a value to be stored in the memory of the computer system at a certain memory address, and a symbol is a reference to that memory address.
In the figure below, you can see two symbols x and y and three values 123, 456 and abc. Symbol x refers to the value 456 and symbol y refers to the value abc, illustrated by the arrows.
Relationship between symbols and values
The next figure shows how both symbols x and y refer to the same value 456. Some programming languages (for example C) let you change a symbol regarding the value it refers to (i.e. let you change the arrow in the figure to point to a different value).
It is also not uncommon that multiple symbols refer to the same value (e.g. an object).
More than one symbol referring to the same value
This in turn implies that when you change the actual value within the memory address the original value is stored in, that change is relevant for all symbol that refer to this value / memory address.
Note however, that not all programming languages offer the features of changing the value itself. Some languages require values to be persistent / immutable because that reduces the danger of introducing bugs into the code (see e.g. Immutability). Some languages let you assign a new value to an existing symbol, but that does not overwrite the actual value the symbol references, but it rather rebinds the symbol, so that it points to a different memory location and thus a different value afterwards.
So for many upcoming topics it will be essential to be aware of the distinctness of a symbol (or variable) and its value.
Depending on the language you’re using you might or might not be aware of this already. Java programmers for example will probably already have developed this awareness. In Java, it’s important to know that passing a primitive into a function actually passes the value itself, while passing an object into a function will just pass a reference to that object. Thus changes to the value of the argument from within that function will either be visible (for objects and other references) or invisible (for primitive values) to the caller.
If you’ve done at least some programming, you will for certain have learned about data types already. Primitive types usually consist of integers, characters, strings, floats and a few more.
Usually, a language also offers some complex data types that can contain multiple symbols, for example arrays, maps, lists and sets (Maps often have various names in different languages, e.g. dictionaries, hashes, associative arrays…).
We’ll see two different ways of how data types are being handled in section Typing.
As you are probably aware, one symbol does not always globally refer to one single value. Consider the following code for example:
It is obvious that the symbol n here inside the function inc does not refer to the value of 123, since n is a parameter to the function inc. You can say that n has a different binding inside the function inc than it has outside of it. Another phrasing is that the definition of parameter n in the parameter list of function inc creates a new binding for symbol n (As you might already guess, introducing new bindings is exactly what is called scope. I’ll talk about scope in a bit.).
A high level programming language usually has a type system, which means different types of data can be distinguished from another. You are probably aware of the fact that there are values of type string and other values of type integer and so on.
In some languages (called statically typed languages), the type is bound to the symbol, while in other languages (called dynamically typed languages) the type is bound to the value. This is being shown in the figure below.
static (type is bound to symbol) and dynamic (type is bound to value) typing
A programming language is statically typed when the type of data that a symbol refers to is known at compile time. This mostly means you will have to declare the type of variables / symbols in your source code, like in C or Java. More modern programming languages (Haskell and Scala for example) offer something called type inference (see Type inference), which actually allows you to omit the type declarations in many places of your code, because the compiler is smart enough to figure out the type a symbol must have when looking at other declarations that are dependent on each other. Nevertheless, these languages are still considered statically typed, as types are still bound to symbols, not values.
