Have those programming languages ​​​​that intend to replace C++ succeeded?

[CSDN editor’s note] Speaking of the C++ language, programmers should be very familiar with it. It contains all the functions provided by the C language. In applications, C++ is everywhere. Recently, Lucian Radu Teodorescu, a software engineer at Garmin, summarized the current technical state of the C++ successor language in an article.

Original link: https://ift.tt/3FNljfL

Author | Lucian Radu Teodorescu

Translator |

Produced | CSDN (ID: CSDNnews)

In 2022 there are many languages ​​that can compete with C++. At this year’s CPP North C++ conference, Google announced a new programming language Carbon, saying it will be the “successor of C++.”

Regarding this incident, foreign media and developers also asked Bjarne Stroustrup, the father of C++, for his opinion. He said: “There are always new languages ​​trying to become the successor of C++ over the years. Experiment. But Carbon is too new and not well-specified for me to really make meaningful technical comments. And it’s often hard to offer an alternative to C++ without developing entirely new language rules, libraries, and management schemes.”

After the language was issued, a large number of netizens came to watch, with support and opposition.

Lucian Radu Teodorescu, a software engineer at Garmin, reported on the current technical state of the C++ successor language in an article recently.

C++ is a special programming language and one of the most used programming languages, but it is also one of the most criticized. According to the TIOBE index, C++ has been the top 4 programming language (using 12-month average) for 30 years and has also successfully won the title of programming language of the year in 2022 .

See the chart below for language trends over the past 20 years (TIOBE Programming Community Index October 2022).

For a programming language that has been around for almost 40 years, it is indeed a great achievement to regularly appear in the list of top programming languages. While it is popular, criticisms of C++ have continued one after another. For example, the father of Liunx directly said that C++ is a bad language. Most people are complaining that this language is too big and too complicated, some functions should be killed, there are too many functions, and conversely, some functions are not enough. To generalize, C++ can be seen as a random collection of features without a clear coherent story.

In defense of the language, Bjarne Stroustrup argues that “in C++ there is a smaller, cleaner language that is trying to move away”. The phrase is still widely used today, 28 years later. While this statement is meant to defend C++, it is also an implicit criticism if you analyze it carefully. C++ still hasn’t been the smaller, cleaner language people had hoped for. It could just mean that this smaller and cleaner language is just a mirage.

A programming language intended to replace C++

So the question is, how can we get a better programming language? Is it simpler and cleaner than today’s C++ and occupies the same space as C++ (systems programming language)? What would a C++ successor language look like?

Although there have been some attempts in the past, it is still rare like 2022, when 3 successor languages ​​​​are announced in the C++ keynote speech at once.

First, there’s Val announced at C++ Now by Dave Abrahams and Dimitri Racordon. The core idea of ​​Val is that we can build safe and efficient programs using mutable value semantics.

Two months later, at CppNorth, Chandler Carruth announced the Carbon language. The Carbon language attempts to address several aspects of C++: technical debt accumulated over decades, prioritizing backwards compatibility, and the evolutionary process of C++.

Two months later, at CppCon, Herb Sutter announced CppFront, as a possible successor to C++. His main goal is to “evolve C++ itself forward, and double the evolution of C++”, preventing users from migrating to other languages. The stated goal is to make C++ 50 times safer and 10 times easier.

The author of this article, Lucian Radu Teodorescu, attempts to provide a critical perspective on the three languages. He explains: “This is not to say that they cannot be successors to C++; quite the contrary, I am trying to list the problems that these languages ​​need to solve before they hope to take the place of C++. I do have some personal biases, but I We will try our best to analyze it objectively.”

early replacement

The D programming language was created by Walter Bright and appeared in 2001; in 2007, Andrei Alexandrescu joined the design and development work. This language should have learned from C++’s mistakes and become its successor. It promises the same level of efficiency, but adds a ton of new functionality and simplifies some of the more complex parts of C++. D’s home page advertises D as a language that can “write fast, read fast, run fast”.

D has attracted some commercial users, but it has arguably not achieved the status of a significant programming language. Andrei is one of the author’s longtime heroes, and has considerable respect for Walter, but sees D primarily as a large collection of language features, loosely tied together. In my opinion, the language lacks a clear foundation on which to make all the features cohesive.

The Go programming language was launched by Google in 2009; version 1.0 was released in 2012. The language’s goal is to let programmers “build fast, reliable, and efficient software at scale.” The designers of the Go language didn’t like C++, so Go seems more like an evolution of C than C++. Go only added generics in 2022, and still lacks widely used features like exception handling.

While Go is arguably a successful programming language, its success is primarily in the cloud computing business. Despite its relative success, it cannot be called a successor to C++.

Rust is a programming language developed by Mozilla, announced in 2010, and the first version was released in 2015. Rust focuses on reliable (memory and thread safe) and efficient software. The Rust language model is built around a so-called borrow checker, which keeps track of the lifetime of all objects; thus, it can detect safety errors at compile time, without using the garbage collector.

Rust, while not as popular as Go, seems to be considered a good alternative to C++. The problem is that there is no clear/clean/common way of interfacing between Rust and C++, and this makes for a sudden migration for C++ programmers who want to switch to Rust.

Val

Val’s goal positioning for himself is:

  • quick definition

  • secure by default

  • Simple

  • Interoperable with C++

Val targets the C++, Rust, and Swift language audiences with these goals. Its goal is to achieve the performance of C++, but with safety in a simpler way than Rust. In terms of performance, Val aims to reduce the number of object copies and memory allocations required to write secure software. In terms of security, all structures in Val are guaranteed to be safe unless the user explicitly requests additional controls (marking a part of the code as unsafe). The language’s simplicity comes primarily from its strong influence on Swift, which is generally considered an easy-to-use language.

Many programming languages ​​don’t necessarily have a core idea that runs through all of their features, like a catalyst for the language; this can give the impression that the languages ​​lack coherence. That can’t be said to be Val’s problem. What makes the language stand out is that it has a model that eliminates safety concerns programmatically: it’s called Mutable Value Semantics. But, before that, let’s discuss the main problem it solves.

C++ is inherently unsafe

It all started with the observation that reference semantics can lead to unsafe programs in the presence of mutations. Because reference semantics allow the creation of complex dependency graphs, mutations are not guaranteed to preserve safety across the graph. For example, if a function operates on two objects and mutates one of them, there is no guarantee that the other object will not be mutated in a completely unexpected way. This creates problems in both single-threaded and multi-threaded environments. Furthermore, programmers have no systematic way to verify the consequences of mutations without in-depth inspection of all potentially affected code. This simply breaks the core idea of ​​structured programming.

Take the following C++ code snippet as an example:

 void append_vec(vector<int>& dest, const vector<int>& src) { for ( auto x: src ) dest. dest.push_back(x); }

Ignoring inefficiencies in execution, this code has a serious security problem. Also, the problem isn’t easy to spot if you just look at this code; you also have to look at the surrounding code. Undefined behavior results if a caller of this function supplies the same vector as the source and destination arguments.

To ensure that functions like this have correct semantics, a guarantee of independence is needed: programmers need to ensure that the objects they interact with (and write to at least one of them) are not the same. This cannot be properly enforced in the language; thus, in unsafe territory.

The problem here is more complex than it appears. If both arguments to a function are references (that is, we’re not changing anything in them), then there’s no problem. The problem only arises when we have mutation.const.

Swift solves this problem by using a copy-on-write technique, but this can lead to inefficiencies.

Rust solves this problem by keeping track of the lifetime of objects. This puts a burden on the programmer and adds unnecessary constraints to the program.

mutable value semantics

Functional programming languages ​​avoid the above problems by prohibiting mutation. It is possible to have multiple references to multiple objects because nobody can change those objects. This feels unnatural to many programmers and is inefficient for countless algorithms.

Val solves this problem in a completely different way: it adds restrictions on references and ensures that no one can read an object while others can change it.

Val recognizes the importance of whole/part relationships. These relationships can only form a tree, not a cyclic graph. If you want to modify an object on this tree, you can immediately know the impact of this change, that is, all other objects that may be affected by this mutation. It allows programmers to reason about which objects are safe to pass into a function as reads and writes.

Finally, following this logic, it is safe to add references to represent whole/part relationships.

In the Val model, mutations are not forbidden, but each time an object is mutated, the compiler can figure out which objects are safe to read and which objects are safe to write at the same time. Security can be guaranteed by construction.

Eliminating arbitrary references between objects and focusing on whole/part relationships is what gives Val value semantics. However, since Val also allows mutation of values, this model can be called mutable value semantics.

scientific methods

At this point, the author thinks an important aspect: Val seems to follow a scientific method. It can be seen that the above content simply describes a computing model to ensure security. This is not just a claim about language safety made by the authors. They have a proof of security, within the constraints of the language.

The main creator of the language, Dimitri Racordon, is actually a postdoctoral researcher. Dave Abrahams also seems like a kindred spirit. Together, Dave and Sean Parent have reorganized Adobe’s STLabs. The influence of Alex Stepanov (creator of STL and former member of STLabs) on Dave and Sean’s research orientation can be seen.

There’s no guarantee that Val will be as successful as C++, but it’s possible to discover a reasonable solution to some of the fundamental problems of C++: clearly define the problem, then come up with a general and elegant solution.

use temporary references

Val simply states that using temporary references is not safe. This makes it unclear how to implement programs that require citations, rather than expressing whole/part relationships.

For example, implementing a doubly linked list requires references that cannot be modeled as whole/part relationships. It’s not clear how to implement a doubly linked list with mutable value semantics. As another example, consider a shared cache component in an application. By definition, such components need to be accessible by multiple parties and need to allow mutation. Again, it’s not clear how to do this in Val.

Perhaps the simple answer to these examples is that the user has to mark some code as unsafe. That might be okay; as users of the language, we just lack experience in how to deal with these situations. Val must provide good guidance for handling these situations.

C++ interoperability

As of this writing, Val has no explicit public plans on how to handle interoperability with C++, it has only announced its intentions. In order to be the successor language to C++, Val needs to solve this problem. Also, the problem doesn’t seem to be easy.

The first thing to note is that according to its description, Val was mostly inspired by Swift. This means that the gap between Val and C++ is not small (the gap between Carbon and Cpp2 on the one hand, and the gap between C++ on the other). Closing this gap may require considerable effort.

The second hurdle is the limitations imposed by the mutable value semantics system. C++ inherently contains a large number of temporary references. This means that C++ code will be considered to contain countless unsafe operations in Val. In the author’s opinion, almost all C++ operations should be marked as unsafe in Val. This seems to increase the interoperability gap.

Note that the author is not saying that Val cannot interoperate properly with C++. Just wanted to state that achieving this might not be an easy endeavor.

Carbon

Carbon was launched at CppNorth 2022 and intends to become the successor language of C++. Carbon is backed by Google (and, according to Chandler, Adobe). Also, an interesting fact is that Google was absent at CppCon 2022; perhaps this is a sign that Google is considering abandoning C++.

In his speech, Chandler listed the current problems with C++.

  • massive technical debt

  • C++ prioritizes backwards compatibility over language evolution; this also hinders fixing technical debt

  • The ISO language development process is not optimized for the actual needs of C++ development.

The solution to these problems, according to Chandler, is to start thinking about C++’s successor language. Similar to how C++ was created as the successor of C, Swift was created as the successor of ObjectiveC, and Kotlin was created as the successor of Java, you need to find a successor language for C++.

In order to create a C++ successor language, it needs to build within the existing ecosystem, provide two-way interoperability, and ensure that tools are in place to facilitate migration and learning. And these are actually the goals of the newly announced Carbon language.

Compared to C++, Carbon does not seem to have a hallmark feature. It’s like a C++ cleanup project. In his talk, Chandler demonstrates cleaner syntax, cleaner pointer semantics, better wrapping, better default values ​​for public/private members, explicit parameters, inheritance cleanup, API extension points, and C++0x-style generic type. All of these features exist in other programming languages ​​in one way or another.

Carbon can be seen as C++ with better defaults, which is a good thing. People see a familiar language as better/easier. Carbon’s learning curve can be smooth, and the transition from C++ to Carbon doesn’t need to jump through too many hoops.

But, on the other hand, how is this different from D? D also tries to be the successor to C++ by learning from C++’s mistakes and cleaning up its rough edges. What makes the Carbon language internally consistent, rather than making it feel like a bunch of unrelated features?

If all the defaults make sense today from an evolutionary perspective, what guarantees they will make sense in the next few decades? How can we prevent Carbon from accumulating technical debt? Part of the answer to this question is, as Chandler mentioned, to use tools to assist with migration. However, we all saw how painful it was to move from Python 2 to Python 3; maybe not everyone is convinced that tools can help with future problems.

These are questions the Carbon team needs to answer. The authors do not mean to say that these questions are difficult to answer, but they need to be answered.

Interoperability with C++ is difficult

Even if Carbon could be a C++ with better defaults, interoperability with C++ isn’t necessarily easy. Here are some points made by Sean Baxter:

  • No function overloading in Carbon

  • There is no exception handling in Carbon

  • There is no multiple inheritance in Carbon, but one can still use it in C++

  • Unlike C++, Carbon does not handle raw pointers

  • Carbon has no constructor

From these perspectives, it’s easy to see that interoperability with C++ will be a complex issue. Most likely, even if interoperability issues are fully resolved, moving from C++ to Carbon won’t be an easy transition for large software.

rise and fall of culture

Google is a company that firmly believes that culture is the driving force of software development. Chandler also expressed this in a quote from Peter Drucker in his keynote.

Culture eats strategy for breakfast, technology for lunch, product for dinner, and soon everything else too.

While corporate culture is indeed essential, just quoting Peter Drucker is not a recipe for success. The main problem is that it is difficult to measure culture and its influence. Chandler lays out several key points about Carbon’s culture (inclusiveness, community friendliness, etc.). While all of these points are good, they are not enough to define culture and make it work in a Carbon project. For example, Chandler doesn’t mention technical excellence, perseverance, the courage to try new things, or how to prioritize different (culturally-related) goals.

Lucian Radu Teodorescu said that at one of his previous companies, there was a mantra that was “we never let a project fail”. Is there a similar goal in the culture of Google and Project Carbon? People seem to see Google as a company that tries many products and shuts them down after a while. For example, pictured below, a tweet by Victor Zverovich, who used this perception to make a joke about Carbon. Considering that Chandler also announced that Google has a different team with the same goal, but after they started in Rust and moved to C++, this line of thinking might not be too far-fetched.

Lucian Radu Teodorescu said the culture is good and so is the point Chandler made. But convincing an engineer requires verifiable arguments.

governance model

One interesting thing about the Carbon announcement is the governance model. The goal of the Carbon project is to achieve a governance where no single corporation can determine the future of a language. Everyone can contribute to the development of the language by creating pull requests, but the more important the feature, the more analysis/argumentation is required.

For important features for which there is no consensus, there is a three-member Steering Committee (Chandler Carruth, Kate Gregory, Richard Smith) that reaches decisions. They don’t have the opportunity to contribute to the design; they just have to weigh the arguments presented to them and make a choice.

Interestingly, this model tries to emphasize a democratic process, which is somewhat similar to ISO’s goals. It’s just a different division of the parties involved, with clearer rules for what to do when there’s an impasse. If the people working on C++ standardization were also working on Carbon, it’s not clear that the process would be significantly better with Carbon.

While democratic methods are currently the best form of governance, we have recently seen a series of major political failures that may be directly related to the negative effects of democracy. It is worth mentioning that in ancient Greece, democracy was considered a poor form of governance.

Cpp2

CppFront is a project announced by Herb Sutter in his closing keynote at CppCon 2022. It’s a transcoder that converts “better C++”, i.e. Cpp2, to old C++. Although CppFront/Cpp2 was officially announced this year, Herb has been working on the project for about 7 years; every year, Herb presents a small part of Cpp2.

Herb wants to improve C++ (ie 10x), not make incremental changes (ie 10%). He wanted to make C++ the old goal of a simpler, cleaner language envisioned by Stroustrup 30 years ago. Interestingly, it takes the same approach that Stroustrup wanted to improve the C language: start a new language and translate the code into the previous language. So CppFront is a small transpiler that takes Cpp2 code (Herb’s new language) and outputs regular C++ code.

Herb also set some metrics that we can use to evaluate the success of this experiment. 50 times safer (that is, reduce 98% of CVE), 10 times simpler (reduce 90% of teaching guidance). Predefining metrics is a great strategy to be able to assess the success of experiments; I really like the idea.

Backward Compatibility and Interoperability

By giving up backward compatibility, Cpp2 can be simpler than C++. This ultimately allowed the language to remove features that were deemed harmful, and to revisit some design choices that proved to be suboptimal. By forgoing backwards compatibility, Cpp2 can finally resolve decades of accumulated technical debt in C++.

To be honest, prioritizing backwards compatibility over language development in C++ is not a solid example. Every time we add a major feature (e.g., concept, program, module, etc.) to the language, we actually create a new era in the language. New code can interact with old code, but old code cannot simply depend on new code written with new features. Although the C++ standard does not formally refer to the language era, there is an underlying era system in the language, determined by the release of new features.

Think of Cpp2 as a major new feature of C++. When it comes to interoperability and tools, things are a little more complicated, but the essence is the same. There is no good technical reason why legacy C++ cannot coexist with Cpp2 in the same application.

By design, Cpp2 is semantically close to C++; this makes interoperability easier. On the other hand, this also prevents Cpp2 from having completely different features from C++. For example, Cpp2 makes it difficult to use C++0x-style generics.

fix security issues

The goal of a 50-fold increase in security sounds impressive. If Cpp2 can achieve this goal, I believe that users of most languages ​​will be happy.

Let’s put this number in perspective to get a full picture of its impact. This means that 98% of C++ applications would not crash anymore if they were translated to Cpp2 (assuming the crashes are only caused by unsafe applications). In other words, 98% of C++ web applications will not have vulnerabilities (if there are no other non-C++ vulnerabilities). This will drastically reduce crashes and security breaches.

It seemed too good to be true. In fact, if we analyze in more detail, these numbers seem too high.

First of all, if you discuss security issues, you need to clearly know what security is. Security includes:

  • type safety

  • border security

  • Lifecycle Security

  • initialization security

  • object access security

  • thread safety

  • arithmetic safety

Herb mentioned the first 4 projects mentioned above in his keynote speech. However, not all aspects of these security programs are addressed. As a prime example, lifetime safety cannot be guaranteed when there is a raw pointer; simply checking the pointer is not enough. Nor is there any functionality to detect use-after-delete of pointer.null.

Cpp2, as described in the CppCon keynote, cannot detect the problem with this code:

 vec.push_back(vec.front());

Herb defines his security metrics to include the first four security components; it seems odd to deliberately ignore other types of security. Especially if the overlooked safety component is important.

Object access security refers to security rules that are affected by object access patterns. Generally speaking, this type of unsafe code can be transformed into type safety, boundary safety or lifetime safety. The rules for void iterators are good examples of this category.

Thread safety is a huge issue with C++, and Herb doesn’t mention it at all. In her 2021 C++ Now talk, Anastasia Kazakova presented data showing that in the C++ community, concurrency safety accounts for 27% of user setbacks. By comparison, boundary security concerns accounted for only 16 percent, and delete-after-use concerns accounted for 15 percent of user setbacks. Concurrency safety is the biggest pain point in security, and it doesn’t show up in Herb’s list.

Cpp2 achieves “structural safety,” Herb said on his slide. It can’t be true. Structural safety should mean that the language is built in such a way that it always leads to safe constructs (unless programmers really ignore the type system and take safety into their own hands) – similar to how Val or Rust are built. But Cpp2 doesn’t do that; it just adds more security checks to some common sources of unsafe behavior. If you’ve seen talks by Dave Abrahams and Dimitri Racordon, and Sean Parent’s talk, this should be immediately apparent.

This leads me to believe that a 50x increase in security is an impossible goal.

Measurability of goals

In theory, at any time, we can measure progress against these indicators and can assess whether this experiment is successful or not.

Let’s start with the second metric: 10x easier, as we need to measure in the guidance taught in C++ books. It is unlikely that a book will be written on Cpp2 until this experiment proves to be successful, but one can imagine what such a book would be about. We can identify what set of concepts we need to teach about Cpp2, and we can compare that to the list of things we’re currently teaching about C++. Therefore, we can measure this indicator.

It’s not as simple as one might think. C++ has a long history; so we know its pitfalls, and people document them in C++ books. However, Cpp2 doesn’t have such a rich history, so it’s always suspected that we don’t know all of its pitfalls. However, Cpp2 is so close to C++ that I sincerely believe that these concerns can be ruled out to get an accurate measure of simplicity.

However, I cannot say the same for the second indicator. How do we measure the percentage of CVEs and security vulnerabilities? First there needs to be a sufficiently large corpus of Cpp2 programs, written by a large number of programmers and companies. However, for this to happen, Cpp2 needs to be considered a success – a circular dependency. Therefore, the security metric defined in Herb’s presentation is not a measure of the success of the experiment.

It makes sense to use this metric to evaluate a language after the mainstream language has been in use for a while, but it cannot judge the success of the experiment.

With or without monads

At 1 hour and 33 minutes into the keynote (youtube video for reference), Herb Sutter said proudly: “I haven’t said the word monads once”. He then goes on to explain that Cpp2 is about the language philosophy we currently use in C++; not weird foreign terms from other languages.

While this statement may appeal to self-centered sections of the C++ community, I think it does more harm than help to the community.

First, C++ uses monads everywhere. The new C++ +23 feature may be a known example of using monads, but C++ is fundamentally built around monads. We implicitly use monads when we call functions that may throw exceptions. That is, almost everywhere.

Second, it creates a sense of self-sufficiency among language users. Such a statement does not open up new ideas to the community, but sends a message: C++ does not need to learn from other languages. However, the large amount of technical debt the language has, and the emergence of three successor languages, bears this out.

Compare

The following table attempts to provide a comparison between the three languages; C++ is also a benchmark.

The three C++ successor languages ​​announced this year are all considered experimental. There is no good indicator of whether they will actually succeed in attracting a sufficient number of coders/codebases to use them in production.

Looking at the number of stars on GitHub, we see that Carbon is the leader of the bunch, with a big gap compared to the other two. Carbon has managed to generate more hype within the community; a focus on inclusivity and a governance model may have contributed to this.

The three languages ​​also differ in how similar they are to C++. As expected, Cpp2 is the closest of the three languages ​​to C++. Carbon seems to be further away from C++, but uses the same basic building blocks as C++; in Carbon, users think in much the same way as they do in C++. Due to mutable value semantics, Val programmers need to have a slightly different mental model when programming, which may make Val a language that is further removed from C++. On the other hand, if we look at Val’s mantra of quick definitions, especially in the context of safety by default and simplicity, the language’s principles seem to translate well to a C++ audience.

Of the three new languages, Val is the only one that can back up its safety promises. The other two languages ​​try to change the defaults for some of the least safe operations; it’s unclear if that makes much of a difference.

All three languages ​​seem to be better than C++ in terms of consistency of language features. But changing the default doesn’t get you that far when it comes to language coherence. Here, Val’s approach seems more coherent than Carbon and Cpp2.

In the end, I think it’s important in an engineering discipline like ours: how many language design decisions are backed by some kind of science? In this regard, Val seems to be the only one with some theoretical basis. This can provide real assurance to its users.

it’s too early to give up

In his keynote, Herb called for not giving up on C++. This is a testament from the leadership of C++ that people are considering abandoning C++. Three successor languages ​​to C++ appeared within a year, just to confirm this idea. Whether C++ will start out in obscurity is unknown, but we can probably consider this year to be an inflection point for the future of C++.

For now, it is too early to tell whether these experiments will be successful. All languages ​​have strengths and weaknesses. If at least one of these succeeds, I believe we will advance the practice of programming languages; this could mean positive effects throughout the software industry.

I’ve tried to be as objective as possible in this comparison, but I do have my own biases. I hope these biases don’t get in the way of doing a good job comparing these languages.

Speaking of bias, I do need to admit: In my spare time, I’ve started working with the Val team to push the language’s core philosophy. To me, these ideas, if they are perfected and successfully adopted in practice, are more important than a particular language. I’d be happy if Val died as a programming language but all its ideas were incorporated into C++.

I’ve been fascinated by the idea of ​​mutable value semantics ever since I saw a recording of Dave and Dimitri’s talk at C++ Now. At CppCon 2022, I met Dave and Dimitri and went over some of the details with them, leading me to believe that the thinking behind Val is deep, well thought out, and worthy of close attention.

Looking at the popular numbers, Val isn’t doing so well. Perhaps one reason is that good ideas take time to settle. To paraphrase a famous speech, I chose to work for Val not because it was easy, but because it was difficult; because Val’s goals were worthwhile.

The text and pictures in this article are from CSDN

loading.gif

This article is transferred from https://www.techug.com/post/are-those-programming-languages-intended-to-replace-c-successful4f18f169a29af7b5c363/
This site is only for collection, and the copyright belongs to the original author.