On Sat, 20 Jan 2001, Christian wrote: > I am not interested in sugar -- I want substance. Perhaps the > substance is the language as a whole, including the developmental > process it encourages. But surely there is more. Or not. That's what > I came here to find out. Arrogant? Sure. Stupid? No. As you're a games programmer, you have the advantage of being in control of all your code, and the disadvantage of needing the maximum speed out of it. Ruby is designed for the opposite end of the spectrum, trading speed for extra generality. As such, you may not get what you want from Ruby. Even if you were to use Ruby for prototyping, you would still need to convert the prototype code to C++ to fit in with the rest of your code. This is pretty much always going to be slower than prototying directly in C++, so I think this may be why you're not seeing the benefits of Ruby as a prototyping language. I'm not really sold on the prototyping idea myself, so this isn't an angle I'm going to push. I used to convert code from Fortran to Pascal and it was a very painful exercise. I can see that converting some Ruby constructs to C++ would be equally painful. All I'll say is that I do find writing code in Ruby to be considerably quicker and the option of rewriting the slow Ruby bits in C solves the execution speed issue for me, but I have less stringent requirements. A language provides an infrastructure that ties everything together. Code communicates with each other through the infrastructure, whether passing values on the stack, or through function calls. Types are one form of infrastructure introduced to prevent ints being read as floats and that sort of thing. OOP was introduced as a way of having private namespaces and hidden implementation details. The two can be combined, but they don't need each other. The problem with infrastructure is that it makes some things very easy at the expense of other things. If I choose to use a hammer as my tool, I can do nails and contract killings, but I can't repair broken watches. If I choose a screwdriver, I can do broken watches and contract killings. Hmm, why did I become a programmer? Combining different forms of infrastructure strengthens and limits the code. Merging the hammer and screwdriver might give me a hammer with a screwdriver head poking out the bottom of the handle. Works well in most cases, but now I can't fit the screwdriver in tight places because the handle is too thick, and I can't twist it very well because the hammer head gets in the way. I'm also in danger of stabbing myself with the screwdriver every time I hammer. OOP with dynamic typing is more like writing template code. I no longer have to make sure that Food and Drink are derived from the same base class before I can issue the "consume" command. Objects can talk directly to each other. This could result in little spiderwebs of tightly coupled objects, so I'll have to apply the Law of Demeter a little more rigorously, but the number of times I want to rearrange objects is greater than the number of times static typing would have saved me. Dynamic typing tells about my mistakes anyway. When considering the question of compiler vs interpreter, I have to ask... why did you write those interpreters? Why do you find ANTLR so useful, rather than just using C++ everywhere? My guess would be that an external call to the C++ compiler wasn't feasible, so you had to use an embedded language. And while you're there, why not create a domain specific language to handle stuff that would be difficult in C++? (I'm guessing) Ruby was created for pretty much the same reasons. It's designed to be easily embedded in existing C programs as a scripting language extension. It can also be used as the infrastructure for a C program for a higher level view. It can be the glue between C modules, And, of course, it can be a stand alone interpreter. Why didn't Matz write Ruby as a compiler from day one? My guess would be that he was more interested in the language than in prematurely optimising for performance. An interpreter is cross-platform by its nature. An interpreter can be embedded in a C program. C extensions can be embedded in the interpreter. These traits make Ruby more immediately useful than a standalone compiler. Another difference between a compiler and interpreter is the level of hardware simulation. A compiler generates code that is expressed in the language of the real CPU. An interpreter pretends to be a CPU tailored for the language. Ruby's interpreter understands higher level language constructs like OOP, continuations, namespaces, and so on. To produce the equivalence of this in real CPU code, a lot of wrapper code would have to be inserted into the machine code. This wrapper code would do pretty much the same stuff as the interpreter does anyway, hence compiled versions of interpreted languages tend not to be much faster. Just call me Analogy Boy, but I have a custom made guitar which I designed so I could define exactly what I wanted. When I play it, I have control over individual notes. My fingers directly touch the vibrating strings, so I can do all sorts of things like bend notes, pluck harmonics, tap with the other hand, add vibrato to a chord and so on. On the downside, I can only play 6 notes at a time, of which I can only modify 4 of them. In comparision, a piano has very limited control. It takes skill to play very quietly. It doesn't let you bend notes, it doesn't let you tap harmonics, and it doesn't even allow you to keep notes going. On the positive side, I can play 10 notes at a time, and modify all of them within the span of my hands. The piano manages this feat by presenting a simplified interface more suitable for human use. Each note was given a fixed, standard, behaviour. It uses equal temperament tuning to make it possible to play in all keys and still retain an audience. Flexibility was traded off for ease of use. The consequence of this was that it became possible to play symphonies on a single instrument. It didn't sound so good, but they sure did what people wanted at the time. Lots more noise per bash. Back to the real world. Ruby is the piano here. It's a predictable language with standard behaviour. The programmer trades the ability to control the code almost to the assembler level, but gains the brainspace from not having to care anymore. That extra brain power can be applied to program design or handling more functionalities in the code. As a practical example, programming problems are best addressed by domain specific designs. The problem comes in when I want to include libraries written by other programmers. In C, some libraries take care of their own objects. Others I have to free. Some return structures. Others take structure pointers and modify in-place. In C++, it gets worse. Some use operator overloading. Others take function calls. Some use homebrew functions, others use the STL. I'm going to have to remember this stuff while coding. "This data comes from libfrob.a so it needs to be passed to frobfree(), not to delete(), or the program crashes". I haven't found a GUI toolset I like yet, because all of them use OOP and callbacks which force me to write my code differently. If someone presses a button, I wanna ask when I wanna know, with a nice specific "if button.pushed" where I care about it, not through some callback! Using more libraries compounds this problem. Passing data from one library to another involves lots and lots of mindless conversion routines. Passing information is a headache - can I put that data in this struct, or will it become a memory leak since this library frees its own data and doesn't know about that library's objects... Ruby lets me forget this and get on with solving the problem. I'm willing to sacrifice other people's flexibility for a consistent model that I can use in my own programs. I want external libraries to be written with the same mindset as my code. I've got that now. -- steve / deaf.org