| Store | Cart

Suggesting a new feature - "Inverse Generators"

From: Jordan Rastrick <jras...@student.usyd.edu.au>
25 Mar 2005 08:10:12 -0800
Sorry about the mangled formatting... like i said, first time on Usenet

Suggestions, comments, replies, etc most welcome.

This definitely includes replies of the form: "This is stupid,
because..."
provided it isnt followed with "youre a jerk who knows nothing.
Period."

Heres a follow up rant in the form of a Q&A, trying to answer what I
think are likely or interesting questions:

----------------------------------------------------

Q: Is this idea even remotely feasible to actually implement?

A: No Idea

Q: Are you volunteering to implement it?

A: Not really. I'd have no clue where to start. I probably don't even
have enough C experience to begin to understand the Python source. But
if some real Python dev (or devs)actually wants to implement this, and
is willing to humour an undergraduate by somehow utilising assistance
in form a very limited set of programming skills, well, then I'd be
highly flattered and more than happy to help :)

Q: The whole document is full of half-formed ideas, hundredth-formed
ideas,
mistakes(conceptual/typograhpcial/stylistic/grammatical/terminological/programming/...),
inconsistencies, random nonsense......

A: Firstly, thats not a question, its a statment.

Secondly, see the very first paragraph.

Thirdly, the whole document, from initial attempts to code the original
for loop (yes, it is a real program I'm trying to write here), to
thinking of Acceptors, refining the model to something vaguely
coherent, coming up with examples, and typing it all out, was produced
on the fly, in the space of 5 hours or so. I attempted to give it a
semblance of coherent structure at first, but soon gave up. Its
basically stream of conciousness production. The bit where the first,
nonsensical example is given, is literally where I first tried to
forumlate the idea in code, saw the massive holes, stopped, thought
about it for a few minutes, and came backed and typed out the much
improved second version. The whole thing is totally unedited.Oh, and I
had virtually no sleep last night.

A real answer, with respect to the issue of terminology: If I use
technical terms loosely, e.g., if I improperly use 'method' for
'function' or vice versa (a hang up from dealing with languages that
only have one e.g. Java, or the other, e.g. C) ,  please forgive me. I
hope what I'm trying to say is still clear enough.

And as for coding style, Python itself is inconsistent (or to be more
diplomatic, not obsessively concerned with the relatively minor issue
of) using underscore_seperated_words or mixedCaseInstead, etc. And
again, I cry the nefarious influence of Java....

Q: Did you steal this from somewhere else?

A: No, its entirely something I thought of, by myself, in the last 5
hours. Thats not to say something like it (or more likely, better than
it) hasnt been thought of somewhere else by someone else. But if it
has, I havent seen it.

To give credit where due though: I was motivated by the various
examples, from sources like www.python.org, of how Generators can be
used to do things really elegantly. Also, I'm still tossing around
ideas in the back of my mind from a great talk given at my university
by Rob Pike, of Google, about a language he helped devise and implement
called sawzall (or something close). Its used to do processing with
Google's massive data sets and highly parallel computing architecture,
yet its incredibly simple to understand and very efficient. I guess it
was only tenuously related to the idea presented here. But it was
certainly very inspiring in a general computer-science-enthusiasm kind
of way.

Q: Why did you go to all this trouble thinking up this feature when you
could have solved the original problem in so many other, simpler ways?

A: I honestly can't give a decent justification :-) Whenever I've
needed to do things like:

line = readline from file
if (line is some sort of 'extra' data)
   do something with line
   line = readline from file # get the 'regular' data
...

in the past, in Pascal, Java and the like, it always irked me. Don't
ask why, it just did.

I thought I could get around it with generator in Python, but I
couldnt. In trying to think of a generator solution, I more or less
randomly thought of extending the generator concept somehow, and I
decided to see where it took me. I thought it took me to somewhere
interesting, and possibly worthy of further investigation.

Q: What about using some sort of 'sequential data sink' that doesn't
use 'pretending to be a function' syntax, e.g. a simple Class of some
sort?

A: Maybe. You can have Iterators without Generators. Maybe you can have
"inverse Iterators" without "inverse Generators", I havent thought
about it.
I love the 'pretending to be a function' syntax, its part of what makes
Generators so elegant. So I tried to emulate it.

Q: What could be some of the benefits of introducing this feature? What
could it be used for?

A: Again, I don't really know. Past the examples I've given, I havent
really thought about possible applications.

Potentially there might be efficiency gains using an Acceptor in place
of a regular function that just processes a sequence, in the same way
that using a Generator can be more efficient than using an actual
sequence like a list.

Then again, there might not.

Q: ....So you've put forward this idea without really stopping to think
if its actually useful?

A: The idea seems *potentially* powerful and useful to me. Once more,
for emphasis - I'm most definitely NOT trying to assert this is a great
idea. I'm saying that maybe its a good idea, so lets put it on the
table. That way, if it is really bad, lots of really smart people can
shoot it down really quickly and save me wasting any more time thinking
about it.

Q: Maybe you should have put a bit more personal though/research into
the idea before putting it out into the public domain? Or at least
waited until you had more experience in Python?

A: I'm not an academic or a professional, I don't have any reputation
worth preserving. I tried not to suggest this in a forum where it'd
distract the people who are responsible for developing Python from
doing their very important work. Anyone could choose to ignore the post
if they so desired - I havent wasted anyone's time, unless they've
conciously chosen to waste it. And you read far enough to get to this
question, so I assume you were at least vaguely interested.

Q: Why not make a smaller, more tenuous suggestion, get some feedback,
and go from there, rather than making one big ranting post?

A: I suppose I just wanted to get all the ideas out while they were
stll in my head. Its the kind of chaotically creative approach I often
apply (though not intentionally) to programming, with results that are
occasionally great and often disastrous.

Q: In Python, there were list comprehensions, and then generator
comprehensions. So what about Acceptor comprehensions?

A: Yeah, sure, maybe. It sounds like a cool idea at least. Havent
thought about it.

Q: Why did you choose this particular syntax and naming?

A: I just used what seemed the most obvious way to do things. I'm sure
better versions could be thought of.

Some advantages: its simple. The use of accept parallels the use of
yield in generators.
Its, arguably, pretty intutiitive.

Disadvantages: It could be a bit too verbose, having to type accept for
each magic argument.  Perhaps an abbreviated sytax might be good

e.g. accept arg1, arg2
in place of
accept arg1
accept arg2

so long as it didn't conflict/confuse with existing syntax, for tuple
assigment, etc.

Another possible variant: the 'magic sequence' could be explicitly
named in an Acceptor's argument list. I kind of like the way the
Acceptor is 'bound' to its magic sequence by the call, with the
sequence itself disappering from the argument list... its sort of
vaguely similar to how  x magically appears in the argument list when
making the method call  x.someMethod(otherArgs)

Q: Why do you keep using the word magic everywhere?

A: "Any sufficiently advanced techonology is indistinguishable from
magic."
Seems like a good enough term for a language feature that I can
conceive, and can think in a limited fashion about some of its effects,
but have no real understanding of its possible mechanisms. Or just for
stuff that seems cool, powerful and slightly mysterious. :) Besides,
once I'd started using it, I think it helped to be consistent.

Q: Can't you already achieve this precise effect very easily with
existing syntax (filter, list comprehensions, simple recursion,
something)?

A: Maybe, I don't know. If you can think of how, I'd like to hear it.

Q: What about backwards compatibility issues?

A: The only obvious one I can think of is the use of accept as a
keyword, which would conflict with any variables called accept. Im sure
one exists in some code somewhere. Hopefully, not too much code would
be broken. Possibly a different syntax wouldnt even have to use a new
keyword, or could use one that wouldnt cause much disruption to code.

I imagine the issue would not be significantly worse than the
introduction of yield for generators was. Or any other new language
feature for that matter.

Note, this is one of the reasons I'd be reluctant to see other special
keywords/functions aside from accept used in the mechanism.

Q: Why don't you want Acceptors to be able to know when the magic
sequence ends?

A: I don't know, I just don't like it. My intuition is you'd end up
writing loops in acceptor functions that could have just been written
in more or less exactly the same way without an acceptor, instead of
writing Acceptor focused code. There's already an implict loop
iterating through the sequence. Adding an additional loop with
something like
while accepting:
     accept ....
is complicating things. Note neither of the two finished examples had
any loops in them at all.

As usual, I could be completely wrong.

A possible compromise: Have an optional finally block at the end of the
method, that executes when the magic sequence runs out of elements.
This could serve much the same function as while accepting: without
reintroducing banished loopiness. And maybe a similar thing, but prior
to accepting. A 'first' block. So:

def combineIntoRecord(): # This is an acceptor function
       first:
	recordList = []
       optionalline = None # We may not get given a value for this line
       accept firstline
       accept secondline
       if condition(secondline):
          accept optionalline
       accept lastline
       recordList.append(createRecord(firstline, secondline, lastline,
optionalline))
       finally:
          return recordList

Of course, thats another new keyword, plus an existing one
overloaded.... again, I'm not a big fan.....

Basically, I can summarise my views on what should and shouldn't be
included in the mechanism thusly:
Iwant to be able to 'accept' in an arbitrarily (or at least very)
complicated way within an Acceptor. I reckon that is what would give
them their power, and could lead to cool applications.

But conversely I don't want Acceptors to 'need to do everything',
burdening them with extra syntax to allow them to behave like regular
functions. They're not intended as a super technique that solves every
problem, they're intended to find and fill a particular programming
niche. Better that niche be small, but Acceptors be a perfect fit for
it - obviously the right answer for some problems, and equally,
obviously the wrong answer for others.

For comparison, think about lambda functions in Python allowed to
contain arbitrary sequences of statements, not just single expressions.
Anything that can't fit easily in a lambda, doesnt belong there. The
same goes for Acceptors.

Most imporant of all, the motivation of the whole exercise is to make
things simpler and more elegant, not more complex and ugly.

Q: Isn't it just perverse to want to code algorithms that are
inherently suited to looping in syntax that does not explicitly loop?

A: Perhaps. The lack of looping wasn't actually how I originally
envisioned the final result.

But you need to think long and hard about what is meant by an
"algorithm inherently suited to looping." Try using a purely functional
language (e.g. Haskell) and you might see what I mean.

As far as my limited understanding of these things go, from a
theoretical viewpoint, looping is actually only a special case of
recursion. Its just that in structured, low-level, imperative
languages, looping is the standard technique for solving a certain
class of problems. So if like most people you learn to program in such
a language, you'll naturally tend to think 'loops.' Hence the issue is
really something inherent to your way of thinking about programs, and
not to the actual problem.

Q: You don't need to use yield, or a loop, or first/finally blocks, to
make the final example work. Just pass in an empty list, and append it
at the end of the method; return nothing.

A: Yeah, I just now realised that. In fact possibly all the benefits of
both the while Accepting and the first/finally ideas could be realised
by preparing and passing in any nessecary intial state, and using
callback on the passed objects instead of return. That way of
implementing things seems cleaner and more in line with the 'Acceptor
feel', in fact. This is definitely a line of thought that needs to be
explored further....

For what its worth, conceptually, that solution pretty much works the
same as using yield. But I like the idea of an Acceptor/Generator, so
I'll let it stand in its own right. Needs a better name name though :-)

Q: What's the project you were working on when you thought of this?

 A: Nothing particularily interesting or important ;-)

Q: Have you got anything more to add?

A: Yeah, I'm tired, and going to bed now.

I'll be interested to see if this actually generates a substantial
discussion of any sort.

And I do apologise for the length of this rant. I hope that by reading
it, you've at the very least gained some sort of amusement and sense of
overwhelming superiority in light of my outrageously stupid
thoughts.....

Recent Messages in this Thread
Jordan Rastrick Mar 25, 2005 04:04 pm
Jordan Rastrick Mar 25, 2005 04:10 pm
Andrew Koenig Mar 25, 2005 04:18 pm
Jordan Rastrick Mar 25, 2005 04:36 pm
Andrew Koenig Mar 26, 2005 01:40 pm
Tim Hochberg Mar 25, 2005 04:25 pm
Michael Spencer Mar 25, 2005 04:46 pm
Jordan Rastrick Mar 25, 2005 05:23 pm
Michael Spencer Mar 25, 2005 06:41 pm
Serge Orlov Mar 25, 2005 07:14 pm
Jordan Rastrick Mar 26, 2005 06:56 am
Peter Otten Mar 26, 2005 08:04 am
Scott David Daniels Mar 25, 2005 07:34 pm
Michael Spencer Mar 25, 2005 08:07 pm
Scott David Daniels Mar 25, 2005 09:00 pm
Bengt Richter Mar 25, 2005 10:11 pm
Bengt Richter Mar 25, 2005 07:43 pm
Terry Reedy Mar 25, 2005 07:13 pm
Jordan Rastrick Mar 25, 2005 04:49 pm
Diez B. Roggisch Mar 25, 2005 06:13 pm
Jordan Rastrick Mar 26, 2005 04:11 pm
phil...@yahoo.com Mar 27, 2005 03:44 am
Oren Tirosh Mar 27, 2005 06:58 am
Messages in this thread