Post Reply 
Prime and 50g, interesting perspective
09-01-2021, 11:08 PM
Post: #11
RE: Prime and 50g, interesting perspective
In my opinion, calling RPL a write-only language is plain wrong, and here's why:

In C, Java, Lua, and all those "good" languages you're writing well-commented and formatted code, most likely with an emphasis on making it readable.
Many RPL programs are instead highly optimized for speed or size (or even both). In addition, they're often stored and exchanged in binary format, meaning that the source you see comes from a decompiler - no comments for you, and the formatting is what the decompiler thinks is appropriate.
You're therefore comparing apples to oranges. Don't do that; take an RPL program stored in source form (i.e. as string - you can use OBJ\-> on it to call the compiler manually) with proper comments and formatting.

Let me illustrate with a C function. Have the spaghetti variant first:
Code:
void quat_mul(const double *q1, const double *q2, double *d) { d[0]=q1[0]*q2[0]-q1[1]*q2[1]-q1[2]*q2[2]-q1[3]*q2[3]; d[1]=q1[0]*q2[1]+q1[1]*q2[0]+q1[2]*q2[3]-q1[3]*q2[2]; d[2]=q1[0]*q2[2]-q1[1]*q2[3]+q1[2]*q2[0]+q1[3]*q2[1]; d[3]=q1[0]*q2[3]+q1[1]*q2[2]-q1[2]*q2[1]+q1[3]*q2[0]; }
That doesn't look very readable, does it? And I assure you, no seasoned C programmer would use this for anything other than a code-golf or obfuscated C programming contest. How about this instead?
Code:
/**
 * Multiply two quaternions (Hamilton product)
 * Quaternions are represented by an array of four doubles,
 * with the real part at index 0 and the imaginary part at indices 1 to 3.
 * Quaternion multiplication is non-commutative.
 * @param q1 The first of the quaternions to be multiplied
 * @param q2 The second of the quaternions to be multiplied
 * @param dest The quaternion in which the result shall be stored
 * @warning This implementation assumes that dest is not the same as q1 or q2
 **/
void quat_mul(const double *q1, const double *q2, const double *dest) {
    // the real part of the Hamilton product is the product of the real parts of both factors,
    // minus the dot product of the imaginary parts
    dest[0] = q1[0] * q2[0]
        - (q1[1] * q2[1] + q1[2] * q2[2] + q1[3] * q2[3]);
    // the imaginary part of the Hamilton product is the sum of:
    // - the imaginary part of each quaternion scaled by the real part of the opposite one
    // - the cross product of the imaginary parts (this is the non-commutative portion)
    dest[1] = q1[0] * q2[1]
        + q1[1] * q2[0]
        + q1[2] * q2[3] - q1[3] * q2[2];
    dest[2] = q1[0] * q2[2]
        + q1[2] * q2[0]
        + q1[3] * q2[1] - q1[1] * q2[3];
    dest[3] = q1[0] * q2[3]
        + q1[3] * q2[0]
        + q1[1] * q2[2] - q1[2] * q2[1];
}
There, much better. And that's just formatting and comments along with some mathematically inconsequential reordering of operations, it remains as optimized as it was. It could be even nicer if one would refer to other helper functions for vector-scalar multiplication, vector addition, dot product, and cross product. (By the way, I just typed these examples out - don't rely on their correctness as they are not tested; the point I'm trying to make is about what the code looks like).

An RPL program that has gone through the compiler and decompiler got its formatting and comments stripped, so it looks about as readable as the one-liner. However, that is your fault and not the language's (at least not entirely). For the sake of your and others' sanity, keep a copy of the source around, format it well, and comment it. Perhaps also leave some optimization out, like using local variables instead of juggling everything on the stack; and while you're at it, give them meaningful names, not just single letters.
Seriously, do it.
And stop comparing code-golfed RPL to formatted other languages.

That said, there are certain traits of RPL that permit bad coding habits to form. The ease and ubiquity of decompilation lures you into accepting its considerable drawbacks, and the relatively low-powered RPL systems (the 50G isn't as bad as the 28C and 28S, but its memory and performance are still way behind what "modern" programming environments offer) nudge us toward optimization even when it's not necessary. However, we can choose to fight the temptation - and produce readable code as a result.

And yes, I'm guilty of having produced a lot of highly optimized, hard-to-read RPL code. It's just that this is not the only way to handle the language.

Finally, another pair of hints:
- If you're worried about the memory cost of keeping the source for your RPL programs around, remember the SD card. You may accumulate a few megabytes of commented source if you're a busy programmer, but I don't think you'll reach a gigabyte, and you probably have two of those sitting around in port 3.
- Since RPL's ancestor Forth was also mentioned, I'll refer to this hint from Leo Brodie's classical Forth introduction:
Quote:Some elements of good FORTH style include:
- [...]
- the use of many short definitions rather than a few longer ones,
This can be applied directly to RPL. That means producing a flood of smaller programs to solve small parts of your problem, and using them in more programs to solve incrementally larger parts, until you have one that can handle the entire problem. In addition to having the pieces available for use in related problems, you'll also make it easier to understand the whole solution by breaking it down into bite-sized pieces. For instance, if RPL didn't have DOT and CROSS already, you'd implement them first, then use them in a program calculating the Hamilton product.
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: Prime and 50g, interesting perspective - 3298 - 09-01-2021 11:08 PM



User(s) browsing this thread: 1 Guest(s)