A thought experiment: can we have C++ programs without source files (that it, without .cpp files)?
The typical C++ program consists of header files (.h) and source files (.cpp). The header files provide definitions for classes, and the source files provide the definition of the implementations.
Yet the C++ language allows one to define function implementation in the header files. We typically see this only for short functions. To wit:
random_file.h
class random_class
{
private:
int foo_;
public:
random_class( int foo ) : foo_(foo);
int foo( void ) { return foo_ };
}
This code defines a small class that contains a single value and has no methods. The sole member variable is initialized in the constructor.
Here's my idea: Using the concepts of functional programming (namely immutable variables that are initialized in the constructor), one can define a class as a constructor and a bunch of read-only accessors.
If we keep class size to a minimum, we can define all classes in header files. The constructors are simple, and the accessor functions simply return calculated values. There is no need for long methods.
(Yes, we could define long functions in headers, but that seems to be cheating. We allow short functions in headers and exile long functions into .cpp files.)
Such a design is, I think, possible, although perhaps impractical. It may be similar to the chemists' "perfect gas", an abstraction that is nice to conceive but unseen in the real world.
Yet a "perfect gas" of a class (perhaps a "perfect class") may be possible for some classes in a program. Those perfect classes would be small, with few member variables and only accessor functions. Its values would be immutable. The member variables may be objects of smaller classes (perhaps perfect classes) with immutable values of their own.
This may be a way to improve code quality. My experience shows that immutable objects are much easier to code, to use, and to debug. If we build simple immutable classes, then we can code them in header files and we can discard the source files.
Coding without source files -- no there is an idea for the future.
Showing posts with label programmer productivity. Show all posts
Showing posts with label programmer productivity. Show all posts
Sunday, April 28, 2013
Tuesday, March 27, 2012
Programming language as amplifier, or not
Studies have shown that different programmers perform at different levels. Not all programmers are alike, not even programmers with the same job title. The difference between a really good programmer and a really poor programmer has been measured to be a factor of twenty-five!
What I have not seen is a study of programming languages and their role in these differences.
I believe some programming languages to be equalizers and other programming languages to be amplifiers. Some programming languages can make programmers better, or at least allow them to be more productive. Other programming languages limit them, bunching programmers together.
I noticed the difference in programming languages when I shifted from C to C++. The C++ language was more than a "better C" or even a "C with classes" arrangement. It allowed one to use more sophisticated constructs, to develop programs that were more complex. As some folks said, "with C you can shoot yourself in the foot, with C++ you now have a machine gun".
C++ is a powerful language, and good programmers can use it to good effect. Poor programmers, on the other hand, frequently end with messy programs that are difficult to understand and maintain (often with defects, too).
C++ is an amplifying language: good programmers are better, poor programmers are worse.
But that does not hold for all languages.
FORTRAN and COBOL are equalizing languages. (That is, the early versions of these languages were equalizers.) They reduce the difference between good and poor programmers. The structure of the languages constrains both types of programmers and the code is pretty much the same, regardless of the programmer's skill. (Later versions of FORTRAN moved it closer to an amplifying language.)
Some other programming languages:
Assembly language is an amplifier. While the "trick" to good programming in assembly language is understanding the processor and the instruction set, assembly language programming is such that a good programmer is really good and a poor programmer has a very difficult time.
Pascal is an equalizer. It has enough "guardrails" in place to prevent a poor programmer from making a mess. Yet those same guardrails prevent a good programmer from truly excelling.
Perl is an amplifier. Python is an amplifier. Ruby is an amplifier.
Java and C# are equalizers, although they are shifting towards the amplifier end of the spectrum. Sun changes Java and Microsoft changes C#, and the changes add features (such as lambdas) which become the machine guns for shooting yourself in the foot.
Viewed in the light of "amplifier" or "equalizer", one can assess programming languages for risk. An amplifying language can allow programmers to do wonderful things, but it also allows them to create a horrible mess. When using an amplifying language, you have to take steps to ensure the former and prevent the latter. An equalizing language, on the other hand, limits the possibility of mess (while also limiting the possibility of something wonderful).
But if you don't care about something wonderful, if you want to deliver a known quantity on known schedule (and the quantity and schedule are reasonable), then an equalizing language is better for you. It allows you to hire not-so-great programmers and you know that they will delivery something of reasonable quality.
If my reasoning is true, then we can expect small shops (especially start-ups) to use the amplifying languages. They have to, since they need above-average results. In contrast, large conservative shops will use equalizing languages. They will (most likely) be unwilling to hire top talent and will opt for mediocre (but available) personnel. They will also (most likely) be unwilling to educate and develop
Capabilities of the language are one factor among many. The C++ programming language become popular not because it was an equalizer (it's not) nor because it was an amplifier -- it became popular because it was the way to develop applications for Windows and Microsoft supplied good tools for it. That is no longer the case. The primary language for Windows applications is now C#. The primary language for iOS applications is Objective-C. The primary language for Android applications is Java. Yet programs for all of these platforms can be developed in other languages.
With today's multi-language market, expect companies to select the tool that suits their needs. Companies that need top-level performance will pick the amplifying languages. Companies that need certainty and want to avoid risk will pick the equalizing languages.
What I have not seen is a study of programming languages and their role in these differences.
I believe some programming languages to be equalizers and other programming languages to be amplifiers. Some programming languages can make programmers better, or at least allow them to be more productive. Other programming languages limit them, bunching programmers together.
I noticed the difference in programming languages when I shifted from C to C++. The C++ language was more than a "better C" or even a "C with classes" arrangement. It allowed one to use more sophisticated constructs, to develop programs that were more complex. As some folks said, "with C you can shoot yourself in the foot, with C++ you now have a machine gun".
C++ is a powerful language, and good programmers can use it to good effect. Poor programmers, on the other hand, frequently end with messy programs that are difficult to understand and maintain (often with defects, too).
C++ is an amplifying language: good programmers are better, poor programmers are worse.
But that does not hold for all languages.
FORTRAN and COBOL are equalizing languages. (That is, the early versions of these languages were equalizers.) They reduce the difference between good and poor programmers. The structure of the languages constrains both types of programmers and the code is pretty much the same, regardless of the programmer's skill. (Later versions of FORTRAN moved it closer to an amplifying language.)
Some other programming languages:
Assembly language is an amplifier. While the "trick" to good programming in assembly language is understanding the processor and the instruction set, assembly language programming is such that a good programmer is really good and a poor programmer has a very difficult time.
Pascal is an equalizer. It has enough "guardrails" in place to prevent a poor programmer from making a mess. Yet those same guardrails prevent a good programmer from truly excelling.
Perl is an amplifier. Python is an amplifier. Ruby is an amplifier.
Java and C# are equalizers, although they are shifting towards the amplifier end of the spectrum. Sun changes Java and Microsoft changes C#, and the changes add features (such as lambdas) which become the machine guns for shooting yourself in the foot.
Viewed in the light of "amplifier" or "equalizer", one can assess programming languages for risk. An amplifying language can allow programmers to do wonderful things, but it also allows them to create a horrible mess. When using an amplifying language, you have to take steps to ensure the former and prevent the latter. An equalizing language, on the other hand, limits the possibility of mess (while also limiting the possibility of something wonderful).
But if you don't care about something wonderful, if you want to deliver a known quantity on known schedule (and the quantity and schedule are reasonable), then an equalizing language is better for you. It allows you to hire not-so-great programmers and you know that they will delivery something of reasonable quality.
If my reasoning is true, then we can expect small shops (especially start-ups) to use the amplifying languages. They have to, since they need above-average results. In contrast, large conservative shops will use equalizing languages. They will (most likely) be unwilling to hire top talent and will opt for mediocre (but available) personnel. They will also (most likely) be unwilling to educate and develop
Capabilities of the language are one factor among many. The C++ programming language become popular not because it was an equalizer (it's not) nor because it was an amplifier -- it became popular because it was the way to develop applications for Windows and Microsoft supplied good tools for it. That is no longer the case. The primary language for Windows applications is now C#. The primary language for iOS applications is Objective-C. The primary language for Android applications is Java. Yet programs for all of these platforms can be developed in other languages.
With today's multi-language market, expect companies to select the tool that suits their needs. Companies that need top-level performance will pick the amplifying languages. Companies that need certainty and want to avoid risk will pick the equalizing languages.
Sunday, January 29, 2012
Productivity
Today, I wrote a small program to parse web pages and create a graph of relationships between them. The task got me thinking of the capabilities of programming languages.
Different programming languages offer different levels of "power". (By power, I mean the amount of work that can be done by a specific amount of code. Powerful languages require less code to perform the same task as weak languages.)
To some extent, power can be masked by the job. Some languages are weak but well-suited to some tasks. A jet airliner is a powerful craft, yet sometimes a hang glider is needed. Let's stick to mainstream projects, which operate in the middle range. We can avoid the hang glider tasks, and we can avoid the tasks that need supersonic stealth flight.
The languages for mainstream projects have, over time, improved. From the Elder Days of FORTRAN and COBOL, through the object revolution of C++, to the network era of Java and C#, later languages (and their IDEs and libraries) have been more capable than their predecessors.
Today I used Ruby and its libraries to parse the HTML in web pages, and GraphViz to render the graph of relationships. I was able to build my "system" in a few hours. Most of my work was "standing on the shoulders of giants", since I could leverage powerful tools. To build the same system in the early 1990s would require a bit more work (Ruby had not been invented, although GraphViz was around).
Languages and tools of today are more powerful than languages and tools of a decade ago. No surprise there. C++ is more powerful than C, Java more powerful than C++, C# slightly more powerful than Java (once you include the IDE and libraries), and Python and Ruby are more powerful than C#. The evolutionary ladder of languages moves us up the scale of power.
But let us think about legacy projects. Legacy projects often stay with their original technology. A project started in C++ often stays in C++; converting to a different language often means a complete re-write of the entire code base. (And often the re-write must be done in toto, converting all code at once.)
Project managers are right to evaluate the cost of converting to a different language. It is a significant effort, and the task can divert resources from enhancements and defect fixes.
But project managers must balance the costs of conversion against the costs of not converting.
A naive approach says that the cost of not converting is zero -- the project continues running and new versions are released.
A more savvy understanding of non-conversion includes the opportunity cost, the cost of lower productivity over time.
The decision of conversion to a new language is similar to the decision to purchase a new car. The old car runs, but needs maintenance and gets poor gas mileage. A new car will cost a lot of money up front, and will have lower maintenance and operating costs (and will probably be more reliable). When do you buy the new car?
An additional musing:
A large project using older technology can be viewed as inefficient, since it requires more developers to perform the same work in a similar system that uses a more powerful language. Therefore, the decision to defer conversion to a new language is a decision to increase the development team (or to forego the opportunity to reduce the development team).
Different programming languages offer different levels of "power". (By power, I mean the amount of work that can be done by a specific amount of code. Powerful languages require less code to perform the same task as weak languages.)
To some extent, power can be masked by the job. Some languages are weak but well-suited to some tasks. A jet airliner is a powerful craft, yet sometimes a hang glider is needed. Let's stick to mainstream projects, which operate in the middle range. We can avoid the hang glider tasks, and we can avoid the tasks that need supersonic stealth flight.
The languages for mainstream projects have, over time, improved. From the Elder Days of FORTRAN and COBOL, through the object revolution of C++, to the network era of Java and C#, later languages (and their IDEs and libraries) have been more capable than their predecessors.
Today I used Ruby and its libraries to parse the HTML in web pages, and GraphViz to render the graph of relationships. I was able to build my "system" in a few hours. Most of my work was "standing on the shoulders of giants", since I could leverage powerful tools. To build the same system in the early 1990s would require a bit more work (Ruby had not been invented, although GraphViz was around).
Languages and tools of today are more powerful than languages and tools of a decade ago. No surprise there. C++ is more powerful than C, Java more powerful than C++, C# slightly more powerful than Java (once you include the IDE and libraries), and Python and Ruby are more powerful than C#. The evolutionary ladder of languages moves us up the scale of power.
But let us think about legacy projects. Legacy projects often stay with their original technology. A project started in C++ often stays in C++; converting to a different language often means a complete re-write of the entire code base. (And often the re-write must be done in toto, converting all code at once.)
Project managers are right to evaluate the cost of converting to a different language. It is a significant effort, and the task can divert resources from enhancements and defect fixes.
But project managers must balance the costs of conversion against the costs of not converting.
A naive approach says that the cost of not converting is zero -- the project continues running and new versions are released.
A more savvy understanding of non-conversion includes the opportunity cost, the cost of lower productivity over time.
The decision of conversion to a new language is similar to the decision to purchase a new car. The old car runs, but needs maintenance and gets poor gas mileage. A new car will cost a lot of money up front, and will have lower maintenance and operating costs (and will probably be more reliable). When do you buy the new car?
An additional musing:
A large project using older technology can be viewed as inefficient, since it requires more developers to perform the same work in a similar system that uses a more powerful language. Therefore, the decision to defer conversion to a new language is a decision to increase the development team (or to forego the opportunity to reduce the development team).
Subscribe to:
Posts (Atom)