Many programming languages include redundant features. The development of language includes work on their exclusion.
There are many programming languages, and new ones keep appearing all the time. Are they better than those that already existed? Obviously, this question cannot be answered until a clear definition is given of what is “better” with regard to programming languages.
If you look at historical trends, you will notice one of the ways to make a better programming language - to identify some redundant opportunity in an existing language and design a new language without it.
')
“Perfection is achieved not when there is nothing to add, but when there is nothing to remove”
Antoine de Saint-Exupery
In this article, you will see several examples of the capabilities of various programming languages that are already recognized as redundant and several others that have the same features and may someday be assigned to the same group.
Unlimited number of ways to shoot yourself in the foot
When the first computers were created, programs for them had to be written in machine codes or assembly language. In machine codes, you can express absolutely everything that a processor is capable of performing, since machine codes strictly correspond to the set of processor instructions. In machine codes, you can write correct programs, but you can also write an infinite number of incorrect programs, including those that will hang, fall, or incorrectly use the hardware on which they work.
Today, you are likely to write code in some high-level programming language, but even with it, you will agree, it’s not so easy to make things run without errors. For each correct program, there are many of its incorrect options.
With the use of machine codes, you have an unlimited number of ways to create a unique incorrect program. You can execute any command of the processor at any time. The set of valid command sequences is only a small subset of the set of all possible instruction sequences.
The first programmers quickly discovered that the writing of programs in machine codes is highly error-prone, and, in addition, the code is long and difficult to read. One way to solve the problem was to create an assembly language. But in fact, this did not help much: assembly language programs were a little more human-readable, but they only repeated one-to-one machine instructions, which means that the set of potentially incorrect programs that could be written remained the same.
High level languages
After some period of anguish with machine codes and assembler, programmers came up with high-level programming languages. The first such languages are not very much used today, but one of the examples of these "low-level" high-level languages, which is still in use, is C.
In C, you can write almost any valid program. There is still a car and a small cart to write an incorrect program that can, for example, fall. But since the language is a kind of abstraction over machine code, there are some sets of machine commands that we cannot express in such a language. Most of them are non-valid programs, which means the abstraction that cuts them off is beneficial.
Note what happened: the transition from machine code to high-level languages has removed some of the features. In machine codes, you could write anything, in the high-level language you can write not everything. We put up with it, because the advantages of the approach outweigh its disadvantages.
Goto
In 1968, Edsgar Dijkstra published his famous work on the harm of the goto operator. In it, he suggested that the very concept of using the goto operator is flawed, and programs would be much better without goto. This spawned a dispute that spanned decades, but today we have come to understand that Dijkstra was right. Many popular programming languages today do not have a goto operator (for example, Java or Javascript).
Since goto was an absolutely unnecessary operator, throwing it out of a language does not reduce the number of valid programs that you can write in that language. But it reduces the number of invalid
Did you catch the pattern? Take away something unnecessary - and you get an improvement. This is nothing new - Robert C. Martin
spoke about this many years ago.
You cannot simply remove the first functions from the language - in this case, you may lose the opportunity to write some valid programs.
But you can remove some functions without harm to the language.
Exceptions
Today everyone agrees that errors should be handled by some exception handling mechanism. At least we agree that error codes alone are not enough. We need something more serious, but at the same time preserving the balance of utility and performance.
The problem with exceptions in our programming languages is that they are essentially
GOTO disguised . And we already found out that using GOTO is bad.
The best approach may be to use a
composite type that collects information about the success of executing a certain block of code, or errors in it.
Pointers
As noted by Robert C. Martin, in old programming languages like C and C ++, you can manipulate pointers, but as soon as you introduce the concepts of polymorphism, you no longer need clean pointers. There are no pointers in Java, there are no pointers in Javascript. In C # there are pointers, but they are needed only in rare cases, like direct calling WinApi-functions.
All of these languages have proven that you do not need pointers in order to pass something somewhere on the link. You can get rid of pointers.
Numeric Types
Most strongly typed programming languages allow you to choose between several numeric types: 16-bit integer, 32-bit integer, 32-bit unsigned integer, floating-point fractional, etc. It made sense in the 1950s, but it is rarely important today. We spend a lot of time on micro-optimization, like choosing the right numeric type, losing the big picture. As Douglas Crockford
said : “There is only one numeric type in Javascript, which is a great idea. The only pity is that this is the wrong numeric type. ”
With the resources of a modern computer, we can afford a programming language that gives exactly one numeric type. Such a language would be an excellent means to dispel all this chaos associated with a variety of numeric types.
Null pointers
Null pointers are one of the most misunderstood concepts in programming languages. There is nothing wrong with that some value can be set, but may be missing. This concept is in many programming languages. In Haskell it is called Maybe, in F # this option, in T-SQL it is null. What is common in all these languages is that this feature is optional. You can declare a value as “nullable”, but by default it is not.
However, due to Tony Hoare’s mistake, which
he himself recognized and valued at a billion dollars, there are null pointers in many languages: C, C ++, Java, C #. The problem is not in the concept of a “null pointer”, but that any pointer may be null by default, which makes it impossible to distinguish between cases in which null is the expected and valid value of the pointer and those situations when it is a defect.
Create a language without null pointers and you will never have to think about generating or handling access errors on a null pointer.
If Tony Hoar is right in his assessment of the damage from this bug of a billion dollars, then getting rid of the null pointer right now can save us all a lot of money in the future. Because of the existence of Turing-complete programming languages without null pointers (like the mentioned T-SQL, Haskell, and F #), we know that we can express any valid program without this concept, which means removing it will remove a huge amount of errors.
Change the values of variables
One of the central concepts in procedural, imperative, and object-oriented style is that you can change the value of a variable as your program runs. This is the reason why it is called "variable." This seems logical and intuitively correct, because the processor contains registers, and everything you do during the program is how you write data there, execute commands and read the results. This is also logical on the other hand: most of the programs are designed to somehow change the state of the outside world - write data to the database, send an email, display a picture on the screen, print a document, etc.
However, it turned out that changing the values of variables is a huge source of software errors. Imagine, for example, this line of C # code:
var r = this.mapper.Map(rendition);
Map — rendition ? — . — Map. , ? - ? . . # ( Java, Javascript) .
- , -, \ — . « isDirty ? ? - customerStatus?».
, :
, ( ) , .
, , goto. goto, . , , .
- C# Java - . — . ( ) — . .
, ?
.
, , - - , , . , - — - . .
. 20
. , . : , ( ), . — .
. , . , .
(, Java #) , . , . ,
SOLID , , - , , . —
. — , . —
#, Java.
. .
, , , . , « », — .
- - .NET Java, , , , . API , .
- — , . , — -.
, , . , - .
: -. - , .
, , — . — . C# Java .
, , : AtomEventStore
IXmlWritable:
public interface IXmlWritable
{
void WriteTo(XmlWriter xmlWriter, IContentSerializer serializer);
}
WriteTo IContentSerializer, :
public interface IContentSerializer
{
void Serialize(XmlWriter xmlWriter, object value);
XmlAtomContent Deserialize(XmlReader xmlReader);
}
, Deserialize() XmlAtomContent. XmlAtomContent? :
public class XmlAtomContent : IXmlWritable
, IXmlWritable — , , IXmlWritable !
, . F# (, -, OCaml) ! F# and rec, . — .
! — .
« »: Scott Wlaschin
C# F# , F# , C#.
Evelina Gabasova.
, , . — , , (, ), .
, , :
? , , - !