Pascal said:
You are so confused! The macros are not expanded by the editor!
Eh. That wasn't my interpretation of the OP's post. He was responding to
this:
"Macros are not a source of headaches in CL because they are most times
as simple as a normal function. And you can always expand the code
directly from the source (by hitting a small sequence of keystrokes) if
you thing it has a bug somewhere."
where someone said if he suspected a macro was buggy he'd type something
in his IDE that would cause the macro to be expanded in-place.
Series is pointing out that if he then went off to fix the bug in the
macro, but forgot to return to that other part of the code to change the
expanded code back into a macro call, then there's two copies of the
macro code -- the macro, and the one particular application of it that
was replaced in the code editor with its expansion pre-compilation.
As I understand it, he's saying the compiler still expands the macro at
all its other usage sites.
The C equivalent (I'm more familiar with C than Lisp) would be:
You have
#define DOIT(x,y) ((x)+(y)+(y))
Later you find a bug at
DOIT(a,b++)
where b is getting incremented twice instead of once.
You do whatever it is and the code there changes to
((a) + (b++) + (b++))
and realize why b is being incremented twice. You remove the "++" from
the first "b" and then zip back up to the top of the file to change the
macro definition to:
#define DOIT(x,y) ((x)+2*(y))
feeling secure in the knowledge that everything used with DOIT can be
multiplied by two (there's no string "+" concatenation operator in C).
Later, there's a decision made to change it to ((x)+3*(y)). In most
locations in the code where it "does it", the compiler dutifully expands
DOIT(foo,bar) into ((foo)+3*(bar)).
But in one lonely spot the code still reads ((a) + (b) + (b++)).
So b is still multiplied by two, instead of three, there.
Bit of a contrived example? Maybe. But I think this is what Series was
getting at. Maybe he's misunderstanding something somewhere, but I think
you definitely are.
The only thing you have to do when you change a macro, is to recompile
the functions that use it. This is easily done automatically by
putting macros in a separate source file and defining correctly the
dependencies of the other files.
In the practical software development world, we have long since adopted
tools that track dependencies for us more or less automatically (Java
has the niggling "public static final field problem" though). Your
manual tracking of dependencies would not scale to a real-world
productive code shop in a major company or major open source project.
"Go to definition" can be implemented using classical tags, like for any
other programming language.
We NetBeans users don't have to implement it at all, nor worry our heads
about editor internals like "classical tags" (whatever those are). We
just right click and away we go, without any mess or fuss.
Getting the documentation and seeing the expansions are primitive
feature of the Common Lisp language. Trivial.
There are two problems with this statement. First, getting the
documentation seems to presuppose there is some. I've seen a fair bit of
Lisp code in my time, but never has any piece of it had anything
recognizable as some kind of doc comment attached to it. If there is any
documentation, it apparently has to be searched manually, and being
maintained separately from the source code, is liable to be out of synch
with the codebase at any given time.
Second, as Series was trying to point out (but you misunderstood), the
command to expand the macro in-place, when used to simply see how it
expands in a particular place, has the side effect of actually modifying
the source code in the editor. If that modification is saved, the macro
expansion is now "baked in" at that one location, and won't reflect
future changes to the macro's definition. So things once again drift out
of synch.
Series noted that a hypothetical NetBeans-like IDE for Lisp would have
the capability, unlike a text editor, to show the results of the
expansion in some sort of pop-over or tooltip or balloon help instead of
having only one place to put it, in the source code itself. As a result,
one could have a "view what this looks like expanded" command that was
actually a non-modifying operation, instead of having to (ab)use the
modifying operation "replace this macro call with its expansion"
(preferably immediately followed by "undo"!) to achieve the desired effect.
I'll note though that the implied lack of such an IDE is not inherently
a problem with the Lisp language itself; one could be written. A
NetBeans plugin could probably even be written. Or an Eclipse one for
people that swing that way.
There's no need for an IDE.
Spoken like someone who's never had to do any REAL programming.
So it's rather trivial to have a simple editor like emacs (or
even simplier) to get the documentation of lisp operators or to expand
a macro.
"Rather trivial" if you like to spend as much time or more programming
the editor as you do actually programming what you're being paid to
program -- and your boss likes you dividing your time that way, too.
Oh, and making mistakes by using "replace this macro call with its
expansion" but forgetting the subsequent "undo", which mistake silently
cause no symptoms until days, weeks, or even years in the future when
the macro definition is changed and something suddenly doesn't quite
work right, and after tearing your hair out for hours you still can't
find any error in the new macro definition, never suspecting that the
error lies somewhere else entirely because the macro definition is the
only recent change.
Why would we do that? That would mean shooting in one's foot. Nobody
would do that.
Apparently, the person Series was responding to would do that.
That person seems to go by the name "gugamilare". If you'd like to tell
him what a horrible kludge it is to use "replace macro with expansion"
as a poor-man's "view this macro call's expansion" due to lack of a
graphical IDE, well, go right on ahead. I wholeheartedly agree with that
sentiment.
In really, such a mission-critical system was developed by Paul
Graham, and sold to Yahoo for a fortune, which used it without such a
catastrophe.
http://lib.store.yahoo.net/lib/paulgraham/bbnexcerpts.txt
Somehow, I doubt Yahoo abandoned all their change-management and
version-control practises and just started hacking on their servers
while they were live. If they'd done that, Series is right about the
likely outcome: some sort of at least downtime, if not a big data loss
or other disaster.
Another example, is the debugging of the OS code of the Deep Space 1
code when it was millions of kilometers from the Earth. Again, the
modifications were made on a running program without outage, and even
without physical access to computer.
That's a rather unusual, special case. Also, I expect they did this
while it was coasting in the vastness of space, so nothing could go too
horribly wrong too quickly so long as they didn't render it unable to
receive and execute commands or become unbootable.
They were also probably very careful indeed; I expect they tested their
changes in a simulator of some sort groundside before beaming any code
modifications to the probe. NASA doesn't take the preservation of
multi-billion-dollar machinery lightly, I expect.
Well probably lisp programmers are smarter. For sure you make us
think so. Is it so hard a concept to make the modifications both in
the running lisp image and in some persistent storage?
Well, now you're making changes in two places at once. Better not forget
one, or make slightly different changes to both.
This is actually the normal work flow of a lisp programmer: he will
edit the source file in emacs, type C-x C-b which will ask slime to
send the file to the running lisp image, which updates it.
Who are you calling slime, ooze?
But if you are editing the source file and then copying the changes to
the running image, that's a bit better since they shouldn't get out of
synch nor any changes be lost. Gugamilare apparently told Series he just
edits the running image and where it stops, no-one knows.
The stuff Series said about keeping separate testing and production
systems, only hacking on the former, and having some sort of version
control seems to stand though. Editing text files on disk does not scale
up to a major software project's development practises; you'll spend
more time using the command line to check in and check out than you
spend editing, testing, or compiling anything. NetBeans provides
integration with multiple widely-used version control systems, by
contrast -- you can edit the file and save it and it can more or less
transparently commit the changes to the repository, maybe prompting you
for a change summary, as well as check out files you browse to.
Meanwhile browsing a manually-maintained mirror on your hard drive means
sometimes seeing code that's out of date, if you forget to re-checkin a
file you haven't viewed in a while.
NetBeans also provides an internal, lightweight version control system
that can recall or undo the changes to a local codebase over the past
week or so. It also can show you diffs of your recent changes in an
easy-to-read way. Quite handy, actually, and way beyond the capabilities
of a mere text editor. Particularly, the NetBeans diff-viewer could
never be even approximated in a text console no matter how fancy you got
with ncurses. You can see at a glance corresponding parts of both
versions, highlighted to indicate what corresponds, what's inserted,
what's removed, and everything, even around parts that have gotten a
fair bit longer or shorter. Lines marking corresponding bits may be
diagonal, at angles you could never manage using /-\|. And it's
*stretchy* in a way that no rigid grid of letters and numbers could ever
be.
