News for hackers. Stuff that matters.
Re:How Lisp macros differ from static code-generation and me... by funptr on Wednesday January 26, 2011 @02:05PM (#2144540)
C99 + GCC extensions + POSIX:

  #define for_duration(seconds, body)                     \
    {                                                     \
      pthread_t tid_task, tid_watcher;                    \
                                                          \
      void* task(void* arg) {                             \
        body ;                                            \
        pthread_cancel(tid_watcher);                      \
        return NULL;                                      \
      }                                                   \
                                                          \
      void* watcher(void* arg) {                          \
        sleep((seconds));                                 \
        pthread_cancel(tid_task);                         \
        return NULL;                                      \
      }                                                   \
                                                          \
      pthread_create(&tid_task, NULL, &task, NULL);       \
      pthread_create(&tid_watcher, NULL, &watcher, NULL); \
      pthread_join(tid_task, NULL);                       \
    }                             
Use as:

  for_duration(10, {
      while (true) {
        printf("Infinite loop! where is your Godel now?\n");
      }
    });
  
Or with single brace-less statements:

  for_duration(10, while (true) printf("something\n") );
  
Lexical scope is sane:

  int i = 0;
  for_duration(10, {
      while (true) {
        printf("%d\n", i++);
      }
    });
My comparison isn't quite fair, because your threading library provides 'with-timeout', while pthreads doesn't. If you factored this out, say with a signature like:

  void with_timeout(unsigned int seconds, void (*func)(void));
(in analogy to the common lisp function), then the macro part becomes just four lines:

  #define for_duration(seconds, body) {			\
    void func() { body ; }				\
    with_timeout((seconds), &func);			\
  }
I acknowledge that the lisp solution is rather more elegant. Also, my C macro is potentially dangerous because it is unhygenic. (It shadows outer declarations of 'task()', 'watcher()', 'tid_task', 'tid_watcher', and 'arg', in the body of 'body'.)
Re:How Lisp macros differ from static code-generation and me... by Xurinos on Wednesday January 26, 2011 @03:07PM (#2144880)
Is there a C macro that can do this?

    (defmacro execute-in-reverse (&body body)
      `(progn ,@(reverse body)))

    (execute-in-reverse (print "Hi") (print "Middle") (print "Bye"))
Prints...

    "Bye"
    "Middle"
    "Hi"
Point: You can do whatever you want with the symbols sent to the macro, whatever their contents. Mahmud's wrapper macro is trivial (it could be done with lambdas). Lisp's macro system allows you to create new syntax, including changes in flow control.

But my example is trivial, too. I could go on to swap individual parts of my forms around, remap them to other forms depending on various conditions, etc.

In addition, people often talk about Lisp macros, but they neglect to mention the power of reader macros, which allow you to go beyond Lisp's basic AST look-and-feel.

Re:How Lisp macros differ from static code-generation and me... by funptr on Wednesday January 26, 2011 @03:25PM (#2144979)
>Is there a C macro that can do this?

No, of course. C macros only see strings; you need to parse a syntax tree to do your reverse example (like lisp macros).

No argument from me.

>Lisp's macro system allows you to create new syntax, including changes in flow control.

Well, C macros seem to be able to manipulate control flow. You can't break up an expression to do that (not smart enough to parse), but you can rearrange expressions that are given whole.

Re:How Lisp macros differ from static code-generation and me... by draegtun on Sunday January 30, 2011 @08:02AM (#2157961)
Wonderful example of what macros can do.

Just for shit & giggles I'd thought I give it a go in Io (http://www.iolanguage.com):

    executeInReverse := method (
        m     := call argAt(0)
        stmts := list()              // list of statements (ie. messages)
    
        loop (
            rest := m next           // rest of messages after current 
            stmts append(m setNext)  // get current message
            m := rest
            if (m == nil, break)     // exhausted statements when "nil"
        )

        stmts reverseForeach (n, doMessage(n))
    )

    executeInReverse( writeln("Hi") writeln("Middle") writeln("Bye") )
And I think with a bit more work I can get it to amend its AST rather than rerunning the loop each time it sees executeInReverse.
Re:How Lisp macros differ from static code-generation and me... by chc on Wednesday January 26, 2011 @02:42PM (#2144737)
I don't believe nested functions like you're using there are valid C. They're a nonstandard extension that some compilers implement because they're so handy. So this basically illustrates that C gets closer Lisp's usability when you add Lispy features to it.
Re:How Lisp macros differ from static code-generation and me... by funptr on Wednesday January 26, 2011 @02:55PM (#2144814)
You're right, it's not even valid C99. My mistake.
Re:How Lisp macros differ from static code-generation and me... by sedachv on Wednesday January 26, 2011 @04:10PM (#2145157)
GCC extensions make me want to hurt people.