C++ sucks for games

K

Kenneth Tilton

Gerry Quinn said:
But any good programmer is certainly held back by lesser languages. I
found Lisp because, well, there is another category in the survey, for
those who went on an active search for a better way before they even
knew there was a better way, simply because they sensed that they were
being held back by their languages.

And if Lisp programmers were demonstrably more productive and effective,
I'd take such claims seriously. As, more importantly, would those who
tend to hire programmers.

[Likewise for 'agile' programmers, or 'test-driven' programmers, or
'generic' programmers, or any other of the many varieties of silver
bullet programmers.]

Speaking of silver bullets (defined as an order of magnitude improvement
by Brooks), I first experimented with a Lisp (in the form of Logo)
because I once saw Lisp described as a 4GL, where 4GL was defined simply
as an order of magnitude better than 3GL. This was shocking to me,
because I knew just enough Lisp to know that it was nothing like most
4GLs with their automatic database and screen building.

After three days of Logo, I understood. :)

kenny
 
K

Kenneth Tilton

Gerry Quinn said:
The other thing is that people actually DO program C++ in an OO fashion.
Not always, but often enough. Correct me if I'm wrong, but Lisp-ers
give a distinct impression of preferring generic programming.

You mean generic functions? Anyway, I would say you have gotten the
wrong impression, possibly because gurus Richard Gabriel and Paul Graham
loathe and despise OO. You may also be seeing what seems to me a general
failure of OO to win the hearts and souls of programmers. Even when they
use it, they do not use it much.

kt
 
M

Momchil Velikov

Kenneth Tilton said:
But any good programmer is certainly held back by lesser languages. I
found Lisp because, well, there is another category in the survey, for
those who went on an active search for a better way before they even
knew there was a better way, simply because they sensed that they were
being held back by their languages.

"Certainly" ?

I'd rather say for a good programmer there's no such thing as a
"lesser language". You either get the job done or you don't.
Everything else are sorry excuses.

~velco
 
P

Pascal Bourguignon

I'd rather say for a good programmer there's no such thing as a
"lesser language". You either get the job done or you don't.
Everything else are sorry excuses.

Yes, thanks to Greenspun's Tenth Law.
 
K

Kenneth Tilton

"Certainly" ?

I'd rather say for a good programmer there's no such thing as a
"lesser language".

Well, let's not get into word-quibbles. 6502 assembler is a fine
language, but the subject here is getting real projects done. Folks
worked out a while ago that an HLL would let programmers think at a
higher level of abstraction without mug cost; a good compiler might even
outdo some handcoded assembly language. So 6502 is sweet, but as far as
productivity goes it simply does not measure up.

As Eckel said, the key is programmer productivity, and an order of
magnitude improvement in that is worth a few cycles one might save by
coding in assembler (tho I guess he was contrasting Python with C++,
which is quite a bit more than a few cycles.).
You either get the job done or you don't.

Well, I keep pointing out that Lisp programmers tend also to kick ass in
more popular languages. They do get the job done. And they find Lisp
precisely because they are the best programmers and have ideas their
current languages cannot handle.

The guy who cuts and pastes code because they are not sure of the syntax
of a function in Vax Basic is most certainly not noticing metapatterns
in code which could be handled by procedural macros.
Everything else are sorry excuses.

Same answer. Who needs an excuse when they are the best in the shop and
deliver C++ or Java or Cobol faster than anyone else in the shop?

kenny
 
P

Pascal Bourguignon

Kenneth Tilton said:
Well, let's not get into word-quibbles. 6502 assembler is a fine
language, but the subject here is getting real projects done. Folks
worked out a while ago that an HLL would let programmers think at a
higher level of abstraction without mug cost; a good compiler might even
outdo some handcoded assembly language. So 6502 is sweet, but as far as
productivity goes it simply does not measure up.

Yes, it does. Just implement a lisp on 6502 and you're done.

As Eckel said, the key is programmer productivity, and an order of
magnitude improvement in that is worth a few cycles one might save by
coding in assembler (tho I guess he was contrasting Python with C++,
which is quite a bit more than a few cycles.).

Of course, the difference is made by a programmer who would try to do
all his application in 6502 and the one who will implement the lisp on
6502 and do the application in lisp.
 
G

Gareth McCaughan

Gerry Quinn wrote:

[about "self-modifying code", under which heading Gerry apparently
includes code generated by Lisp macros. (And C++ templates? And the
C preprocessor?)]
Surely the insistence that there must be some original code to be
written over is purely arbitrary and irrelevant? When code generated by
the program is executed, it is completely irrelevant whether it was
written in a portion of memory that contained some original source.

// Program A:

PUT_CODE_HERE:
NOP
NOP
NOP
NOP
GenerateCodeAt( PUT_CODE_HERE );
ExecuteCodeAt( PUT_CODE_HERE );

// Program B:

void* putCodeHere = (void*)( new opSizeItem[ 4 ] );
GenerateCodeAt( putCodeHere );
ExecuteCodeAt( putCodeHere );

They are both self-modifying, aren't they?

No, neither of them is self-modifying. There is no code
being modified in either case. There is code being
*generated*.

You are welcome to think that this is just as bad as
(what I'd call) self-modifying code. It seems fairly
clear to me that it isn't, but I don't know what your
reasons are for disapproving of self-modifying code;
maybe those reasons all apply equally to code generation.
 
S

Stefan Ram

Pascal Bourguignon said:
Of course, the difference is made by a programmer who would try
to do all his application in 6502 and the one who will
implement the lisp on 6502 and do the application in lisp.

It must have been around 1981 when I wrote my first LISP
functions into a computer (I might have written LISP functions
before - but only on paper). I still remember, writing a
"flaten" function for Lists. This was done using a 6502-Lisp,
called "HGL-Lisp".

It ran on my Pet 2001, i.e., on a 6502. I had bought HGL-Lisp
personally from its developer, Hans-Georg L.[1], who lived in
Berlin. I believe, there were few items sold and nowadays this
Usenet posting might be the only record (available via Usenet
or Web) of the existence of this Lisp implementation called
"HGL-Lisp".

[1] I know his full name, but I do not know, whether he wants
it to be published on the Usenet. I also have lost track of
him for a long time.
 
G

Gareth McCaughan

Gerry Quinn said:
My diagnosis is that you don't actually know C++. Your function
"Rabbit::jump(rabbit, 3)" makes no sense whatsoever. If the rabbit is
being told to jump, it doesn't need to be told it's a rabbit. And if it
is jumping over another rabbit, the other rabbit should be passed as a
reference, not a copy.

Eh?

1 There is only one rabbit there.
2 You have no way of knowing that it's being passed as a copy
rather than by reference; if the first argument to Rabbit::jump
was declared, say, as "const Rabbit &" then the call would
look just the same.

Of course jumping rabbits as such are of no relevance here;
here's a legitimate circumstance in which you could get a
function call of the kind you're saying is proof that Peter
doesn't know C++.

- Your program has a logging subsystem, based around
a class called Log whose instances are suitable
recipients for logging information.

- The Log class also has some static member functions;
for instance, there's one called "stringify" that
accepts an object reference and returns a string
that describes the object. This is in the Log class
because its behaviour is affected by a number of
parameters that are used elsewhere in the logging
subsystem.

- When a Log object is created and ready to start
logging, the first thing it does is to record some
information about itself for debugging purposes.

- This is done using the "stringify" function.

- So in Log::Log, or perhaps Log::begin or something
of the kind, you have some code that looks like this:

string s = Log::stringify(*this, some, other, parameters);
write_line(... some stuff involving s ...);

This isn't the exact same form as Peter's example, but
I think it's clearly just as "bad". The first argument
(passed by reference) is statically known to be of type Log,
after all.

Note: I don't claim that the above is great design,
and if I were actually designing a logging subsystem
I wouldn't expect it to look quite like that. But
it's certainly not crazy enough to warrant saying
that anyone who'd do it "doesn't actually know C++".
 
P

Peter Lewerin

Gerry Quinn said:
My diagnosis is that you don't actually know C++.

ROFL, again. Half a year ago I was randomly chatting with some
colleagues in university. The complexity of C++ came up, and I said,
half-jokingly: "I think only a half-dozen people in the world actually
know C++ really good". The other guy said: "Well, you know Henrik
[one of our 'visiting lecturers'] is really good at C++". To which I
had the perfect once-in-a-lifetime reply: "Of course! After all, *I*
taught him!"

Bottom line, I've used C++ professionally for quite a few years as a
programmer, and I've taught it for some years more. I know it well
enough.

You really shouldn't attempt to make up for your lack of solid
arguments by questioning other people's knowledge. Prove that
*you're* correct, instead of just shouting that *I'm* wrong.
Your function "Rabbit::jump(rabbit, 3)" makes no sense whatsoever.

Well, it *can* make sense, but that's not the point. You made the
point that C++ has a consistent syntax, and I demonstrated that it
does not, or at least not as consistent as Lisp's.
If the rabbit is being told to jump, it doesn't need to be told it's a
rabbit.

Presumably implemented as rabbit.jump(3), another example.
And if it is jumping over another rabbit, the other rabbit should be
passed as a reference, not a copy.

Firstly, how can you tell it's a copy and not a reference?

Secondly, it's still the case that if for some arcane reason it's
really imperative to call jump as a class method, there's no good way
of supplying the object that we wish to have jump except by passing it
as an argument. You may still say it's stupid and I might agree, but
it's valid C++.
 
G

Gerry Quinn

Claims? What claims? Those are good programmers who answered my survey
by saying they went looking for a better way and found it.

[Followed by some claims by two guys. Guys who may be eminent in the
computing field but whose primary work seems to be writing and
consulting. Guys who therefore have a vested interest in language churn
and silver bullets.]

What exactly did they *build* with their various flavour-of-the-month
languages?
Gerry, the simple fact is that you would be much more productive in Lisp
than you are in C++. Python, too, but that is still pretty slow and a
bit of a hack as languages go.

Why is that a fact? Can you point me to the Windows games and
screensavers written in these languages?

- Gerry Quinn
 
G

Gerry Quinn

Gerry Quinn wrote:

[about "self-modifying code", under which heading Gerry apparently
includes code generated by Lisp macros. (And C++ templates? And the
C preprocessor?)]

It might or might not. What I'm pointing out, after all, is that the
details of how the modified code is generated doesn't count.
No, neither of them is self-modifying. There is no code
being modified in either case. There is code being
*generated*.

NOP; NOP; NOP; NOP is code that is modified. Or if you object to this I
could change it to something that does something more interesting, or
would if it were not erased and replaced by alternative code.

The fact is it makes no difference. It is all about the level of the
generated code.

- Gerry Quinn
 
R

Raistlin Magere

Gerry Quinn said:
It might or might not. What I'm pointing out, after all, is that the
details of how the modified code is generated doesn't count.


NOP; NOP; NOP; NOP is code that is modified. Or if you object to this I
could change it to something that does something more interesting, or
would if it were not erased and replaced by alternative code.

The fact is it makes no difference. It is all about the level of the
generated code.

- Gerry Quinn
Hi,
I am sorry I don't understand but if the complain is about the fact that
"generated code" is bad (though I am not sure this is what you are saying)
and that "self-modifying code" is not a important definition distinction
from "generated code" (again I am not sure whether you meant this, this
premises is only what I understood from your messages but I might be wrong),
then aren't all programming languages above machine level bad? I mean as far
as I understood it when you write a C,C++ or Lisp program what used to
happen is that it got translated into assembler code (or machine code) i.e.
assembler code got "generated" by the compiler.
I don't see the difference between C code that generates C code and compiler
that translates C code to machine code (or whatever). However I feel that
there is a conceptual difference between code that modifies itself rather
than just creating new code. But as I said I am not sure I understood fully
this branch of the thread.
 
G

Gerry Quinn

Well, it *can* make sense, but that's not the point. You made the
point that C++ has a consistent syntax, and I demonstrated that it
does not, or at least not as consistent as Lisp's.
Secondly, it's still the case that if for some arcane reason it's
really imperative to call jump as a class method, there's no good way
of supplying the object that we wish to have jump except by passing it
as an argument. You may still say it's stupid and I might agree, but
it's valid C++.

Fair enough, and I apologise for doubting your knowledge of C++. I
think in part I was misled by your use of the term 'class method' for
what in a purely C++ context would usually be called a 'static method'.
Mainly though, it's probably just that the rabbit example is
exceptionally unsuited to an example of such a method! Sometimes
knowing a language can cause one to be blind to abnormal uses of it...

Of course C++ has a wide variety of usable function syntax, arguably too
wide. Though this is at a tangent to the original point of discussion
anyway.

- Gerry Quinn
 
C

Coby Beck

Gerry Quinn said:
Claims? What claims? Those are good programmers who answered my survey
by saying they went looking for a better way and found it.

[Followed by some claims by two guys. Guys who may be eminent in the
computing field but whose primary work seems to be writing and
consulting. Guys who therefore have a vested interest in language churn
and silver bullets.]

What exactly did they *build* with their various flavour-of-the-month
languages?

Anybody else's irony meter pinging its glass casing? Lisp, with roots 40+
years old and a decade old ANSI standard being referred to as "flavour of
the month"!
 
G

Gareth McCaughan

Gerry Quinn wrote:

[I said:]
[about "self-modifying code", under which heading Gerry apparently
includes code generated by Lisp macros. (And C++ templates? And the
C preprocessor?)]
[Gerry:]
It might or might not. What I'm pointing out, after all, is that the
details of how the modified code is generated doesn't count.

I don't think it's at all obvious that the details don't
matter. One of the reasons for avoiding self-modifying code
is that programs that use self-modifying code are hard to
understand. The way in which the code is generated can
make a difference to how hard the program is to understand.
NOP; NOP; NOP; NOP is code that is modified. Or if you object to this I
could change it to something that does something more interesting, or
would if it were not erased and replaced by alternative code.

The fact is it makes no difference. It is all about the level of the
generated code.

I don't understand that last statement. What do you mean by it?

As I hinted in the grandparent of this article, it would
be helpful if you'd explain exactly what you consider to
be the reasons for disapproving of self-modifying (or, more
generally, generated) code. There are several possible
such reasons, and some of them but not others apply (at
least in some measure) to all code generation. Also,
some of them are (at least in some measure) bogus reasons. :)

I'd say that there are several different questions that
need to be answered about an instance of code generation
before you can tell whether it's a Bad Thing or not. For
instance, and this is far from an exhaustive list,
- Does it happen at compile time or run time or what?
- Does the code responsible for generating it make
the function of the generated code clear? Preferably,
just as clear as the function of the normally-compiled
code in the program?
- Is any other code being replaced by the generated code?
- What determines whether or not the code gets generated,
and *what* code gets generated?
- Does the same code get modified several times during
the execution of the program?
- Is it necessary to understand exactly what's going on
with the code generation, in order to understand the
program?
- What safeguards are in place to ensure that the
code generation doesn't stomp on code that isn't
meant to be modified?

So, for instance, if you're writing code that looks like
this then it's pretty majorly bad. (My apologies to anyone
reading this in, e.g., comp.lang.lisp who may be offended
by the choice of C syntax...)

int do_something(int x) {
/* blah blah blah */
}

void hack_it(int a, int b, int c, const char * s) {
char * p = &do_something;
char t;
/* write preamble: */
*p++ = 0x90;
*p++ = 0xf3;
/* write main code */
while ((t=*s++) != 0) {
switch (t) {
case 'a':
*p++ = 0x83;
*p++ = 0x1f;
*p++ = a & 0xff;
break;
/* ... other equally hideous cases .. */
}
}
/* write postamble */
*p++ = 0xaa;
*p++ = 0xdc;
do_something(b);
flush_icache(&do_something, 0x100+(char*)&do_something);
}

Spotting all the things that suck about the crawling horror above
is left as an exercise for the reader. There are rather a lot.
But there are plenty of other things that can reasonably be called
code generation, and they don't all share all those problems.

Now, you've been describing Lisp macros as "self-modifying code".
I don't know how much you know about Lisp macros, but they are
certainly an *entirely* different kettle of fish from the nasty
C code above. Different enough that I can't imagine why anyone
would call them "self-modifying code".
 
P

Pascal Bourguignon

Gareth McCaughan said:
So, for instance, if you're writing code that looks like
this then it's pretty majorly bad. (My apologies to anyone
reading this in, e.g., comp.lang.lisp who may be offended
by the choice of C syntax...)

Yes, you could have done it in lisp:

(defun do-something ())

(defun hack-it (args exprs)
(let ((ignored (gensym)))
(eval `(defun do-something ,(append args (list '&rest ignored))
(declare (ignore ,ignored)
(prin1 "entered do-something")
(unwind-protect (progn ,@exprs)
(prin1 "exiting do-something")))))))


To be used for example with:

(run-in-parallel-threads
(loop (apply (function do-something) '(1 2 3 4 5)) (sleep 1))
(loop for args in '((a) (x y) (z) ())
for expr in '(((print a)) ((print (+ x y)))
((setf z (z + (sin z))) (print z))
((print "Who I am?")))
do (hack-it args expr) (sleep (random 3))))

Spotting all the things that suck about the crawling horror above
is left as an exercise for the reader. There are rather a lot.
But there are plenty of other things that can reasonably be called
code generation, and they don't all share all those problems.

Well, here (and in your C source) it's rather controlled. For example,
I believe above hack-it function to be perfectly Common-Lisp
conformant.


Another case which could be frowned about would be if hack-it had
modified itself, or like this:

(defun hack-it (next-result)
(let ((result '(nil)))
(PROG1 (first result)
(SETF (first result) next-result)))

(list (HACK-IT 1) (HACK-IT 2) (HACK-IT 3)) ==> (NIL 1 2) ; on clisp
(list (HACK-IT 1) (HACK-IT 2) (HACK-IT 3)) ==> (NIL NIL NIL) ; on sbcl

But what about:

(DEFUN hack-it (payload)
(LABELS
((FIND-CAR (TOKEN TREE)
(COND
((ATOM TREE) NIL)
((EQ TOKEN (CAR TREE)) TREE)
(T (OR (FIND-CAR TOKEN (CAR TREE))
(FIND-CAR TOKEN (CDR TREE)))))))
(prog1 :result
(LET* ((SOURCE '(DEFUN hack-it (payload)
(LABELS
((FIND-CAR (TOKEN TREE)
(COND
((ATOM TREE) NIL)
((EQ TOKEN (CAR TREE)) TREE)
(T (OR (FIND-CAR TOKEN (CAR TREE))
(FIND-CAR TOKEN (CDR TREE)))))))
(prog1 :result
(LET* ((SOURCE ':QUINE)
(QUINE (COPY-TREE SOURCE)))
(SETF (CAR (FIND-CAR :QUINE QUINE)) SOURCE)
(SETF (CAR (FIND-CAR :result QUINE)) payload)
(eval QUINE))))))
(QUINE (COPY-TREE SOURCE)))
(SETF (CAR (FIND-CAR :QUINE QUINE)) SOURCE)
(SETF (CAR (FIND-CAR :result QUINE)) payload)
(eval QUINE)))))

(list (HACK-IT 1) (HACK-IT 2) (HACK-IT 3) (HACK-IT 4))
==> :)RESULT 1 2 3) ; on any Common-Lisp I believe.
 
P

Peter Lewerin

Gerry Quinn said:
Fair enough, and I apologise for doubting your knowledge of C++.

No problem. I *was* being sloppy in my terminology: even if I
personally think 'class method' is a better term than 'static member
function', using a non-standard term will cause confusion.
Of course C++ has a wide variety of usable function syntax, arguably too
wide.

One could also argue the other case: 1) maybe different things
*should* be expressed differently. More to learn, but each case is
distinctive. 2) If someone really dislikes the variable syntaxa
(sp?), they could just use overloaded functions for type dispatch.
 
P

Petter Gustad

Gerry Quinn said:
Surely the insistence that there must be some original code to be
written over is purely arbitrary and irrelevant?

Did you read the wikipedia article? You seem to make you your own
definition of established terms. Same thing with object oriented
programming languages somewhere else in this thread.

Petter
 
G

Gerry Quinn

You mean generic functions? Anyway, I would say you have gotten the
wrong impression, possibly because gurus Richard Gabriel and Paul Graham
loathe and despise OO. You may also be seeing what seems to me a general
failure of OO to win the hearts and souls of programmers. Even when they
use it, they do not use it much.

I honestly don't care how Lisp-ers like program. And gurus appeal
mainly to those who want magic new 'paradigms' and associated jargon
that makes them feel clever.

- Gerry Quinn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,667
Latest member
DaniloB294

Latest Threads

Top