• Create Account

Banner advertising on our site currently available from just $5! # Why lisp? Old topic! Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic. 104 replies to this topic ### #81Krippy2k Members - Reputation: 134 Like Likes Like Posted 24 February 2004 - 06:57 AM Not sure that''s a great example I dont know a lot about SDL, but I see no reason that one could not do the same thing with C macros and have this: WITHLOCKEDSURFACE( screen, rl->update(t); gl->update(t); bl->update(t); ); Which is more readable than your example for me. The C macro might be less readable than your macro, I don''t know, as I havent gotten too far into lisp macros yet, and you didn''t show what your macro looked like A similar C macro could look something like this: (havent tested this actual code, so i might have done it wrong, but i know the macro could be done correctly if i spent a few minutes on it) #define WITHLOCKEDSURFACE( screen, commands ) \if (SDL_MUSTLOCK(screen)) \{ \ if (-1 == SDL_LockSurface(screen)) \ { \ printf("Can''t lock hardware surface\n"); \ exit(1); \ } \} \commands;\if (SDL_MUSTLOCK(screen))\{ \ SDL_UnlockSurface(screen);\} Or one could simply forget about macros and use functions: Lock( screen );rl->update(t);gl->update(t);bl->update(t);Unlock( screen ); Which is still just as readable as your code, and the only area that makes it more bug prone is that a person could forget to unlock. Peace Sponsor: ### #82HairyTroll Members - Reputation: 192 Like Likes Like Posted 24 February 2004 - 07:13 AM quote: Original post by Krippy2k Not sure that''s a great example I dont know a lot about SDL, but I see no reason that one could not do the same thing with C macros and have this: WITHLOCKEDSURFACE( screen, rl->update(t); gl->update(t); bl->update(t); ); Which is more readable than your example for me. I had no idea that C macros could do that Do you have to pass a variable with the name ''screen'' to the C macro, or can it be any variable name, like ''screen-surface'' ? quote: Original post by Krippy2k Or one could simply forget about macros and use functions: Lock( screen ); rl->update(t); gl->update(t); bl->update(t); Unlock( screen ); [/source] Which is still just as readable as your code, and the only area that makes it more bug prone is that a person could forget to unlock. In SDL, surface locks can be nested, with a 5 locks requiring 5 unlocks. Forcing the coder to manually match lock/unlock calls would be a potential source of bugs. Can the C macro be nested, for example if the call to lock the surface was in a recursive function ? ### #83HairyTroll Members - Reputation: 192 Like Likes Like Posted 24 February 2004 - 08:03 AM quote: Original post by Krippy2k Not sure that''s a great example I dont know a lot about SDL, but I see no reason that one could not do the same thing with C macros and have this: WITHLOCKEDSURFACE( screen, rl->update(t); gl->update(t); bl->update(t); ); OK, Mr. Smarty-pants Say you wanted to add a new IF conditional, so instead of having to do this: SDL_Surface* pSurface = SDL_SetVideoMode ( SCREENWIDTH , SCREENHEIGHT , SCREENBPP , SCREENFLAGS ) ;if (pSurface == null) { // Videomode failed. Very Bad. Exit program}// Do something with pSurface  You could do this: aif (SDL_SetVideoMode ( SCREENWIDTH , SCREENHEIGHT , SCREENBPP , SCREENFLAGS ) != null) { // Do something with *it*. } else { // Videomode failed. Very Bad. Exit program}  I say // Do something with *it*. Where *it* is created by aif and automatically bound to the return value of SDL_SetVideoMode. ### #84Krippy2k Members - Reputation: 134 Like Likes Like Posted 24 February 2004 - 08:35 AM Not sure I understand you correctly, but that looks like something that C++ if statements already give you. I would do it like this: if ( SDL_Surface* it = SDL_SetVideoMode( SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SCREENFLAGS ) ){ //*it* is in scope here, we can use it.}else{ //bad video mode} Which would be a little different from what you state, it requires you to define the type of the return value yourself, but atleast you would be able to see what type of object *it* is at the relevent place. Edit: Note that the above only works in C++, C requires all variables to be declared at the beginning of a function. Peace [edited by - krippy2k on February 24, 2004 3:42:44 PM] ### #85Vlion Members - Reputation: 151 Like Likes Like Posted 24 February 2004 - 08:42 AM Interesting. The lisp macro is more readable than the core code, for sure. C macros are not something particularly cool in general. I would probably have some kind of locking class that locked in constructor and unlocked in destructor. Not knowing SDL I''m not sure how clean that would be. ~V''lion Bugle4d ### #86ggs Members - Reputation: 166 Like Likes Like Posted 24 February 2004 - 10:02 AM quote: Original post by flangazor I don''t think this subtopic is going to bear any useful fruit. I think it should end here before it turns into a full-fledged battle of pedantry. I agree, and I''ll not going to be adding any more to it. ### #87Spoonbender Members - Reputation: 1254 Like Likes Like Posted 24 February 2004 - 10:14 AM quote: Original post by Vlion I still don''t see why lisp is conclusively better than a well-written imperative langauge with a good library behind it. What makes you think that *any* language is conclusively better than another? most languages have their good and bad points, and that includes Lisp as well as C++. Which one is better? Depends on your preferences. (And of course, on what you want to do with it) (Sorry, just had to shoot that in here) :D --------- Life is like a grapefruit. It''s sort of orangy-yellow and dimpled on the outside, wet and squidgy in the middle. It''s got pips inside, too. Oh, and some people have half a one for breakfast ### #88Dobbs Members - Reputation: 164 Like Likes Like Posted 24 February 2004 - 01:44 PM quote: Original post by Krippy2k Not sure I understand you correctly, but that looks like something that C++ if statements already give you. I would do it like this: if ( SDL_Surface* it = SDL_SetVideoMode( SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SCREENFLAGS ) ){ //*it* is in scope here, we can use it.}else{ //bad video mode} Which would be a little different from what you state, it requires you to define the type of the return value yourself, but atleast you would be able to see what type of object *it* is at the relevent place. Edit: Note that the above only works in C++, C requires all variables to be declared at the beginning of a function. Peace [edited by - krippy2k on February 24, 2004 3:42:44 PM] The example given above was just one instance of a general style of macro programming referred to as anaphora in On Lisp (I don''t know if the term is in more widespread use, that''s the only place I''ve seen the term/feature used). Chapter 14 of On Lisp goes into more detail about how this can be used, although if you don''t have experience with Lisp/macros/functional programming you might have trouble understanding it. That chapter demonstrates for example how you can create unnamed function within whose body the symbol "f" is automatically bound to the function (so you can make unnamed, recursive lambda expressions). Something I did with macros after a few months of hacking around in Lisp for fun - function currying. I had a macro which could take code declaring an arbitrary function* like this: (defun f (x y z) (+ x y z)) into a form like this: (defun f (x) (lambda (y) (lambda (z) (+ x y z)))) Then I wrote another macro which would take an actual call to f: (f 1 2) and turn it into: (funcall (f 1) 2) Voila, basic function currying. Not present in Lisp, but it''s a feature I like in SML and I hacked it into Lisp with relatively little experience. * well not completely arbitrary, it doesn''t handle keyword arguments and fancy stuff like that. ### #89SabreMan Members - Reputation: 504 Like Likes Like Posted 24 February 2004 - 10:22 PM quote: Original post by HairyTroll quote: Original post by Krippy2k Not sure that''s a great example I dont know a lot about SDL, but I see no reason that one could not do the same thing with C macros and have this: WITHLOCKEDSURFACE( screen, rl->update(t); gl->update(t); bl->update(t); ); Which is more readable than your example for me. I had no idea that C macros could do that The C preprocessor does not provide anything like the abilities of the Lisp macro system. For starters, C macros cannot perform environment capture, which means WITHLOCKEDSURFACE is unlikely to be hygienic. This is really why people wishing to see the benefits of Lisp need to go and do some learning - it''s no good producing syntactic similarities and assuming that the semantics are the same. ### #90flangazor Members - Reputation: 516 Like Likes Like Posted 25 February 2004 - 01:10 AM The C++ idiom I would have chosen would be: { Lock lock(screen); rl->update(); gl->update(); bl->update(); }//implicit dtor on lock releases lock. But I agree with SabreMan that trying to think in C++ in order to describe Lisp will only show you the subset of what Lisp you can express in C++. You may like to think of it as the relation between normal speech and ''newspeak'' from 1984 (without the ominous overtones). ### #91Krippy2k Members - Reputation: 134 Like Likes Like Posted 25 February 2004 - 03:24 AM quote: The C preprocessor does not provide anything like the abilities of the Lisp macro system. For starters, C macros cannot perform environment capture, which means WITHLOCKEDSURFACE is unlikely to be hygienic. This is really why people wishing to see the benefits of Lisp need to go and do some learning - it''s no good producing syntactic similarities and assuming that the semantics are the same. For macros, the C preprocessor just expands the macros inline. That macro would come out to the *exact* code that was used in the first C example, and I don''t see any way you could break it. There is no need to ''capture'' the environment, the code is unrolled in-place before it is compiled, it would work just like I typed the original C routine. Perhaps they dont work exactly the same underneath as the Lisp macros; I would hope not, being as this is C, and that is Lisp. But in all likelihood, the outcome would be exactly the same. Results are what matter, not semantics. Peace ### #92Woodsman Members - Reputation: 426 Like Likes Like Posted 25 February 2004 - 03:43 AM quote: Original post by Krippy2k Results are what matter, not semantics. Exactly. But then you're using this as the only example of using Lisp and C macros towards an end which might lead you to make some erroneous assumptions about the power of lisp macros. Wicki has some length on macros though I'm not sure it's particularly helpful. [edited by - woodsman on February 25, 2004 10:51:33 AM] ### #93Krippy2k Members - Reputation: 134 Like Likes Like Posted 25 February 2004 - 04:02 AM I wasnt using it as an only example, that was just the only lisp example that has been given. I am certain that there are better examples, thats why I said I didnt think it was the best example At the rate I''m going I''ll get to the macros section in On Lisp in about oh.... 19 years... lol... just kidding, hopefully in a few months I''ll have a better grasp of it. I have so many things going on I can only commit a few hours a week to it. It would be nice if the various abstracts asserted in this thread hold water in the face of a real problem. Peace ### #94Vlion Members - Reputation: 151 Like Likes Like Posted 25 February 2004 - 05:08 AM Ya. Interesting thread, overall. I''m going to stop replying now. Anaphora, in linguistics: # In the following sequence, the relationship of the pronoun he to the noun phrase a well-dressed man is an example of anaphora: # A well-dressed man was speaking; he had a foreign accent. ### #95SabreMan Members - Reputation: 504 Like Likes Like Posted 25 February 2004 - 05:41 AM quote: Original post by Krippy2k For macros, the C preprocessor just expands the macros inline. That macro would come out to the *exact* code that was used in the first C example, and I don't see any way you could break it. There is no need to 'capture' the environment, the code is unrolled in-place before it is compiled, it would work just like I typed the original C routine. One problem is that, when a macro is expanded (not just the current example, but in general), you may be clashing with the local environment. To avoid this, you need to start employing token-pasting to implement an ad-hoc name-mangling scheme. The complexity of the macro goes up, and there is still not a firm guarantee that potential clashes are resolved. This danger also exists in Lisp, but there are mechanisms provided explicitly to avoid this danger. Another point is that the full power of Lisp is available within a macro, whereas C/C++ employ a limited language with a completely different syntax to the host language. quote: Perhaps they dont work exactly the same underneath as the Lisp macros; I would hope not, being as this is C, and that is Lisp. But in all likelihood, the outcome would be exactly the same. Only if you ignore the semantics. quote: Results are what matter, not semantics. Anyone who convinces themselves of this is walking a very risky path. This can lead to all manner of perverse rationalisations, such as it doesn't matter if the code is a mess, as long as it works''. It almost sounds like the Turing equivalency argument restated: my language can compute anything yours can''. This is not the point. We're having a debate about expressivity, which means it's exactly the semantics which are important. [edited by - SabreMan on February 25, 2004 12:43:37 PM] ### #96Predictor Members - Reputation: 198 Like Likes Like Posted 25 February 2004 - 06:32 AM It is my impression that many of the comments posted to this thread have to do with very local particulars of Lisp and its competitors (mostly C++), or with personal preferences, especially about flexibility of the programming languages. Qualitative arguments of this sort can be told in either direction (C's freedom vs. Pascal's constraint, or is that... C's anarchy vs. Pascal's order?). Personally, I am much more interested in productivity. How fast can programs be written? How fast/how big are the programs when executing? How complex/long is the resulting code? How bug-ridden are they likely to be? How maintainable are they? Such questions cannot be answered directly by appealing to personal taste. Having only been exposed to Lisp long ago, I found the Lisp adherents' comments here thought-provoking. I searched online for comparative studies (preferably with differences quantified) of Lisp vs. _____. Here are some of the things I found online: http://www.flownet.com/gat/papers/lisp-java.pdf http://userpages.umbc.edu/~bcorfm1/C++-vs-Lisp.html http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/msg00310.html http://www.paulgraham.com/paulgraham/avg.html -Predictor http://will.dwinnell.com [edited by - Predictor on February 25, 2004 1:36:23 PM] ### #97Neoshaman Members - Reputation: 170 Like Likes Like Posted 25 February 2004 - 06:45 AM i still have hard time with lisp and still a total noob but one things which blow me up is that i could write a program which could continue write himself and even auto debug, i''m not sure this could be done efficiently in other language i have see (but i''m not an expert, i''m an artist , i''m using programmation as an extansion tool of creation) >>>>>>>>>>>>>>> be good be evil but do it WELL >>>>>>>>>>>>>>> ### #98Krippy2k Members - Reputation: 134 Like Likes Like Posted 25 February 2004 - 06:47 AM quote: Anyone who convinces themselves of this is walking a very risky path. This can lead to all manner of perverse rationalisations, such as it doesn''t matter if the code is a mess, as long as it works''. It almost sounds like the Turing equivalency argument restated: my language can compute anything yours can''. This is not the point. We''re having a debate about expressivity, which means it''s exactly the semantics which are important. I think maybe we are in different debates I''m not having a debate about expressivity, I''m having a debate about power and usefulness. Semantics and expressivity are only useful to me if they help solve the problem more efficiently. More efficiently meaning efficiently developing the product to solve the problem. And if somebody is going to demonstrate that the semantics of a particular method are more useful than another method, more than just the interface needs to be presented. We can''t compare semantics based only on an interface. Peace ### #99SabreMan Members - Reputation: 504 Like Likes Like Posted 25 February 2004 - 09:21 AM quote: Original post by Krippy2k I think maybe we are in different debates Actually, you''re right. I thought I was in a different thread when I wrote that. Normally, I''d be paying closer attention! However, the comment about expressivity isn''t entirely irrelevant. If someone tries to show an example of the power of Lisp macros'''', what is implied is the expressivity of Lisp macros. That is, expressive power. It is easy to find something which achieves something equivalent in another language, but it''s the full semantics of the examples which are important. There''s a lot hidden in the Lisp macro examples which will not be apparent to someone who has not worked with Lisp, since Lisp macros really are unique. quote: I''m not having a debate about expressivity, I''m having a debate about power [...] What other power is there beyond expressive power? ### #100Nekhmet Members - Reputation: 132 Like Likes Like Posted 28 February 2004 - 08:10 AM I think I can explain this to all the C++ guys out there. Recently, I was doing some OpenGL programming. In OpenGL, to render, you first set the rendering state, like this: glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); etc Then, you call "glDrawElements" or "glDrawArrays" to render something. The rendering state consists of about a bazillion miscellaneous flags and parameters, so the actual amount of code needed to set up the rendering state can be quite large. Setting the rendering state can be slow on many implementations of OpenGL, so rather than just calling gldisable or glenable, it's important to wrap each piece of state-setting in a conditional: if (lighting_enabled) { glDisable(GL_LIGHTING); lighting_enabled = false; } If you accidentally forget to set up some part of the rendering state, the result is an extremely-hard-to-diagnose bug. For example, let's say I don't want the stencil buffer, but I forget to say: glDisable(GL_STENCIL_BUFFER); The result will be that every once in a blue moon, the image will be incomprehensibly missing or mangled, and no error message will be returned. This happens daily. There is so much opengl state that I almost always used to forget something, or used to configure some part incorrectly. Almost every time I wrote some new rendering code, it suffered from inexplicable artifacts until I found the bug in the state-setting code. The fact that this code was so verbose and so unreliable indicates that clearly, I wasn't expressing myself in the best possible way. So at some point, I asked myself, "what's the right way to express this?" The answer I came up with is: 1. There will be a list of rendering modes. Rendering will consist of picking one of the modes by name, and then rendering polygons. 2. When I use a rendering mode, it should completely override all previous state of the opengl pipeline. In other words, each rendering mode *completely* specifies the state, guaranteeing deterministic behavior. 3. When I activate a rendering mode, it should not alter parts of the opengl pipeline that are already configured correctly, for speed. 3. When I define a rendering mode, I shouldn't have to mention all the parts of the opengl pipeline, only the parts I'm using. The other parts should be implicitly disabled or set to reasonable defaults. The code I wrote reads in a configuration file that defines the rendering modes. The configuration file contains definitions like this: define SPRITE_PARAMETERS parameters mat$PROJ mat $MODV mat$CUBEM vecq $LIGHTPOS vecq$MSLIGHT vecq $MSEYE abgr$TINT abgr $LTINT parameters int$NVERT arr $VA arr$NA arr $TA arr$CA arr $SA int$NIDX arr $IA tex$TEX tex $BUMP enddefine mode sprite_glass_A0 SPRITE_PARAMETERS alphatest off blending standard zbuffer standard cull backfaces fragment arbfp10$TINT $LTINT TEMP t, tex0, diffuse, ndiffuse, brighter; PARAM scale = {4,2,1,0.5}; PARAM specpow = {0,0.333,0,0}; TEX tex0, fragment.texcoord[0], texture[0], 2D; DP3 t, tex0, specpow.yyyz; MUL t, t, program.env[1]; MAD tex0.rgb, program.env[1].a, t, tex0; MAD t, fragment.color.primary, scale.x, -scale.y; MOV_SAT diffuse, t.z; MOV_SAT ndiffuse, -t.z; SUB t,scale.z,tex0; MUL brighter,t,t; MUL brighter,brighter,t; SUB brighter,scale.z,brighter; MAD t,ndiffuse,-scale.w,scale.z; MUL tex0.rgb, tex0, t; LRP result.color, diffuse, brighter, tex0; MOV result.color.a, tex0.a; END colormask off vertex simple$PROJ $MODV data simple triangles$NVERT arr vtx $VA arr tex0$TA arr col $CA idx uint$NIDX $IA texture simple$TEX lin clod -0.5 mip wrap
endmode

This is a definition of the macro SPRITE_PARAMETERS, followed by a mode definition for rendering glass. As you can see, it doesn't mention the stencil buffer - implicitly, this rendering mode operates with the stencil buffer off.

The first lines of the mode are a list of parameters that must be passed into the rendering mode: a projection matrix, a modelview matrix, some light positions, some constant colors, some textures, and so forth. To actually render, you call the C function GscriptRender with the name of the mode, and the parameters to the rendering mode:

GscriptRender("sprite_glass_A0",
MatrixP, MatrixM, MatrixT,
lightpos, mslightvec, mseyevec, color, scenetint,
vcount, vertices, normals, texcoords, colors, scolors,
icount, indices, tex, bump);

The important thing about this notation is that it is error checked. The code that processes the mode definition makes sure that every piece of the OpenGL pipeline has been configured, and it does a few sanity checks for common inconsistencies.

This is the right notation for the job. My error rate has dropped to almost zero - when it was almost impossible to get things right before. I can add new rendering modes effortlessly.

To make it happen, though, I had to write a whole fricking compiler. I had to write a lexical analyzer, a parser, a macro preprocessor, parameter handling code, I had to create a "pcode" representation to store the compiled code in, and I had to write a pcode interpreter. It took a month.

In lisp, adding little languages is easy. In lisp, I could have written:

(define-rendering-mode sprite-glass-A0 (proj modv ...)
(alphatest off)
(blending standard)
(zbuffer standard)
etc...)

The construct "define-rendering-mode" would be a macro that would expand into a definition of a function, in this case, sprite-glass-A0. Since sprite-glass-A0 is a function in its own right, I wouldn't need the "GscriptRender" function that takes a variable number of arguments, instead, I'd call:

(sprite-glass-A0 proj modelview ...)

The amount of code needed would have been vastly less than in C++: Lisp already includes the parser, it already includes the macro preprocessor, it already implements the parameter handling, it already has a built-in "pcode" notation (lisp itself), it already includes a built-in pcode interpreter. The only thing I would actually have had to write would be the code to emit the opengl calls. This would have taken 2 or 3 days in Lisp.

In summary: "little languages" are an important programming tool. Lisp is specifically designed for extension with little languages, it includes all the features needed to add them easily. Having to write a whole compiler each time you want a little language discourages little languages, nearly eliminating a powerful tool from the programmer's toolbox.

[edited by - Nekhmet on February 28, 2004 3:29:35 PM]

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS