wxPython and macros (was: Why don't people like lisp?

M

mike420

Tayss said:
app = wxPySimpleApp()
frame = MainWindow(None, -1, "A window")
frame.Show(True)
app.MainLoop()

Why do you need a macro for that? Why don't you just write

def start_window(name) :
app = wxPySimpleApp()
frame = MainWindow(None, -1, name)
frame.Show(True)
app.MainLoop()
return (app, frame)

Macros are used for other things!

With this function, you can do

app, frame = start_window("a window")
app.do_stuff()
frame.do_whatever()

With a "macro" (if Python had them), you could define
with_open_window(name), and do

with_open_window("a window")
app.do_stuff()
frame.do_whatever()

Conclusion: you don't need macros here.
Moral: maybe you do not *deserve* macros.
 
K

Kenny Tilton

Tayss wrote:




Why do you need a macro for that? Why don't you just write

def start_window(name) :
app = wxPySimpleApp()
frame = MainWindow(None, -1, name)
frame.Show(True)
app.MainLoop()
return (app, frame)

Macros are used for other things!

With this function, you can do

app, frame = start_window("a window")
app.do_stuff()
frame.do_whatever()

With a "macro" (if Python had them), you could define
with_open_window(name), and do

with_open_window("a window")
app.do_stuff()
frame.do_whatever()

Conclusion: you don't need macros here.
Moral: maybe you do not *deserve* macros.

They are unworthy? :)

You know, I'll say it again, considering the audience (Pythonistas
debating amongst themselves whether to have macros) Lispniks should have
emphasized from the get-go that one of the things macros do is clean up
code visually (as demonstrated above). Some think I over-use macros, but
I think I do so precisely because, like Pythonistas, I place a premium
on visually clean code.

If you go here:

http://alu.cliki.net/RtL Highlight Film

....and read the subsection "Power Hungry" you would think macros are
there just for the expressive power. That's true about the power, but
what is strange is that the response by some here has been "I can do
that with an HOF or a metaclass! OK, it's a little messy, but...".

The problem is, they are precisely right! In fact, many a groovy:

(with-groove-on (x y z) (do-your-ting))

expands directly into :

(call-with-groove-on (lambda (x) (do-your-ting))
:eek:ption-a y :eek:ption-b z)

Me, I am not as smart as some Lispniks, and I find that visual clutter
makes it hard for me to read even my own code. I am a pathological slob
in all aspects of my life, but when it comes to code I switch from Oscar
to Felix (obscure "Odd Couple" reference). If code does not look
aerodynamically efficient I shave down the corners, with a macro if I
know the rough bit is such a key part of the framework I am building
that it will appear in dozens or hundreds of places.

Now one very good point is that macros are a big change to make an
already clean-looking language cleaner. ie, The added value may not be
so great in Python as in other languages because another way
(indentation) was found to clean up code (and in my experience the
improvement is dramatic.

It will be interesting to see if Pythonistas can clean up your wxPython
example using existing Python capabilities.

If so, ok, /now/ we can argue about whether Paul Graham is right when he
says that some things can only be done with a macro:

http://www.paulgraham.com/onlisp.html

:)

kenny the sophist
 
B

Brian Kelley

Kenny said:
They are unworthy? :)

You know, I'll say it again, considering the audience (Pythonistas
debating amongst themselves whether to have macros) Lispniks should have
emphasized from the get-go that one of the things macros do is clean up
code visually (as demonstrated above). Some think I over-use macros, but
I think I do so precisely because, like Pythonistas, I place a premium
on visually clean code.

Now one very good point is that macros are a big change to make an
already clean-looking language cleaner. ie, The added value may not be
so great in Python as in other languages because another way
(indentation) was found to clean up code (and in my experience the
improvement is dramatic.

After debating this topic, I have a slightly better understanding of how
I would use macros if they existed in python. My thinking is pretty
much dealing with book-keeping and resource handling.

Specifially talking about wxPython, in some class constructors, any non
handled exception (in, for example, wxFrame) can crash the application
with no tracebacks. Additionally, when subclassing some wxPython
classes, the base class *must* be called first. These issues could be
solved with macros in a perhaps clean fashion. Naturally, you don't
*need* them, but they do reduce book-keeping and visual clutter in my
opinion.

class wxFrame:
def __init__(self, ...):
with wxFrame_init(self, ...):
special constructor code here


as opposed to

class wxFrame:
def __init__(self, ...):
wxFrame.__init__(self, arguments)
try:
special constructor code here
except ...:
# handle errors, perhaps writing to a log
# close down the application with an appropriate
# error message

Perhaps I have become converted :) I also think that this could fit in
nicely to the python environment. Much more than I would have before.
I wouldn't use macros to change the language, but to provide fail-safe
handling for common tasks, sort of why I wanted to use python in the
first place.

Brian
 
K

Kenny Tilton

Brian said:
After debating this topic, I have a slightly better understanding of how
I would use macros if they existed in python. My thinking is pretty
much dealing with book-keeping and resource handling.

Specifially talking about wxPython, in some class constructors, any non
handled exception (in, for example, wxFrame) can crash the application
with no tracebacks. Additionally, when subclassing some wxPython
classes, the base class *must* be called first. These issues could be
solved with macros in a perhaps clean fashion. Naturally, you don't
*need* them, but they do reduce book-keeping and visual clutter in my
opinion.

class wxFrame:
def __init__(self, ...):
with wxFrame_init(self, ...):
special constructor code here


as opposed to

class wxFrame:
def __init__(self, ...):
wxFrame.__init__(self, arguments)
try:
special constructor code here
except ...:
# handle errors, perhaps writing to a log
# close down the application with an appropriate
# error message

Is the above meant to be for, say, wxFrame3D, a subclass of wxFrame?

Anyway...Yep. Any time there is boilerplate code one can slap it into a
macro. In the end only the bit that is different gets coded, so it
stands out more clearly and code is easier to read.

Now the million dollar question is: how could the longer version above
be cleaned up without macros, with HOFs or a metaclass hack or something?

kenny

--
http://tilton-technology.com

Why Lisp?...

http://alu.cliki.net/RtL Highlight Film
 
P

Pascal Costanza

Brian said:
After debating this topic, I have a slightly better understanding of how
I would use macros if they existed in python. My thinking is pretty
much dealing with book-keeping and resource handling.

Specifially talking about wxPython, in some class constructors, any non
handled exception (in, for example, wxFrame) can crash the application
with no tracebacks. Additionally, when subclassing some wxPython
classes, the base class *must* be called first. These issues could be
solved with macros in a perhaps clean fashion. Naturally, you don't
*need* them, but they do reduce book-keeping and visual clutter in my
opinion.

Yes, exactly! :)
Perhaps I have become converted :) I also think that this could fit in
nicely to the python environment. Much more than I would have before. I
wouldn't use macros to change the language, but to provide fail-safe
handling for common tasks, sort of why I wanted to use python in the
first place.

Well, but that's exactly what language design is all about.

Consider the following two functions that both do the same thing:

(defun example-1 (x)
(let ((i 0))
(tagbody
:loop
(when (> i x) (go :end))
(print i)
(incf i)
(go :loop)
:end)))

(defun example-2 (x)
(loop for i from 0 to x
do (print i)))

EXAMPLE-1 requires lots of book-keeping in your head, especially when
things get messier. EXAMPLE-2 uses a for loop "just" to reduce
book-keeping and visual clutter. ;)


Pascal
 
T

Tayss

Whoa, I bow to your ability to start endless threads.

I just started drinking something when I came across this, so let me
just recap a few things, because I sense you pushed me out of context:
- Lulu inspired me to think about the nature of languages, and I
thought it was worth pointing out that frameworks were like verbose
languages. So it's not like macros are the unique evil.

- Any well-designed language with macros will have tools to help you
deal with them. Macros are after all just another tool to help you
manage complexity.

- My audience was those curious few following the thread, not the
Pythonista skimming usenet for good tips on daily work. So I'm kinda
wondering if they're angry all these threads are shoved in their
faces. I'm not out to convince, just entertain thoughts.

- I experiment. Python/wxPython was the right choice for the project,
but sometimes the soul aches for Lisp's ability to bend reality. With
Python, I can often shorten distances while running. With Lisp, I can
make reality seep into cracks and bend it around me. Maybe that's the
alcohol talking.

So when I'm coding along and a framework rubs up against me and I
wonder if it's not so maintainable, I start considering whether
there's a way to fix things. I spend a couple minutes looking at
alternate ways to express myself, and no matter if I drop or keep it,
I've learned something. Whether or not I have good taste is something
else; if I have bad taste you can bet I've been making bad decisions
with every other mechanism I can get my hands on. (Object-oriented
programming!)


-- Tayssir
 
K

Kenny Tilton

Tayss said:
...So I'm kinda
wondering if they're angry all these threads are shoved in their
faces.

I worry, too. I console myself with premises minor and major:

minor: my newsreader shows the subject of a message. :) it also has an
"ignore thread" menu item. a couple of clicks and an asinine thread
about whether Scheme is a Lisp does not exist AFAIAC. Or I can save the
click and Just Not Read(tm) the bullshit.

major: Information Is Deeply Good. Don't ask me why, it just seems to
reliably turn out that way. Pythonistas are by definition Seekers (sheep
have the Establishment-Approved Java and C++.) Seekers do not mind
Information. And even if one resents the threads, I think one would
concede that folks are /not/ off track yelping about one language or
another, the conversation has stuck reliably to "life with macros".

I am one of those Lispniks who is always open to new technology but who
also believes "No macros? No, thanks." If you follow the link in my sig
you'll find more (and there were a few who said the same but got quoted
for some other remark).

Python has a lot of other stuff strongly reminiscent of Lisp. Y'all
should at least get to know the one feature that makes Lispniks most
ecstatic before dismissing it.

My 2. kenny

--
http://tilton-technology.com

Why Lisp?...

http://alu.cliki.net/RtL Highlight Film
 
M

Michele Simionato

Kenny Tilton said:
Now the million dollar question is: how could the longer version above
be cleaned up without macros, with HOFs or a metaclass hack or something?

kenny

Probably yes. For what concerns automatically calling the base class
__init__ method with a metaclass, see this thread (sorry for the long
URL):

http://groups.google.com/groups?hl=...Google+Search&meta=group%3Dcomp.lang.python.*

It is interesting to notice that I never use this trick since
"explicit
is better than implicit" and I do prefer to call explicitly the
__init__
method. I think it is better for the readers of my classes (including
myself six months from now).

Michele
 
T

Tayss

Ok, now being sober...


Why do you need a macro for that? Why don't you just write

def start_window(name) : # 1
app = wxPySimpleApp() # 2
frame = MainWindow(None, -1, name) # 3
frame.Show(True) # 4
app.MainLoop() # 5
return (app, frame) # 6

Remember that we lose this game if lines #2-5 are executed out of
order. The system crashes.

Notice in #1, you used a string ("name") as the parameter. But that's
weird, you'd rather have all of line #3 as the param, not just the
little string part of it. So why can't you do that? The secret is
that strings don't have big side-effects when they execute, but line
#3 does! If you tried calling start_window() with the value of #3,
the call would execute it immediately and the system crashes.

Your example above is sensible, because we don't have the power to do
anything more meaningful. So we're stuck with some trivial function
that does nothing really important. Boa Constructor, the great Python
IDE, pops up three windows of different kinds and names on startup,
but /we/ are stuck with the trivial ability to customize one window's
name.

Sure, we can perform all sorts of functional programming tricks to get
things to execute in the right order as mentioned here:
http://groups.google.com/[email protected]
but we lose readability, which was the point of this exercise.

Maybe you argue this particular code only occurs once per app; but
there's a good documentation and maintainability advantage of having
stuff done once, and done right. And we talked about closing files
safely with try/finally earlier; that is something that needs to be
done often, and macros are a good way to do it. If I learn #5 should
be in a finally block, I don't want to do a big hunt and replace on my
old apps.

Conclusion: you don't need macros here.
Moral: maybe you do not *deserve* macros.

If you think I should be a good boy and go to school only reading the
safe books, getting a spanking when I look at the dangerous ones, well
that's one philosophy of life.

-- Tayssir
 
A

Anthony Briggs

Notice in #1, you used a string ("name") as the parameter. But that's
weird, you'd rather have all of line #3 as the param, not just the
little string part of it. So why can't you do that?

Why don't you do something like this?

def start_window(appfunction, framefunction) : # 1
exec("app = "+appfunction) # 2
exec("frame = "+framefunction) # 3
frame.Show(True) # 4
app.MainLoop() # 5
return (app, frame) # 6

start_window( "wxPySimpleApp()", "MainWindow(None, -1, name)") # 7

Anthony
 
B

Brian Kelley

Tayss said:
Ok, now being sober...





Remember that we lose this game if lines #2-5 are executed out of
order. The system crashes.
Your example above is sensible, because we don't have the power to do
anything more meaningful. So we're stuck with some trivial function
that does nothing really important. Boa Constructor, the great Python
IDE, pops up three windows of different kinds and names on startup,
but /we/ are stuck with the trivial ability to customize one window's
name.

This isn't really the case I think, we just have a different idiom for
doing something more meaningful. The solutions in the wxPython world
that I have seen do something like this:

class Application:
def __init__(self, name):
app = wxPySimpleApp()
self.name = name
try:
self.createApplication()
app.MainLoop()
except Exception:
# report on applicatino failure
# and close down properly
raise

def createApplication(self):
"""create your application here"""
# note, the window name is name
raise NotImplementedError

So know the usage is

class MyApp(Application):
def createApplication(self):
frame = self.frame = wxFrame(None, -1, self.name)
frame.Show()

app = MyApp("test")

So there are non-macro solutions to these issues that are equally
expressive in some cases. This is just more verbose than the
corresponding macro solution, I still think that it is quite readable
though.

app.app = application
app.frame = main window

Brian.
 
T

Tayss

Brian Kelley said:
This isn't really the case I think, we just have a different idiom for
doing something more meaningful. The solutions in the wxPython world
that I have seen do something like this:

This OOP solution looks like the functional one I mentioned earlier,
freezing code in a subclass's function instead of a plain function.
http://groups.google.com/[email protected]

But since GUIs often lend themselves well to OOP, I can see this as a
resourceful way to solve this special case. Making sure that
superclass.__init__() is always called and deciding early to structure
the entire App with OOP. I'm not a fan of calling overridden methods
from an old init, but life could hurt worse.

-- Tayssir
 
K

Kenny Tilton

Kenny said:
And to think someone said I do not know anything about marketing?

An emailer just asked if my objective was to market Lisp or macros. The
answer is macros. The whole thread (even The Fat Five Hundred) has seen
Lispniks speaking up in defense of macros in the abstract. I cannot
speak for others, but my feeling is: it would be a shame for Pythonistas
to miss out on something good for the wrong reasons.

btw, regarding my use of the M word, marketing can be evil (witness Joe
Camel) but in the general case it is just about communicating
effectively by considering the listener.

btw^2, anything a Lispnik says that makes macros happen in Python is bad
for Lisp, because then there is one less (huge) reason to check out
Lisp. we need folks to help develop more libraries and Pythonistas are
good at that. (Lispniks just sit around and moan on NGs.) So...hmmm...

MACROS SUCK!

:)

kenny

--
http://tilton-technology.com

Why Lisp?...

http://alu.cliki.net/RtL Highlight Film
 
T

Tayss

Kenny Tilton said:
btw, regarding my use of the M word, marketing can be evil (witness Joe
Camel) but in the general case it is just about communicating
effectively by considering the listener.

I got an interesting email too, this one with the novel solution (at
least to me) of using "" around Python code like a lisper would use '.
He'd then parse and execute it using the exec statement. To think
that one year ago I might have dismissed such code for vague
reasons... And now it seems like a normal thing to do, except for the
fact it's not a style encouraged by Python with tools, libs and docs.

So there are Python users who naturally think in a Lisp. I was
probably in that situation. So some level of "marketing" is good when
it provides good info for people who are searching for something.

This thread is weird though. My position morphed from "macros would
keep me from making unfortunate tradeoffs" to "macros are the only
solution!!! Bow to lisp!!!" Maybe trolls are very good at telling
you about yourself, and I just need to embrace the inner lisp weenie
or something. Or maybe I'm working with code too much lately and
obsessing over perfection.
 
K

Kenny Tilton

Tayss said:
I got an interesting email too, this one with the novel solution (at
least to me) of using "" around Python code like a lisper would use '.
He'd then parse and execute it using the exec statement. To think
that one year ago I might have dismissed such code for vague
reasons... And now it seems like a normal thing to do, except for the
fact it's not a style encouraged by Python with tools, libs and docs.

So there are Python users who naturally think in a Lisp. I was
probably in that situation. So some level of "marketing" is good when
it provides good info for people who are searching for something.

yep. the interesting thing is that you cannot just leave the information
on the doorstep and assume it will get recognized as cool by the
inhabitants. i know, having ignored MCL ads (big long detailed ones in
APDA catalogs) for weeks during a search which ended up with delirious
delight... at MCL!
This thread is weird though. My position morphed from "macros would
keep me from making unfortunate tradeoffs" to "macros are the only
solution!!! Bow to lisp!!!"

Twist our arms. :)

Maybe trolls are very good at telling
you about yourself, and I just need to embrace the inner lisp weenie
or something. Or maybe I'm working with code too much lately and
obsessing over perfection.

If you go here:

http://alu.cliki.net/Kenny's RtLS Top-Ten

.... the current #2 favorite story of mine is about a fellow effectively
trying to hack GCC so the source he wrote could include hints to the
compiler as to how best to "write" the assembler output. A GCC guru told
him, "You are looking for Lisp."

I like this story because the fellow honestly was trying very hard to
get something done, /not/ looking for an excuse to do Lisp. It just
turned out that his requirement mapped onto something (compiler macros,
a special kind of macro) Lisp does --not by design-- but as a
consequence of other fortuitous design decisions.

This long "to macro or not to macro" thing has been unfortunate in that
it has been conducted in the abstract, without actual code to point to
that some Pythonista macro advocate argues could be improved only with
macros. Is there a formal proposal on the table with such a thing?

kenny


--
http://tilton-technology.com

Why Lisp?...

http://alu.cliki.net/RtL Highlight Film
 
K

Kaz Kylheku

Why do you need a macro for that? Why don't you just write

def start_window(name) :
app = wxPySimpleApp()
frame = MainWindow(None, -1, name)
frame.Show(True)
app.MainLoop()
return (app, frame)

Macros are used for other things!

In conjunction with wxWindows, macros are indeed useful. The C++
library itself has, for instance, a WX_IMPLEMENT_APP macro that
implements the application: you just name the root class. It also has
message map macros which bind messages by event and control ID to
class methods.

I started working on Lisp wrappers for wxWindows which provide Lisp
versions of these macros.

The example goes something like this:

(use-package :wx)

(defclass my-app (app) ())
(defclass my-frame (frame) ())

;; save command
(defmethod on-save ((frame my-frame) (event event))
(format t "my-frame::eek:n-save~%"))

;; print command
(defmethod on-print ((frame my-frame) (event event))
(format t "my-frame::eek:n-print~%"))

;; button click
(defmethod on-foo-clicked ((frame my-frame) (event event))
(format t "my-frame::eek:n-foo-clicked~%"))

;; Message map: Lisp macro.

(define-message-map my-frame
(menu-event
:)save on-save)
:)print on-print)
(command-event
:)foo on-foo-clicked))
(close-event on-close))

;; Application macro, just like in a WxWindows C++ program.
;; There has to be an ON-INIT method specialized for the MY-APP
class!

(implement-app my-app)

Note that instead of the integer control ID's used in the C++ realm,
we use keyword symbols! So there is nothing to declare. In ON-INIT,
you create the button with the control identifier :FOO, and that's
what you refer to in your map or elsewhere. Whereas the C++ programmer
has a silly chore of maintaining a header file that defines symbolic
constants for control ID's and things.

Writing the ON-INIT method in the application class is a chore,
because of the function call interface used for constructing the GUI.
This would be another good candidate for macrology. Ideally, there
should be a simplified description language which defines the elements
of the GUI, and is translated into the object constructor calls.

Wait, isn't this what resource files or scripts are in dumb
programming environments? These are just simplified, condensed
languages for defining GUI layouts so you don't have to write them in
the awful language you are using to develop the rest of the program.
;)
 

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
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top