An orthogonal set is a minimalistic set of attributes which can be combined (at different values) to create any object in a category of objects defined by said attributes.
Ok, I just kinda vomited that up. Lemme see if I can write that in a way that I'll be able to understand it next month when I read my own blog. I know, I'll give a couple examples.
There exists a category (called two-dimensional space) of objects (called "points") that are fully defined by two attributes ("x-coordinate" and "y-coordinate"). Substituting these specific words into my definition above, we find that the x-coordinate and the y-coordinate make up an orthogonal set. Don't believe me? Watch:
The x- and y-coordinates are a minimalistic set of attributes which can be combined (at different values) to create any point in two-dimensional space.
So, if some attributes make up an orthogonal set, then each such attribute is said to be orthogonal to each other such attribute. Hence, the x-coordinate is orthogonal to the y-coordinate.
This isn't the whole story on orthogonality ... I'm still digesting the notion. But this gets me far enough to talk about orthogonality in programming languages.
Orthogonal languages try to implement a minimalistic set of features which can be combined to create any semantic in the range of the language.
Now Larry and Matz (of Perl and Ruby, respectively) have both (at different times) expressed a dislike for languages that try to be very orthogonal (like Java, C, etc). Orthogonal languages are small (in features) and often easy to learn completely. But they also often yield very verbose code, that people of the non-orthogonal persuasion would call unreadable.
Non-orthogonal languages like Perl and Ruby are large (especially Perl). They give you thirty ways to do the same thing. The idea is that the best way to do X in one place is not necessarily the best way to do it in another place. As a result, you can write very terse code. A person who knows a lot of the language finds this terse code super-readable.
The drawback to non-orthogonality is barrier to entry. Perl, for instance, can take a long time to learn. On the flip side, you can begin to be productive with Perl even if you only understand a very small subset of the language. Larry likes to use this fact in a comparison to natural languages. If all you know of Spanish is "te quiero", you already know enough to get a date, even though there is much more of the language to learn. (That is my example, not Larry's.)
Friday, September 26, 2008
Wednesday, August 27, 2008
Effective Optimization
I'll start with a simple premise: spend more time optimizing repeated
activities to get the biggest bang for you buck.
For example, if you wash dishes every day, but only mow the lawn once
a month, you will do better to spend some time improving your dish
washing skills, rather than spend that same time improving your lawn
mowing skills.
Similarly, if you are coding and you run across the need for a loop,
you should expend your effort optimizing the loop (especially if it
undergoes many iterations) than optimizing code that only executes
once.
The reasoning behind this rationale is simple. If you shave a second
off of a task that is executed once, you have saved a second. But, if
you shave a second off of an operation that occurs 3600 times, you
have saved an hour.
So, as a programmer, it seems natural to spend some time up-front
learning your tools (you do that once), in order to save time using
your tools (you do that lots).
I would gladly spend an hour learning a new time-saving feature of my
editor (namely Vim), if I will have the opportunity to use that
feature to save a second, ten million times before I die. (Ten million
seconds is well over a year's worth of 40-hour work weeks.) That
would be a really good use of an hour. Shoot, you could justify that
even if it took a week to learn that feature.
To sum up, I might say that an effective programmer should spend time
learning to:
1. Type rapidly,
2. Edit text quickly,
3. Know the languages that he/she uses well, and
4. Be able to quickly and effectively use his/her entire tool chain.
After all, just a few well-targeted optimizations in the form of the
basic programmer skills can mean years and years of savings over the
course of your career.
activities to get the biggest bang for you buck.
For example, if you wash dishes every day, but only mow the lawn once
a month, you will do better to spend some time improving your dish
washing skills, rather than spend that same time improving your lawn
mowing skills.
Similarly, if you are coding and you run across the need for a loop,
you should expend your effort optimizing the loop (especially if it
undergoes many iterations) than optimizing code that only executes
once.
The reasoning behind this rationale is simple. If you shave a second
off of a task that is executed once, you have saved a second. But, if
you shave a second off of an operation that occurs 3600 times, you
have saved an hour.
So, as a programmer, it seems natural to spend some time up-front
learning your tools (you do that once), in order to save time using
your tools (you do that lots).
I would gladly spend an hour learning a new time-saving feature of my
editor (namely Vim), if I will have the opportunity to use that
feature to save a second, ten million times before I die. (Ten million
seconds is well over a year's worth of 40-hour work weeks.) That
would be a really good use of an hour. Shoot, you could justify that
even if it took a week to learn that feature.
To sum up, I might say that an effective programmer should spend time
learning to:
1. Type rapidly,
2. Edit text quickly,
3. Know the languages that he/she uses well, and
4. Be able to quickly and effectively use his/her entire tool chain.
After all, just a few well-targeted optimizations in the form of the
basic programmer skills can mean years and years of savings over the
course of your career.
Monday, June 30, 2008
Implicit information via types / inheritance
There exists a broad class of objects in the real world called vehicles. A car is a type of vehicle. A Toyota Camry is a type of car. A 2006 Toyota Camry is a type of Toyota Camry.
These types of relationships would be easy to implement in classes, using subclassing. Class vehicle implements some really basic stuff. Class car implements some more specific stuff, and so on.
Or, you could say a car is a vehicle with the "type" attribute set to "car".
This provides greater flexibility, but you forfeit some niceties.
For instance, the count_wheels method should return 4 for a car, and 18 for a semi. (In C++ terms, count_wheels would be a "pure virtual method" in the vehicle class, and overridden in subclasses.) If you make car be a subclass of vehicle, no conditional is needed when you call count_wheels ... the type system checks the type and calls the appropriate overridden method.
But if you make car be a vehicle with a member called "type" set to "car", you control the conditional (= greater flexibility).
Of course, if you use the type system to hold the implicit info (am I a car or a semi?), then the conditional is evaluated at compile time ... so there *may* be a performance consideration, but beware of thinking this way.
So the moral is that anytime you use inheritance, you forfeit flexibility, but gain some "compiler-does-it-for-you" efficiencies. In fact, inheritance creates strong coupling between the parent class and the subclass, which is not usually a design goal! The only gain is less code (because the compiler does some stuff for you).
On a similar note, I've read some blogs where people claim that all inheritance should be replaced with composition, because composition doesn't require you to give up as much flexibility as does inheritance. So, for instance, a car is "composed of" a vehicle. The con here is you have to completely rewrite the interface for the car class. It doesn't come for free from the vehicle class like with inheritance.
These types of relationships would be easy to implement in classes, using subclassing. Class vehicle implements some really basic stuff. Class car implements some more specific stuff, and so on.
Or, you could say a car is a vehicle with the "type" attribute set to "car".
c = new vehicle;
c.type = "car";
This provides greater flexibility, but you forfeit some niceties.
For instance, the count_wheels method should return 4 for a car, and 18 for a semi. (In C++ terms, count_wheels would be a "pure virtual method" in the vehicle class, and overridden in subclasses.) If you make car be a subclass of vehicle, no conditional is needed when you call count_wheels ... the type system checks the type and calls the appropriate overridden method.
class car : vehicle { int count_wheels() { return 4; }; };
class semi : vehicle { int count_wheels() { return 18; }; };
c = new car;
s = new semi;
c.count_wheels(); // returns 4
s.count_wheels(); // returns 18
But if you make car be a vehicle with a member called "type" set to "car", you control the conditional (= greater flexibility).
class vehicle {
int type;
int count_wheels() { // conditional
if (type == "car" ) return 4;
if (type == "semi") return 18;
}
};
Of course, if you use the type system to hold the implicit info (am I a car or a semi?), then the conditional is evaluated at compile time ... so there *may* be a performance consideration, but beware of thinking this way.
So the moral is that anytime you use inheritance, you forfeit flexibility, but gain some "compiler-does-it-for-you" efficiencies. In fact, inheritance creates strong coupling between the parent class and the subclass, which is not usually a design goal! The only gain is less code (because the compiler does some stuff for you).
On a similar note, I've read some blogs where people claim that all inheritance should be replaced with composition, because composition doesn't require you to give up as much flexibility as does inheritance. So, for instance, a car is "composed of" a vehicle. The con here is you have to completely rewrite the interface for the car class. It doesn't come for free from the vehicle class like with inheritance.
inheritance -> shorter :), less flexible :( code
Subscribe to:
Posts (Atom)