
Thank you pg and rtm - pogos
http://catdancer.github.com/thank-you.html
======
mahmud
and now for the anti-pandering anti-pattern ;-)

I can not believe for _once_ that this guy obtained hacking nirvana through
Arc. Not once! Why? because the Arc documentation is so meager as to be non-
existent. You will need serious feet-wetting with more established Lisp
dialects before you can "get there" with Arc.

All the epiphanies he lists are easily experienced with most modern Lisp
dialects; either he "got it" before and just needed to extend the credit to
Arc, for some reason .. or he isn't there yet, at least not to its full
potential.

It had to be said, as much as I hate to be rude and blunt like this :-|

~~~
pg
I have a lot of experience with Arc, Scheme, and Common Lisp, and I find Arc
significantly more pleasant to program in. When I have to shift into Scheme
(some parts of Arc are written in Scheme), it feels like there is a lot of
extra drag.

It was noticing this difference that made me decide Arc was ready to release.
If it (a) felt significantly better to me, who (b) am experienced with
existing Lisp dialects, and (c) writing a type of application (HN) that's not
wildly specialized, then it had the "quantum of utility" I usually use as the
test for releasing a version 1.

~~~
mahmud
Paul, you're fit to prefer Arc over the rest because: 1) you're an experienced
Lisper, and 2) it's your own creation, you know it inside and out and the
language spec, manual, tutorial and research papers are somewhere between your
ears (the most convenient type of bookshelf ;-)

However, it's IMO, unacceptable for a fairly new Lisp programmer to cast aside
50 years of Lisp research, development and deployment while brushing aside the
industry's backbone languages, and herald Arc as the best thing ever when it
isn't even finished.

I can accept personal choice and opinion, if kept to one's self and made in
private. Even if someone sings Arc, or Clojure or Common Lisp or Scheme,
praises, I am fine with it. But to say "Languages X, Y, Z suck because they
don't allow me to write succinct programs", well, you're just trolling for X,
Y and Z programmers to come out and straighten you out. The sort of macrology
he is after (code-compacting type, not language extension) is pretty basic and
could be done with the C pre-processor and M4. You can even write compact
_assembly_ programs with GASP, HLA, and NASM macros; it's not rocket science.

I reserve my judgment for Arc until it's done. There is no manual yet to hold
the compiler accountable, and to save me from guess-work. However, what I
can't ignore is blind fanboyism; if everybody here sang Arc praises, when it
is just arc-tutorial.txt and arc.arc, and there were no "dissenting" honest
voices, well, the place just wouldn't be the same.

~~~
scott_s
I think you're being unnecessarily argumentative in this discussion. The
author likes Arc, feel is makes him more productive, and he wanted to share
that with the community.

He did not say other languages suck. What he said was he prefers Arc over
those languages, and explained why.

~~~
mahmud
I realized that pretty much by now. I had a WTF moment earlier and wished I
had spent those few hours I spent on this thread doing something else.

Lesson learned. Modded you up for the truth. Thank you :-)

------
CatDancer
OK, I have a HN etiquette question. I don't post much on HN, and I wasn't the
one who posted the link to my thank-you here on HN. I've had a HN account for
a while, but I'm still pretty much a newbie to HN.

I have a desire to not just stand here and take it on the chin as mahmud
publicly proclaims that I'm pandering, a Lisp newbie, irrational, a blind
fanboy, hypocritical, dismissive, and unfair. On the other hand I don't want
to waste everyone's time with a tedious flamewar.

Thoughts?

~~~
pg
He was surprisingly nasty about it, but I wouldn't bother fighting back. A lot
of the people who voted up his comment didn't do it because they agreed with
him so much as because they're worried you'll start a trend of people posting
stuff trying to suck up to us. Which is actually a reasonable thing to worry
about, considering that a significant number of HN users think they might one
day apply to YC. So you were basically just unlucky.

------
markessien
I understand what the guy is saying, but this is equivalent to art students
discussing the technicality and construction of canvases. Even if you select
the best canvas in the world, it does not make your painting better.

I think that too much of writing about programming is focused on the details
of the programming act, and too little on the result of the programming.

Reading about finding and learning a programming language is like reading
about an artist choosing a brush. Reading about the technical details of
someone scaling a Django app on a single server to serve 1000 concurrent
requests per second is like seeing the finished artwork.

~~~
anc2020
> Reading about finding and learning a programming language is like reading
> about an artist choosing a brush.

Wands are a much better metaphor to make. Or perhaps, what if you had a magic
brush that could at any time be extremely fine or large or anywhere in between
depending on how you felt? That would be some brush, especially when you
compare it to the many medium sized brushes which aren't so fine when you need
them to be.

Okay, so maybe the metaphor is still stretching a bit, but these are no
ordinary brushes; they are worth writing about.

------
axod
>> "The second half of the book is how to apply the principles to Java code.
Which is horrendous! Not the book. If you should be so unfortunate to be stuck
trying to write good code in Java, the book is a great, lucid description of
how to do so. Yet in Java, it’s hard to get anything shorter than ten or
twenty lines of code. See some code duplication, and by the time you’ve
written the classes and interfaces and methods you need to write to remove the
duplication, the code is just as long as it was before."

Yeah you're doing something wrong there. I know it's fashionable to bash Java
and say how lame and verbose it is, but it does wear a bit thin. I actually
enjoy writing Java. Perhaps due to me having grown up programming assembly - I
don't mind verbosity. Java is an extremely solid fast language.

~~~
abstractbill
_Java is an extremely solid fast language._

You mean "the JVM is an extremely solid fast _runtime_ " - languages by
themselves aren't fast or slow ;-)

~~~
axod
Right - Java as a word is heavily overloaded ;). For me, that's the bit that
matters - the JVM. Java is just something I use because it's easier than
writing bytecode :/

Java as a language, the syntax, is for me sane. It gets a lot of things right,
and some things wrong, but on balance, it's sane enough to use. Just like
English as a language is sane enough to use, whilst having lots of stupid
inconsistencies in spelling/pronunciation etc.

And it's likely to be the fastest/most optimized of any JVM target language.

------
pg
We're releasing a new version quite soon. So once again, if there's anything
you want fixed, now is the time to tell us.

<http://arclanguage.org/item?id=9257>

One of the things I want to add next is graphics libraries. Does anyone have
any recommendations for what to plug into to munge images?

~~~
crescendo
_Does anyone have any recommendations for what to plug into to munge images?_

ImageMagick (<http://www.imagemagick.org/>) has worked well for us. There are
bindings out there for many languages, including Common Lisp (<http://common-
lisp.net/project/cl-magick/>); you might want to look there for inspiration.

~~~
pg
We used ImageMagick to manipulate images in Viaweb. So if it's still the best
thing around now, 14 years later, it must be pretty good. Thanks!

------
jmatt
If we're going to be thanking people...

Thanks Anarki and arcfn.com!*

They were both tremendously useful/helpful when I last used arc.

*All creators and contributors.

------
stcredzero
From what this guy is saying, the power of Lisp style Macros is akin to what I
can do with the syntactic Rewrite Tool and Blocks (Lambdas) in Smalltalk. I've
always been led to believe that Lisp Macros are something even more powerful.
(I haven't had the time to really delve into them.)

~~~
jimbokun
Yes, there was a recent article on HN about "your language features are my
libraries."

[http://blog.bitquabit.com/2009/05/20/your-language-
features-...](http://blog.bitquabit.com/2009/05/20/your-language-features-are-
my-libraries/)

That was comparing Smalltalk to C#, but it is a similar idea. Smalltalk and
Lisp belong to that elite fraternity of programming languages where the
ability to easily extend the syntax is built into the language. The mechanisms
are different, but the expressive power is similar.

~~~
stcredzero
Well, I've heard that Blocks get you most of the way to Macros, but not quite.
I'm wondering if the "not quite" part is something beyond what's afforded by
the Rewrite Tool.

The Rewrite Tool is not dynamic. Perhaps this is the key? But I could imagine
a Smalltalk function that takes a method, applies a Rewrite Tool syntactic
transformation to its source, compiles the method as a Block, then calls this
Block with the arguments that would've been send to the original method.

Something like:

    
    
        perform: methodName 
        with: arguments
        rewriting: aMatchingPattern
        as: aRewritePattern
    

Where aMatchingPattern would be something like:

    
    
        ``@rcv
            ifTrue: `Block1
            ifFalse: `Block2
    

Then aRewritePattern could be something like:

    
    
        "Order of Blocks reversed"
    
        ``@rcv
            ifTrue: `Block2
            ifFalse: `Block1 
    

Just be careful to cache the result of the compilation by method name and
Class, and this wouldn't be too much slower than a conventional #perform:

This particular example would let you dynamically call any method, but with
all of the if-then-else equivalents with the then and else clauses swapped.

Would this constitute Smalltalk Macros?

~~~
jimbokun
"I could imagine a Smalltalk function that takes a method, applies a Rewrite
Tool syntactic transformation to its source, compiles the method as a Block,
then calls this Block with the arguments that would've been send to the
original method."

I don't understand what you said, but in non-hygenic Lisp macros (the kind you
get in CL, Arc, and Clojure) a macro is simply a function that expands into
code before being compiled or evaluated. You can almost think of it as an
extremely clever query-replace functionality in your text editor that always
happens before you compile or run your program.

This is why so many Lispers claim that Lisp is at the top of the heap when it
comes to language power. If you can arbitrarily expand your code into some
other form at compile time, you can pretty much do anything any other language
can do. A canonical example of this is that the object system added to Common
Lisp is just a bunch of macros. Name your programming paradigm, and there's a
very good chance someone has implemented it in Lisp, with macros.

What you describe sounds more complex than Lisp macros, which brings us to the
necessity of all the parentheses. The idea of macros only works well when the
language is built up out of a data-structure supported by the language. In
Lisp, of course, programs are lists and macros let you do anything to your
program that you can do to a list. When people try to add "macros" to
languages where the code is not a data structure, there usually needs to be
some intermediate representation of the parse tree, and then things tend to
start getting ugly as the relation to what the source code would look like is
quickly lost.

Having said all that, I'm curious if anyone that knows both Smalltalk and Lisp
can name concrete examples of programming in Smalltalk and finding something
you were unable to do without macros.

~~~
stcredzero
The Rewrite Tool meta-syntax allows you to do a few nifty things. It is also
"an extremely clever query-replace functionality" and in the scheme I
proposed, you could "decorate" a function, such that a transformed version is
called at runtime.

The Rewrite Tool also gives you access to the Smalltalk Parse Tree, though
this isn't quite as pretty as Lisp's. However, you can very easily apply a
Visitor to your AST. Perhaps even better, there's also a { : ... } syntax for
executing arbitrary Smalltalk code to do your transform.

 _which brings us to the necessity of all the parentheses_

Yes, Lisp is it's own AST! That's amazingly brilliant! Makes software
toolsmithing equivalent to just plain programming.

------
jpedrosa
Hi. My experience lies in Ruby and in JavaScript (these days) so I can see
these worlds however close, differently. In Ruby I have all kinds of gimmicks
that help with cutting the chase when that's what I want, but I also can make
it a little harder when I am interested in something else, in experimenting
with some other approach.

What I find a little disgusting is when my "meta-programming" in Ruby starts
doing things like when an exception occurs, it points to a line number
slightly different than where it really is, or when the backtrace becomes all
the more "hacked" with harder to understand things thrown in there. It serves
to remind us that there are tradeoffs involved. Also there is the issue
creating shareable modules and when you start hacking it away it can make it
all the more harder to share. But it's more than fun, it does work, it's just
that one can have mixed feelings because for ever cool finding or development,
there can exist a little nuisance as well or something that you cannot quite
do anymore because you deviated from mainstream...

I gotta go have lunch!

Be well.

------
jcl
I'd love to hear what the difference is between arc macros and scheme hygenic
macros that makes one effortless and the other unhelpful.

~~~
abstractbill
I haven't used arc in a while, but if I remember correctly it has a Common
Lisp style defmacro that anyone can figure out:

    
    
      (defmacro foo (args go here) `(code goes ,here))
    

On the other hand, Scheme has this monstrosity for defining macros that I
can't describe because I never managed to keep straight in my head how it was
supposed to work.

Hygiene is a red-herring. It's easy enough to achieve with a defmacro-style
macro system - just use gensyms.

~~~
shiro
Ah, this has been repeated many times, but I can't help to click "reply"...

> It's easy enough to achieve with a defmacro-style macro system - just use
> gensyms.

Gensym cannot prevent global identifiers from being shadowed in macro use
environment.

    
    
        (define-macro (my-if a b c) `(if ,a ,b ,c))
    
        (define (boo)
          (let ((if list))      ; if is shadowed
            (my-if 'x 'y 'z)))  ; evaluates to (x y z), not y  
    

In CL you don't need to worry much, since (a) it is Lisp-2 so variables won't
shadow operators, and (b) using packages greatly reduces accidental shadowing.
In Scheme the chance is much higher; you probably don't bind 'if' locally, but
you can't check every user-defined global procedures the macro inserts into
the output.

~~~
anc2020
It is unfortunate for abstractbill to use this incorrect explanation, because
hygienic macros are still a red herring - a decent module system and a bit of
restraint gets you there.

    
    
        (define-macro (my-if a b c) `(std.if ,a ,b ,c))
    
        (define (boo)
          (let ((if list))      ; if is shadowed
            (my-if 'x 'y 'z)))  ; gives (std.if x y z)  
    
        (define (boo2)
          (let ((std.if list))  ; error! cannot shadow module vars.
            (my-if 'x 'y 'z)))
    

I've posted this around a few times asking why this isn't already used in
Lisps and never seem to get a convincing argument back. The only conclusion I
can draw from this is that CL-ers are ashamed of the fact that multiple
namespaces aren't actually necessary and Schemers are rightly ashamed of
hygienic macros. Please convincingly prove me wrong!

(ps. This ofcourse would not be limited to the languages std module but would
also apply to any exported module symbols.)

~~~
shiro
That's exactly what I meant in "In CL ... (b) using packages greatly reduces
accidental shadowing." So I'm not sure what you are asking to be convinced. CL
certainly does not prevent you from messing with package-private symbols, but
usually a convention is enough to avoid disaster. I mean, I won't write (let
((your-package::private-symbol list)) (your-macro ...) ...) unless there's
absolute need to do, such as emergency workaround of a bug in a third-party
library.

On the other hand, one of the reasons Scheme avoids explicit module prefix is,
I think, that it breaks abstraction. Suppose my-module defines my-macro and
my-function. My-macro expands into a call to my-function. But I don't really
want my module users to call my-function directly, so I only export my-macro
and keep my-function private.

In your proposal, my-macro will expands into prefixed-symbol like this:

    
    
        (define-macro (my-macro arg)   `(my-module.my-function ,arg))
    

But... if we allow module-private function to be called with module prefix, we
can't prevent ordinary code from calling my-function as well.

This is a language design choice. Some may not mind others to mess with
module-private bindings; CLers certainly would not. But _if_ you want to hide
module-private symbols, _and_ want to allow macros expand into them, how will
you do that? One idea is to mark the output of macro expansion so that the
compiler can distinguish whether the reference is from legitimate macro
expansion or not... well, that's what hygienic macro is doing.

~~~
anc2020
Thanks for the explanation. I hadn't thought of the my-macro problem because I
tend to think of macros exactly as a clever copy paste mechanism, so would
expect it to always use public variables, but I guess some people might have a
problem with that in some cases.

In the first point I was asking to be convinced that you can't have hygiene
solely through the use of a package / module system and without needing
multiple namespaces.

Although your workaround argument (for allowing variables to be shadowed) is
convincing, in that case the package system wouldn't really be providing any
safety at all and only the convention would be helping. I guess we can sum it
up as CLers really don't see a problem at all, and Schemers require macros to
be completely abstract.

------
10ren
_First I figure out how to do what I need to do, then I translate that into
the constructs of the language, then I try it and it doesn’t work, and then I
debug or figure it out :-)._

It's a wonderful thing to have a language that matches how you think, an
extension of your mind analogous to how physical tools can be an extension of
your body, with a heft, weight and balance that causes them to leap to hand,
and guide you at times.

But my particular tasks at the moment involve so much more work at the drawing
board (the _figuring_ stage) that having better tools doesn't actually help me
- much as I would love them to.

It's very true that the tools you need depend on your personal way of
thinking, the task, the stage of the task, and how many times you've done it.

------
wingo
It's funny, just today I finished up some work merging a hygienic expander
into the core of Guile. I've been writing defmacros for a few years now, and
while things are not all lovely in the world of syntax-rules or syntax-case,
it is so much more lovely to write a macro that you know catches the important
cases, and that will compose well with other code, and /especially/ code from
other modules.

That said, have fun with Arc ;-)

