Discussion:
[Edu-sig] PySqueak: "Self" as the source of many ideas in Squeak
Paul D. Fernhout
2006-05-05 07:46:27 UTC
Permalink
In continuing to contemplate what are the essential ideas of Squeak in
terms of using them in an educational environment resting on Python, I
decide to revisit some of Squeaks' roots. Many of these are in "Self", a
prototype based programming language (and IMHO a constructivist one too).
The main page for Self:
http://research.sun.com/self/language.html

I had read of Self, and met one of the key people once at a conference,
and I was inspired by many ideas from those interactions, as well as work
with NewtonScript (the native programming language of the Newton, also
inspired by Self), but I had never seen the Self system in action. It
turns out there is a 15 minute or so video on Self, linked to from here:
http://www.merlintec.com:8080/Self
Kirby, you mentioned the persuasive power of videos in another context,
and I suggest viewing the high definition version of the videos there
would be useful in seeing how a graphical environment for students could
approach the immediate feedback of the command line, especially with most
of today's students who are presumably already "point and click" mouse
literate.

The key principles mentioned in movie for Self's design are based on ideas
from the physical world, and are summarized as:
* Directness (everything is potentially visible and touchable)
* Uniformity (you can consistently change everything)
* Modelessness (always running, so no editing/running distinction)
Self also demonstrates multiple people doing activities together in one
(2D) environment. [BTW Neometron's Learningworks was about 3D communities
using Smalltalk and was deployed a decade ago, which shows some other
roots of Squeak/Croquet roots here.]

From the paper here (first seen in a link below):
http://research.sun.com/self/papers/programming-as-experience.html
"Finally, in designing Self, we have learned one lesson by making
mistakes: examples can persuade the designer to include additional
features which later turn out to produce incomprehensible behavior in
unforeseen circumstances. This might be called the language designer's
trap. Minimalism, simplicity and consistency are better guides. They
benefit every programmer, not just the ones who need advanced features. We
suspect that many of today's object-oriented languages could profit by
dropping features."

In my own work in Smalltalk development, knowing that Self existed, and
having experience with prototypes in Newtonscript, I was often frustrated
by Smalltalk not having Self's elegance. And I think many of the issues
Self addresses (particularly eliminating a class side / instance side
distinction) are very important to making programming easy to get into, as
well as keeping it more fun. In the movie near the end they make the
distinction between telling objects what to do (writing code) and just
banging them around into position (which Self's GUI helps support, in
addition to programming). By building in "Morphic" (the Self GUI paradigm)
Squeak tries to get this Self leverage, but I think, given Squeak's use
of Smalltalk (which has classes), Morphic always seemed to me to be rather
inelegantly bolted on (this is not a slam at the developers, just an
inherent problem of a class based programming system trying to work with
dynamic constructivist material).

One of the things I have always liked about Python is its use of
dictionaries for storing values in instance objects. This is
computationally inefficient compared to looking up things by position in
an array as C or Smalltalk do, but it is more flexible in terms of taking
any specific instance and adding more data fields to it, so it is
efficient in a human-oriented way and can lend itself somewhat to this
sort of prototype based work. So, another idea when thinking about
PySqueak is: how can Python better support prototype based development? As
well as: how can what we have with Python2.4/Jython2.1 now be used to do
that in interesting ways?

Now this certainly isn't a new idea, see for example these discussions:
http://lists.canonical.org/pipermail/kragen-hacks/2000-September/000264.html
http://www.thescripts.com/forum/thread30832.html
http://www.prothon.org/
http://www.google.com/search?hl=en&q=Prothon
or Prothon's apparent successor, PyCS:
http://www.prothon.org/pipermail/prothon-user/2004-August/003269.html
http://pycs.org
[However, the Prothon and Pycs links seem to be down right now, I read
them through the Google cache just now as this project is new to me,
perhaps an indication the project is ended?]

These three key principles above, relating to a dynamic nature of the Self
system, are probably needed to support any constructivist approach to
software creation and use. But notice how they are the opposite of the
principles behind something like C++ or other statically typed languages,
which focus on data hiding, specialized interfaces, and set-in-stone
compiled applications. Or as Alan Kay put it:
http://www.smalltalk.org/articles/article_20040731a.html
"I invented the term Object-Oriented, and I can tell you I did not have
C++ in mind." This statically compiled approach culminates brilliantly in
something like OCaml,
http://en.wikipedia.org/wiki/Ocaml
since if you want types with the least pain and syntactic clutter, OCaml
can infer many of them for you. C++ or OCaml are pretty much about
specifying everything in advance and locking down the system, assuming it
will never change at runtime, to get the most out of memory and computer
cycles focused on a narrowly defined fixed problem. This is not to say C++
or OCaml can't be used to make open systems (say, by defining a Smalltalk
or Common Lisp or Python virtual machine in some way), but openness at
runtime is clearly not what those languages are about.

Now there are places for that sort of efficient and effective closedness,
but it is a very different philosophy from creating open systems like
Self, or Squeak. Python clearly potentially can be used in a Self-like or
Squeak-like open way, and some core development tools rely on that, but in
practice most of the time Python seems not to be used that way. Perhaps
this is due to, as a speculation, that most people come to Python from a
C/C++ background, which is why they liked the "f(a, b, c)"-style syntax as
opposed to keywords (Smalltalk) or lots of parens (Lisp). Clearly, if most
Python development had a long legacy of being oriented around that sort of
open and dynamic constructivist principle, with the size of the Python
community and its technical skill, we would probably already have a
dynamic environment better than Squeak for all the things Squeak does. :-)
So, as I reflect on this, the roots of not having Squeak on Python
*already* may have more to do with Python community culture and history
and mindset than Python limitations.

One can of course hope that a successful PySqueak project in that
direction will prove to be a "better mouse trap" and the Python community
will flock to it, although that may not be realistic, speculating about
the Prothon and PyCS sites being down. And as it pointed out here by
Sjoerd Visscher:
http://lambda-the-ultimate.org/classic/message11653.html
"Flexibility is nice, but useless when the libraries are implemented in
one programming style. That programming style will be the only natural
style of the language."

I want to underscore and emphasize this difference between these two
philosophies of programming language design, because it seems that the
directions proposed for mainstream Python, if anything:
http://www.artima.com/weblogs/viewpost.jsp?thread=86641
have been in directly the opposite direction to Self, to a Python with
static typing (including RPython). So, frankly, there very well simply be
an insurmountable cultural barrier here. And there is nothing wrong with
that -- static types are a valid way to generate code that efficiently
uses memory and computation to solve a specific well defined purpose (like
a well specified Python VM or any other well specified problem). However
such a focus will remain at odds as far as I can see with the notion of a
living and evolving population of objects system, which is at the core of
a constructivist vision of education or programming. Hopefully a diverse
Python community could productively use both paradigms in language
variants, so an RPython for certain specific tasks, and a proto-Python for
everything else (or at least, some forms of educational use)?
Unfortunately, the more one sees a path diverging from Python as it is
commonly defined (towards, say, a Prothon? direction) the quicker interest
in a PySqueak will evaporate, if it has not already. :-) Because then it
is just some quirky side variant. Still, there are niches in the Python
community, like with Jython, where a slight change in direction may be
more feasible, at the very least as a proving ground of sorts (Jython
sometimes has its own identity crisis of whether to track CPython or
strike out on its own, usually resolved in favor of tracking.).

So, again, in thinking what Squeak on Python might mean, as opposed to
aping Squeak, Python could build on its strength of using dictionaries
internally and support a more prototype based environment like what
Prothon or PyCS tried to move towards, making it more similar to Self than
the derivative (in that sense) Squeak (which still uses classes). Coupled
with a self-like GUI, I think that would better support constructivist
educational needs. Of course, then one can ask, is this just reinventing
the Self wheel and is that worth doing (to potentially gain Python
community advantages, which might be questionable if the approach deviated
in any significant way from mainstream Python)? It would seem clearer that
the most leverage would be gained if Python (or Jython) as it is now (or
with at best trivial changes) could be used to support Self-like features,
and thus realize some of the constructivist ideals also embodied and
further popularized in Squeak.

Or, as Ian Bicking points out here in "Initial thoughts on Prothon":
http://www.artima.com/forums/flat.jsp?forum=122&thread=41588
"[After mentioing Prothon syntax changes from Python...]
I actually wonder to what degree prototypes could be implemented in
Python with metaclasses. While some of the syntax would currently be crufy
with Python (e.g., you'd have to create a function, then assign the
function to an object), that's kind of a separate issue. The bpython
metaclasses
asic object
model in Python feels like it should be replaceable, especially since we
already have both new and old style classes. I think it's still a bit hard
to think about these with the syntax getting in the way or otherwise being
distracting, but feel like the potential is in there somewhere. If it
could be hacked onto Python instead of developed entirely separately from
Python, it could make Prothon much more interesting from the perspective
of practical programming. Ultimately it would probably have to be like
Stackless -- a patch against Python implementing some necessary changes to
syntax. But that's a more viable development effort, and one that's more
likely to percolate ideas into the main Python interpreter."

I think that Ian's suggestion is the most sensible strategy for proceeding
in that direction and continuing to maintain community interest in a
PySqueak inclined towards Self-like prototypes and a related GUI for
constructivist educational use (and other general use as well).
And if metaclasses turn out to not be the best approach,
still anything simple which preserves the Python syntax
while giving the new features (say, having all prototypes inherit from a
common class which overrides __getattr__ and __setattr__ to
simply look into the instance to find data and behavior?)

Ian, any recent thoughts on that? I would speculate that part of the
general interest of the world in HyperCard was that it to some extent
worked in a direct-manipulation protype-based way. Perhaps that similarity
resonates with you as well?

--Paul Fernhout
Paul D. Fernhout
2006-05-05 14:19:25 UTC
Permalink
Post by Paul D. Fernhout
http://www.artima.com/forums/flat.jsp?forum=122&thread=41588
[with quoted text from Ian which had "python metaclasses\n"
pasted in it by me by mistake.]
Ian-

Sorry to mangle your eloquent writing by accidentally pasting "python
metaclasses" in the middle of it (up till 4am writing inspired by seeing
the Self video, sorry).

--Paul Fernhout
kirby urner
2006-05-05 16:09:33 UTC
Permalink
On 5/5/06, Paul D. Fernhout <pdfernhout at kurtz-fernhout.com> wrote:

<<SNIP>>
Post by Paul D. Fernhout
So, as I reflect on this, the roots of not having Squeak on Python
*already* may have more to do with Python community culture and history
and mindset than Python limitations.
Constraints provide form and allow function.

I'm thankful that Python has the heritage Guido gave it: easy to
learn if you're an adult in a late 1900s technical mindset, already
working around computers, probably already knowing some C (but
finding it slow going and unproductive).

Python made it easier for astronomers, health professionals,
statisticians, engineers to get work done in a computer language.
That's a fine place to start, no apologies needed.

I go back to my view that a powerful 3D graphics engine is something
many languages would like to use and there's no reason the Python
community should shoulder the entire developmental effort. Establish
a common low level API that lots of languages might use.

Such a 3D engine is for data visualization and simulations, but also
for storyboarding and puppet shows -- not unlike Blender in some ways.
We have cameras (points of view) and shapes with behaviors and
attributes, coordinate systems. A single Python script could set up
the scene and carry us through a story about a White Monkey.

I'm reminded of a Pycon demo in DC, where we saw a simulator and
language trainer used for English speakers going to Iraq. Unreal
Tournament 3000 was the game engine. Python bindings had been
established...

Suddenly, we were in the outskirts of Baghdad, encountering Iraqis
lolling around a coffee shop in a somewhat destroyed landscape.

The dialog was basically:

"Hello [polite introductions] who is your leader and how can we find him?";

detailed instructions provided [left, right, left, straight...];

following instructions; finding and greeting leader [politely].

That's if all went well.

At every decision point, trainees might experience Game Over, perhaps
because of intonation. A speech analyzer on the other end of the
microphone contained algorithms looking for intelligible Arabic.
Anything less was unacceptable.

Kirby
Ian Bicking
2006-05-05 16:22:15 UTC
Permalink
Post by Paul D. Fernhout
The key principles mentioned in movie for Self's design are based on ideas
* Directness (everything is potentially visible and touchable)
* Uniformity (you can consistently change everything)
* Modelessness (always running, so no editing/running distinction)
Self also demonstrates multiple people doing activities together in one
(2D) environment. [BTW Neometron's Learningworks was about 3D communities
using Smalltalk and was deployed a decade ago, which shows some other
roots of Squeak/Croquet roots here.]
This is a little of what I intend with HTConsole; the objects are
(vaguely) live, and potentially shared. Though I've only implemented
useful liveness for functions so far. It's at conflict with the idea of
source code, and live objects really require an image, and I've never
liked images. So I'm not sure if it's a useful path.
Post by Paul D. Fernhout
http://lists.canonical.org/pipermail/kragen-hacks/2000-September/000264.html
http://www.thescripts.com/forum/thread30832.html
http://www.prothon.org/
http://www.google.com/search?hl=en&q=Prothon
http://www.prothon.org/pipermail/prothon-user/2004-August/003269.html
http://pycs.org
[However, the Prothon and Pycs links seem to be down right now, I read
them through the Google cache just now as this project is new to me,
perhaps an indication the project is ended?]
As far as I know, the project fizzled soon after the move to CLR was
announced.
Post by Paul D. Fernhout
I want to underscore and emphasize this difference between these two
philosophies of programming language design, because it seems that the
http://www.artima.com/weblogs/viewpost.jsp?thread=86641
have been in directly the opposite direction to Self, to a Python with
static typing (including RPython).
I wouldn't put too much weight on this, especially RPython. RPython
isn't meant to compete with Python in that way. And it is Squeaky in
its own way.
Post by Paul D. Fernhout
http://www.artima.com/forums/flat.jsp?forum=122&thread=41588
"[After mentioing Prothon syntax changes from Python...]
I actually wonder to what degree prototypes could be implemented in
Python with metaclasses. While some of the syntax would currently be crufy
with Python (e.g., you'd have to create a function, then assign the
function to an object), that's kind of a separate issue. The basic object
model in Python feels like it should be replaceable, especially since we
already have both new and old style classes. I think it's still a bit hard
to think about these with the syntax getting in the way or otherwise being
distracting, but feel like the potential is in there somewhere. If it
could be hacked onto Python instead of developed entirely separately from
Python, it could make Prothon much more interesting from the perspective
of practical programming. Ultimately it would probably have to be like
Stackless -- a patch against Python implementing some necessary changes to
syntax. But that's a more viable development effort, and one that's more
likely to percolate ideas into the main Python interpreter."
Some things other people have done (like Logix:
http://livelogix.net/logix/) makes me think that this could be done in
CPython now, with just some fiddling in the compile process. I think
the Python object model (which can't easily be changed) is already
flexible enough for this.

And ignoring some syntactic details you could do this in current CPython.
Post by Paul D. Fernhout
I think that Ian's suggestion is the most sensible strategy for proceeding
in that direction and continuing to maintain community interest in a
PySqueak inclined towards Self-like prototypes and a related GUI for
constructivist educational use (and other general use as well).
And if metaclasses turn out to not be the best approach,
still anything simple which preserves the Python syntax
while giving the new features (say, having all prototypes inherit from a
common class which overrides __getattr__ and __setattr__ to
simply look into the instance to find data and behavior?)
I think it could be easier than that. I think a lot of the more
declarative programming I do really has prototypes underneath it.
(Ironically in Javascript I never find a need for prototypes, except to
simulate classes.) An example:

class Person(SQLObject):
name = StringCol(notNull=True)

I think Person.name is really best represented as a prototype. I've
played around with using this:

class Person(SQLObject):
class name(StringCol):
notNull = True

As an equivalent operation -- it starts looking better when you add
methods to the object (e.g., on_delete, on_update, etc). Actually
having Person.name be a class is annoying, but you can get class
statements to generate instances with some appropriate hackery. At that
point you start blurring the distinction between class and instance.

So, in this model, clone is the basic operation. I.e.,:

class obj(prototype):
a = 1

Means something like:

obj = prototype.__class__()
obj.__dict__.update(prototype.__dict__)
obj.a = 1

(The actual mechanics require some dumb fiddling with fake metaclasses.)
This is different from the delegation of a typical prototype language
(where the prototype isn't copied, but is called back to), but it's fast
and uses normal Python. And I guess with clone in a prototype language
you are basically doing this copy? I'm more comfortable with copies
than chains of delegation.

There was a proposal recently for a "make" syntax in Python
(http://www.python.org/dev/peps/pep-0359/), so this would look like:

make prototype obj:
a = 1

And the exact semantics would be something like:

obj = prototype('obj', (), {'a': 1})

Or my preference:

obj = prototype.__make__('obj', {'a': 1})

Sadly Guido rejected it. I think it's a much better syntax with cleaner
semantics for this kind of case, and I think this kind of case is
actually extremely common. The whole Lisp S-Expr stuff is about this
kind of declarative data structure, and adding that to Python just
requires this little tweak of the language; it doesn't give Python
macros, but the way Lisp uses data structures is for much more than just
macros. Smalltalk doesn't have anything like Lisp either, but uses live
objects to some similar effect, which is what binds it to the image.
Post by Paul D. Fernhout
Ian, any recent thoughts on that? I would speculate that part of the
general interest of the world in HyperCard was that it to some extent
worked in a direct-manipulation protype-based way. Perhaps that similarity
resonates with you as well?
I'm not really sure how to fit HyperCard into this -- I don't have a
strong feel for what it really means. I suppose one aspect is that the
source code is not at the core; instead the card stack is (or whatever
content-centric metaphor you use), and code is attached there. Ad hoc
structured code doesn't work that well with a class... you get something
like:

class Foo:
def bar(self)...

foo = Foo()

And the class/instantiation is just a kind of boilerplate. OTOH,
modules are another model; if each content-context (aka card) was a
module, you get some of the structure without the conceptual overhead of
the class.
--
Ian Bicking / ianb at colorstudy.com / http://blog.ianbicking.org
Paul D. Fernhout
2006-05-05 17:27:18 UTC
Permalink
Post by Ian Bicking
This is a little of what I intend with HTConsole; the objects are
(vaguely) live, and potentially shared. Though I've only implemented
useful liveness for functions so far. It's at conflict with the idea of
source code, and live objects really require an image, and I've never
liked images. So I'm not sure if it's a useful path.
Ian-

Thank you for your detailed reply and I promise more thought on it, but on
this one issue, to respond immediately, consider my earlier comments on
images and the muse as to a potential "Pythonic" resolution. Basically, it
is to think of the Python *image* as being defined by a Python *program*
that builds an object world and is stored in a textual *.py file, and just
looks and acts like regular Python source code -- ideally with comments
preserved too. So, no pickled objects, not binary image files, just Python
source code as readable text that rebuilds hierarchies and meshworks of
objects.

Or, as I realized shortly afterwards, perhaps an "python image" would be
nto jsut one *.py file, but a whole bunch of *.py files in a directory,
some of which might be more about defining classes (when you program that
way) and some of which are about defining specific in-use instances. So,
the Python image saving system might use the existing tagging of Python
objects back to file names, for example (perhaps with some extensions
needed). This way, a "save image" essentially would rewrite your directory
of source. A bit scary perhaps, but with subversion or such not too risky
perhaps. And not that different in some ways from what a tool like
BoaConstructor does (or attempts to do). And other round trip GUI
development systems (like Delphi) do this as well to varying degrees.

The key difference of this approach might be that you were not usually
editing the textual Python files in that directory by hand, but rather
were using constructivist HyperCard and self-like tools to modifying a
running Python program. Only then would you save the whole thing, to be
able to reload next time you wanted to be in that specific environment
defined by that directory. So, very similar to how things are done now in
most respects, except the changes are made to the running Python object
system, not the frozen textual representation of a pointing time of it.
Naturally, you could still make changes by hand to the *.py files when the
system was stopped, but if the GUI system was good enough, eventually few
people might want to work that way for most things.

It is also risky in another way, because loading a Python program could do
anything to you system (unless we have Python VMs with Java like security
limits on writing to files or sockets, where the VM enforces the
restrictions internally from security flags). But then again, a Squeak
image could do anything to your system when you load it in too. That
security issue just needs to be dealt with at the VM level, or at the OS
level, or through a system of trusted sites and so on (the "we're all
consenting adults Python philosophy", etc.). So I think it could be
managed in practice with risk equivalent to what we have now.

--Paul Fernhout
Ian Bicking
2006-05-05 19:18:12 UTC
Permalink
Post by Paul D. Fernhout
Post by Ian Bicking
This is a little of what I intend with HTConsole; the objects are
(vaguely) live, and potentially shared. Though I've only implemented
useful liveness for functions so far. It's at conflict with the idea of
source code, and live objects really require an image, and I've never
liked images. So I'm not sure if it's a useful path.
Ian-
Thank you for your detailed reply and I promise more thought on it, but on
this one issue, to respond immediately, consider my earlier comments on
images and the muse as to a potential "Pythonic" resolution. Basically, it
is to think of the Python *image* as being defined by a Python *program*
that builds an object world and is stored in a textual *.py file, and just
looks and acts like regular Python source code -- ideally with comments
preserved too. So, no pickled objects, not binary image files, just Python
source code as readable text that rebuilds hierarchies and meshworks of
objects.
That's very hard to implement...

For instance, imagine the user does this:

x = [1, 2]

Then they get a handle on that [1, 2] list (we'll call it OB1) and do
"OB1[0] = 5". How do we represent that as source? Because they are
acting on actual objects, not bindings, and OB1 doesn't have any name,
nor will it exist at the same address in a second run of the program.

In order to turn this into source, you'd have to keep track of how you
can repeatably get to OB1 (I guess you'd see that it was named "x"
through source introspection?), and then translate operations on that
object into source that does operations on the path to that object.

I think doing this generally becomes infeasible, though you can get
close through successively more bizarre source code generation, until
you end up with something that looks like a Python-source version of
pickle, and even that won't work very well.


This is all not to say that modifying Python source in a manner
different than ASCII is infeasible. Only that "source" and "runtime"
have to be kept separate to keep this process sane. Images -- which
mingle the two -- have never felt sane to me; clever, but not
manageable. Unfortunately we do not have very good abstractions in
Python related to source, so they have to be invented from scratch. The
AST might help, but higher-level abstractions are also called for. For
instance, you might define a color interactively in some fashion, and
the color gets serialized to:

import color
color.Color(r, b, c)

That color object might be immutable (probably should be), but the
*source* isn't immutable, and the source means something. How can we
tell what it means?

I can imagine a bit of interaction between the source and the runtime to
do this. For instance, we might see that "color" is bound to a specific
module, and "color.Color" to a specific object. We'll disallow certain
tricks, like binding "color" dynamically, monkeypatching something into
"color.Color", etc. Ultimately figuring out exactly what color.Color is
isn't *easy*, but at least it is feasible.

Using existing introspection we can figure out some parts, some of the
sorts of things that IDEs with auto-completion figure out. They can
figure out what the arguments to Color() are and the docstring.

But, you can also imagine adding an editor or other things to that
object; a richer form of __repr__, or a richer editable form than the
ASCII source. Maybe there would be a flag on Color that says it can be
called without side effect (meaning we can speculatively call it when
inspecting source); and then the resulting object might have something
that says it can be displayed in a certain way (with its real color),
and has certain slots you can edit and then turn into a new Color
invocation.

This is where the 'make' syntax starts to come into play again, or more
generally where declarative source comes into play. Take a typical
non-declarative module, like optparse:

parser = OptionParser()
parser.add_option('-v', '--verbose', action='store_true',
dest='verbose', help='Be verbose')

There's nothing there that looks like a literal; the first call to
OptionParser isn't very interesting, all the structure is in later
parts. This on the other hand:

make OptionParser parser:
make Option verbose:
"""Be verbose"""
aliases = ['-v']
action = 'store_true'
dest='verbose'

that is really a much more fully-formed piece of source that can be
understood as a complete piece; you could add methods to OptionParser
and Option to make this usefully editable. (Or use generic functions to
avoid having to modify those objects to give them rich source
representations)

Sometimes declarative structures are in conflict with runtime
dynamicism, but I don't think they have to be. The declarative form
doesn't make the .add_option() method obsolete; it just offers a static
form for the most common case where you statically construct the
options. There also might be a hint of static typing here -- an
OptionParser source editor might suggest an option to add another
Option, and so it will be bound to the Option class specifically; but
it's just important to leave in the same generality in the source editor
as the original source has. That is, OptionParser should defer to
Option for the 'verbose' key that's already set.

This is all harder than what HTConsole is doing currently, mostly
because Python source introspection is much poorer than Python object
introspection.
Post by Paul D. Fernhout
It is also risky in another way, because loading a Python program could do
anything to you system (unless we have Python VMs with Java like security
limits on writing to files or sockets, where the VM enforces the
restrictions internally from security flags).
Loading a Python program can already do anything, if you put the
commands at the top-level (not in a function). So Python source really
is focused on constructing objects -- even functions and classes are
*built* by the source, not declared by it, and so circular imports and
circular class references can be challenging as a result.
--
Ian Bicking / ianb at colorstudy.com / http://blog.ianbicking.org
Paul D. Fernhout
2006-05-05 20:15:59 UTC
Permalink
Post by Ian Bicking
That's very hard to implement...
Probably true, at leas to do it in a human readable way.
Post by Ian Bicking
x = [1, 2]
Then they get a handle on that [1, 2] list (we'll call it OB1) and do
"OB1[0] = 5". How do we represent that as source? Because they are
acting on actual objects, not bindings, and OB1 doesn't have any name,
nor will it exist at the same address in a second run of the program.
In order to turn this into source, you'd have to keep track of how you
can repeatably get to OB1 (I guess you'd see that it was named "x"
through source introspection?), and then translate operations on that
object into source that does operations on the path to that object.
I think doing this generally becomes infeasible, though you can get
close through successively more bizarre source code generation, until
you end up with something that looks like a Python-source version of
pickle, and even that won't work very well.
Just as reference to Squeak Smalltalk, it has a "changes" file that
records each top level Transcript type interaction (equivalent to a Python
shell in many ways) so that these can be replayed if you need to rebuilt
an image from the last version you saved if there was a crash. That's not
what I am proposing here.

But to address your specif example, maybe it does point to a paradigm
shift. Is this what you would do in an interactive session for your example?
Post by Ian Bicking
Post by Ian Bicking
x = [1, 2]
OB1 = x
OB1[0] = 5
del OB1
x
[5, 2]
Post by Ian Bicking
Post by Ian Bicking
OB1
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'OB1' is not defined

But, your "program" in terms of an image at that point no longer needs to
assign "x = [1, 2]". What it needs to do, to get back to where it is, is
assign "x = [5, 2]" if I understand your example correctly? Basically,
there is a bound variable in some scope, and a value it is. As long as
objects are reachable, we can write them out starting from roots of the
system (class path, the stack, modules and globals, and so on). Anything
we cant; reach should have been garbage collected anyway (though might not
have with CPython's reference counting system). So, we recreate the
binding and the object in as simple a way as possible, to make the objects
that are part of the accessible system. (Might make sense to combine this
work with a true generational mark-and-sweep multiple-spaces tenuring etc.
garbage collection system for Python? :-)

Maybe I don't understand the example? As I see it right now, while it
might be interesting to have a change log about how objects got to be how
they are now, what counts when saving an image to a Python *.py file for
future reload would be just their current structure and the name bindings.

As a note, remember that if there was a line of program code somewhere to
create an object using a class, using "x = [1, 2" that line would be
stored and regenerated as part of the class being stored. The fact that
creating a new object using an
"test = Spam()"
would assign
test.x = 1
is independent of the fact that in recreating test, we might do:
test = object()
test.__class__ = Spam # can this work? fails with a TypeError
test.x = 5
or, with some sort of optimizing storage system geared to writing
human-equivalent code rather than doing things one piece at a time:
test = Spam()
text.x = 5
Again, though maybe I am missing something obvious here?

Now, there may be a lot of things to improve this. I like your "make" idea
in that regard, and perhaps other ideas could help with that as well.

You are absolutely right in Python syntax defining how to create a set of
objects being more than declaring a specific structure. Forth has some of
the same aspects (only worse!). It is a big headache in many ways to
analyze Forth (as opposed to Smalltalk or Java or plain C) but Python now
has the advantage that this approach of using a Python program to save the
state of a sea of objects is more feasible.

Obviously somewhere you are going to have some code with a lot of
declaration of temporary variables and deleting them for complex
manipulation on structures. Perhaps this could require sort of engine to
optimize how to do that in a human readable way, sort of like an
optimizing compiler? A big task, but potentially doable for people who
like that sort of thing.

--Paul Fernhout
Ian Bicking
2006-05-05 21:07:50 UTC
Permalink
Post by Paul D. Fernhout
Post by Ian Bicking
That's very hard to implement...
Probably true, at leas to do it in a human readable way.
Post by Ian Bicking
x = [1, 2]
Then they get a handle on that [1, 2] list (we'll call it OB1) and do
"OB1[0] = 5". How do we represent that as source? Because they are
acting on actual objects, not bindings, and OB1 doesn't have any name,
nor will it exist at the same address in a second run of the program.
In order to turn this into source, you'd have to keep track of how you
can repeatably get to OB1 (I guess you'd see that it was named "x"
through source introspection?), and then translate operations on that
object into source that does operations on the path to that object.
I think doing this generally becomes infeasible, though you can get
close through successively more bizarre source code generation, until
you end up with something that looks like a Python-source version of
pickle, and even that won't work very well.
Just as reference to Squeak Smalltalk, it has a "changes" file that
records each top level Transcript type interaction (equivalent to a Python
shell in many ways) so that these can be replayed if you need to rebuilt
an image from the last version you saved if there was a crash. That's not
what I am proposing here.
But to address your specif example, maybe it does point to a paradigm
shift. Is this what you would do in an interactive session for your example?
Post by Ian Bicking
Post by Ian Bicking
x = [1, 2]
OB1 = x
OB1[0] = 5
del OB1
x
[5, 2]
Post by Ian Bicking
Post by Ian Bicking
OB1
File "<stdin>", line 1, in ?
NameError: name 'OB1' is not defined
Interactive sessions are source. The OB1 I referred to is the actual
object in memory, which has no real name, though it can be referenced
directly in memory.

Maybe a better example is something in HTConsole right now. Any
function you can get your hands on in HTConsole is editable, in-place.
Post by Paul D. Fernhout
Post by Ian Bicking
import random
random.choice
And you'll get a form that shows the source to that function, and lets
you edit it. That works fine in-memory. But saving that is hard.

There's actually lots of ways to get access to a function. When you get
random.choice, you are actually getting access to a method of a
singleton stored in the random module. When you edit that, you are
editing the method. How do you represent that edit as source? Do you
see that the function is available as random.choice.im_func, or
random.Random.choice? Or a property, which might be available as
SomeClass.some_property.fget. There's lots of paths to functions, and
the function alone doesn't necessary know how to get to it. And
functions are relatively easy; other objects can be much harder...
Post by Paul D. Fernhout
Post by Ian Bicking
items = range(5)
The contents of items cannot be edited in place, because they are
recreated dynamically. They can only be modified by later commands.

Keeping a log of commands is possible. But you aren't editing live
objects anymore, except perhaps an illusion of that. Instead you are
generating saveable commands from a specific location, which are
immediately executed to give you feedback but also saved so they can be
replayed in the future.

As I've been thinking about this, I think command generation is pretty
much like direct source modification, but direct source modification
also leads to nice source. So that's why I'm thinking that live objects
isn't a good metaphor, after going down that path some.
--
Ian Bicking / ianb at colorstudy.com / http://blog.ianbicking.org
Paul D. Fernhout
2006-05-06 07:52:39 UTC
Permalink
Ian-

Maybe we are still thinking about different things here.

I'm going on the presumption that Python, like Smalltalk, have various
"roots" which are things like (in Python) the loaded modules, the active
threads and their stacks, and perhaps some other state. A Python world of
objects is defined by these, since if any Python objects exist but are not
reachable somehow, they can't effect the system. As I reflect on that, I
can see how in theory outside forces that get a handle into object memory
might make changes and such things might exist in other processes or
threads, but that would just be a broken VM (or VM abstraction) to me more
than a problem to solve. :-)

So, going on this assumption that all Python objects of interest are
reachable from these roots (even if some of the roots themselves might be
only known to the VM, like the current thread?) then a recursive procedure
can flow down through from these roots and write one big text file
consisting of mainly:

# big module
import lots_of_stuff
temp1 = object()
temp1.__class__ = Point
temp1.x = 10
temp1.y = 20

temp2 = object()
temp2.__class__ = Point
temp2.x = 40
temp2.y = 50

temp3 = object()
temp3.__class__ = Rectangle
temp3.origin = temp1
temp3.extent = temp2

modules.mymodule = object()
modules.mymodule.__class__ = Module # or whatever?

modules.mymodule.myrect = temp3

And so on. Now obviously this gets tedious, so an optimizing writer would
instead produce:

# module mymodule
myrect = Rectangle(Point(10, 20), Point(40, 50))

But that's a matter of a smart writer, which I think is doable. Just think
of it as like optimizing code (although maybe in reverse. :-)

Now the problem you point out, that there may be several ways to reference
an object is obviously a real one. But a smart writer should handle that
(with a little handwaving by me. :-) But essentially, like with pickle,
the writer would know it has to write the definition for a function out
somewhere, and so it would pick a good spot, and then other references to
that function could refer back to the first place it was defined. (Or it
could be put in a temp variable which was later deleted after it was done
being used.) Even if the writer picked a bad spot, the problem would only
be that the code looked harder to read and understand, not that it would
not recreate the same objects in memory that were written out (though
perhaps at different locations; I'm presuming that would not matter -- if
it did, then that might be a problem requiring VM changes or some fancy
object creation order footwork, which would almost certainly mess up the
code's readability). As I've just casually glanced at the CPython VM
source code, and only just a bit more at the Jython code, I don't know
enough off hand to see whether there might be other bigger problems.

Anyway, I still don't see a show stopper (unless it is specific object ids
or exact memory locations being important -- perhaps affecting dictionary
hashes or some such thing?). Difficulties yes, maybe painful ones, but no
showstopper so far as I can see to writing out running code as Python
files (again, unless the above object ID issue).

I can see that nicer source will likely result from tracking commands as
the user defines them, as you suggest. But still, my focus isn't on
readable source. That's more a nice to have feature from my set of
priorities for GUI oriented construction and programming. What I am more
interested in is, can the running program be changed, and can the changes
be saved so they can be reloaded? So, our priorities may diverge there,
but that's OK -- makes life interesting. :-)

--Paul Fernhout
Post by Ian Bicking
Interactive sessions are source. The OB1 I referred to is the actual
object in memory, which has no real name, though it can be referenced
directly in memory.
Maybe a better example is something in HTConsole right now. Any
function you can get your hands on in HTConsole is editable, in-place.
import random
random.choice
And you'll get a form that shows the source to that function, and lets
you edit it. That works fine in-memory. But saving that is hard.
There's actually lots of ways to get access to a function. When you get
random.choice, you are actually getting access to a method of a
singleton stored in the random module. When you edit that, you are
editing the method. How do you represent that edit as source? Do you
see that the function is available as random.choice.im_func, or
random.Random.choice? Or a property, which might be available as
SomeClass.some_property.fget. There's lots of paths to functions, and
the function alone doesn't necessary know how to get to it. And
functions are relatively easy; other objects can be much harder...
items = range(5)
The contents of items cannot be edited in place, because they are
recreated dynamically. They can only be modified by later commands.
Keeping a log of commands is possible. But you aren't editing live
objects anymore, except perhaps an illusion of that. Instead you are
generating saveable commands from a specific location, which are
immediately executed to give you feedback but also saved so they can be
replayed in the future.
As I've been thinking about this, I think command generation is pretty
much like direct source modification, but direct source modification
also leads to nice source. So that's why I'm thinking that live objects
isn't a good metaphor, after going down that path some.
Paul D. Fernhout
2006-05-06 07:25:49 UTC
Permalink
Post by Ian Bicking
This is all not to say that modifying Python source in a manner
different than ASCII is infeasible. Only that "source" and "runtime"
have to be kept separate to keep this process sane. Images -- which
mingle the two -- have never felt sane to me; clever, but not
manageable.
Well, perhaps sanity is overrated. :-)

And Smalltalk has been managing this for thirty years. :-)

But it is true, it requires a bunch of special purpose tools. Changeset
browsers. A change log. External source code control. Image cloners. and
so on. Probably a Python that stored a running image as Python program
files might need some specialized tools too.

And I will go further and agree that I find mixing running application
state (like what windows are opened or what the stack looks like) with
application data (your email, your accounts receivable) is pretty scary too.

But again, one needs some sort of tools to help you with that, and there
is no reason some things can't be in the image and other things not in it.

In a Smalltalk system, generally there is at least a file with library
source code and a file with user additions to that as a current change
log. Although in the case of Squeak, it can decompile methods (if it saves
comments) even if you don't have the source code. One of the people on the
project (Alan Kay or Dan Ingalls?) quipped something to the effect that a
Squeak image was really a source code compression algorithm with a
development environment thrown in for free.

But, a Smalltalk image is generally saved as binary objects. But now that
disk is cheap and cpu cycles plentiful, storing an image as python program
files seems OK to me resource-wise.
Post by Ian Bicking
Unfortunately we do not have very good abstractions in
Python related to source, so they have to be invented from scratch. The
AST might help, but higher-level abstractions are also called for. For
instance, you might define a color interactively in some fashion, and
import color
color.Color(r, b, c)
That color object might be immutable (probably should be), but the
*source* isn't immutable, and the source means something. How can we
tell what it means?
I'm not sure anyone needs to ever tell what that means, except the Python
parser when it reads in the code and runs it (in the context of other code
it also loaded). Obviously when code is being written out which can
reconstruct a current object tree, then the writing process needs to
understand what it means by each piece of code, especially as it might
refer to previously defined bits to shorten or make more readable the
output code file. But since it is writing the code, there should not be
any ambiguities of intent. The hardest issue perhaps becomes making the
results look as close to human written Python as possible (say, using
"class" to define a class instead of making a plain object and turning it
into a class by setting fields).
Post by Ian Bicking
I can imagine a bit of interaction between the source and the runtime to
do this. For instance, we might see that "color" is bound to a specific
module, and "color.Color" to a specific object. We'll disallow certain
tricks, like binding "color" dynamically, monkeypatching something into
"color.Color", etc. Ultimately figuring out exactly what color.Color is
isn't *easy*, but at least it is feasible.
Using existing introspection we can figure out some parts, some of the
sorts of things that IDEs with auto-completion figure out. They can
figure out what the arguments to Color() are and the docstring.
Perhaps you are thinking about this from the point of view of something
like PyDev parser, which reads Python code to syntax highlight it and
perhaps provide code assistance. But, since the code has already been
read, and we are manipulating the object tree directly, we know what
everything means, because we just look at what the objects are directly by
inspecting them. Granted, some of those objects represent code, and the
code may be wrong or ambiguous or confusing from the users point of view,
but that is ignorable by the code writer, which just writes out the
snippet of code the way a user put it in.
Post by Ian Bicking
But, you can also imagine adding an editor or other things to that
object; a richer form of __repr__, or a richer editable form than the
ASCII source. Maybe there would be a flag on Color that says it can be
called without side effect (meaning we can speculatively call it when
inspecting source); and then the resulting object might have something
that says it can be displayed in a certain way (with its real color),
and has certain slots you can edit and then turn into a new Color
invocation.
I can see the value of all this from the GUI side, with various desired
display options defined in the class or prototype. But again, Python
object are (or should be :-) constructible from scratch without calling a
class' init function. So, given that a writer can inspect an instance and
just write out all the fields in its dictionary and their values it seems
like we can write out any object (though perhaps it may need to
recursively write out parts of embedded objects first, and then perhaps
patch up circular references at the end).
Post by Ian Bicking
This is where the 'make' syntax starts to come into play again, or more
generally where declarative source comes into play. Take a typical
I like what you outline and I see how something like it could make the
code the output writer creates be more legible.
Post by Ian Bicking
This is all harder than what HTConsole is doing currently, mostly
because Python source introspection is much poorer than Python object
introspection.
Good point. And perhaps an area of Python that this project could work on?
Can you elaborate on what parts of source introspection might need the
most work and in what ways so that either programs or people can better
inspect running Python programs?
Post by Ian Bicking
Loading a Python program can already do anything, if you put the
commands at the top-level (not in a function). So Python source really
is focused on constructing objects -- even functions and classes are
*built* by the source, not declared by it, and so circular imports and
circular class references can be challenging as a result.
True. But, the writer should be able to figure out how to handle this,
perhaps using some sort of recursive process with a patch list and a
cleanup routine?

--Paul Fernhout
Ian Bicking
2006-05-07 00:00:54 UTC
Permalink
Post by Paul D. Fernhout
Post by Ian Bicking
This is all not to say that modifying Python source in a manner
different than ASCII is infeasible. Only that "source" and "runtime"
have to be kept separate to keep this process sane. Images -- which
mingle the two -- have never felt sane to me; clever, but not
manageable.
Well, perhaps sanity is overrated. :-)
And Smalltalk has been managing this for thirty years. :-)
But it is true, it requires a bunch of special purpose tools. Changeset
browsers. A change log. External source code control. Image cloners. and
so on. Probably a Python that stored a running image as Python program
files might need some specialized tools too.
Zope went down that path with through-the-web development with the ZODB
as the image. I think everyone agrees that didn't work. Smalltalk has
pursued that with more vigor, but I was never comfortable with the
image. In some ways you can read my comments as me figuring out just
why I dislike the image model.

I think it's important to figure out, because the image model seems very
compelling for an education environment.
Post by Paul D. Fernhout
Post by Ian Bicking
Unfortunately we do not have very good abstractions in
Python related to source, so they have to be invented from scratch. The
AST might help, but higher-level abstractions are also called for. For
instance, you might define a color interactively in some fashion, and
import color
color.Color(r, b, c)
That color object might be immutable (probably should be), but the
*source* isn't immutable, and the source means something. How can we
tell what it means?
I'm not sure anyone needs to ever tell what that means, except the Python
parser when it reads in the code and runs it (in the context of other code
it also loaded). Obviously when code is being written out which can
reconstruct a current object tree, then the writing process needs to
understand what it means by each piece of code, especially as it might
refer to previously defined bits to shorten or make more readable the
output code file. But since it is writing the code, there should not be
any ambiguities of intent. The hardest issue perhaps becomes making the
results look as close to human written Python as possible (say, using
"class" to define a class instead of making a plain object and turning it
into a class by setting fields).
With the color example, I'm really thinking about richer kinds of source
literals. Maybe color.Color(1, 0, 0) is a better example. You can
statically determine that is "red", and you could display it as red.

And maybe it's not that much of a stretch to think about the program as
a set of these objects. They aren't live objects, and they aren't
entirely equivalent to the live objects. So a function definition is a
source object; the function itself is the runtime object. We can treat
them as equivalent, until we get to the point that we want to update things.
Post by Paul D. Fernhout
Post by Ian Bicking
I can imagine a bit of interaction between the source and the runtime to
do this. For instance, we might see that "color" is bound to a specific
module, and "color.Color" to a specific object. We'll disallow certain
tricks, like binding "color" dynamically, monkeypatching something into
"color.Color", etc. Ultimately figuring out exactly what color.Color is
isn't *easy*, but at least it is feasible.
Using existing introspection we can figure out some parts, some of the
sorts of things that IDEs with auto-completion figure out. They can
figure out what the arguments to Color() are and the docstring.
Perhaps you are thinking about this from the point of view of something
like PyDev parser, which reads Python code to syntax highlight it and
perhaps provide code assistance. But, since the code has already been
read, and we are manipulating the object tree directly, we know what
everything means, because we just look at what the objects are directly by
inspecting them. Granted, some of those objects represent code, and the
code may be wrong or ambiguous or confusing from the users point of view,
but that is ignorable by the code writer, which just writes out the
snippet of code the way a user put it in.
You can't know much about the objects inside a function, because they
aren't bound to anything. You can know about objects defined at the
module level. So even with runtime interaction you really can't do a
whole lot better than PyDev.
Post by Paul D. Fernhout
Post by Ian Bicking
But, you can also imagine adding an editor or other things to that
object; a richer form of __repr__, or a richer editable form than the
ASCII source. Maybe there would be a flag on Color that says it can be
called without side effect (meaning we can speculatively call it when
inspecting source); and then the resulting object might have something
that says it can be displayed in a certain way (with its real color),
and has certain slots you can edit and then turn into a new Color
invocation.
I can see the value of all this from the GUI side, with various desired
display options defined in the class or prototype. But again, Python
object are (or should be :-) constructible from scratch without calling a
class' init function.
I don't understand what you mean here? Most objects aren't
constructible from scratch. Many objects are immutable, and can only be
recreated, not modified.
Post by Paul D. Fernhout
So, given that a writer can inspect an instance and
just write out all the fields in its dictionary and their values it seems
like we can write out any object (though perhaps it may need to
recursively write out parts of embedded objects first, and then perhaps
patch up circular references at the end).
You mean pickle?
Post by Paul D. Fernhout
Post by Ian Bicking
This is all harder than what HTConsole is doing currently, mostly
because Python source introspection is much poorer than Python object
introspection.
Good point. And perhaps an area of Python that this project could work on?
Can you elaborate on what parts of source introspection might need the
most work and in what ways so that either programs or people can better
inspect running Python programs?
There's a bunch of pieces. There's work already done on many of them,
and people (particularly in the IDE crowd) interested in refining that
work. It's not something I've done a lot with, but here's some
non-obvious pieces:

* Better source code readers. Perhaps the work on a Python API to the
AST would help here. Python 2.5 introduces a better internal model for
source (the AST), but actual access to that isn't worked out yet. It's
important to know how that abstract structure maps to actual source;
right now I think it just has a line-level granularity.

* The decompiling tools might be useful. There's already several; I
know they drop things, but I don't know what. I think they do pretty
well. If things like comments lived in the AST, that'd be great, but
they don't currently. I think some variable names might be lost too,
but I'm not sure.

* Tools to figure out the relations between modules. Or maybe more
generally, just a way of determining as much as possible statically.
PyChecker and other tools do this some. It doesn't have to be perfect.

* We can only really work with modules that can be safely imported and
do not care about their environment. Lots of modules aren't like that,
but I think those modules should just be given up on, or they need to be
fixed. PyChecker and other projects have to worry about this a lot, and
it's just not worth it -- environment-dependent modules just suck and
need to be fixed.

And maybe that's mostly it. The AST seems most important, though
current tools actually do a lot of the necessary parts.

So, for instance, I was stressed out about how a function gets edited in
place. But maybe that doesn't need to be too hard. A function usually
has a reference to where it comes from (the file and line number). You
could then parse the code to figure out where the function ends. Then
you rewrite the file with the new function definition, indented to the
same level as the old function definition.

Few other objects carry their source information. Modules do (just
their __file__). Classes do not, nor do attributes or other
assignments, and objects like lists often have no direct representation
in the source.

But classes are easy enough to figure out by just looking at the source,
and at least they carry their original name.

Well, at least this makes me feel a little better about what I want to
do with HTConsole. I just have to avoid editing objects that are not
obviously represented by source. I.e., you can edit/reassign variables
and class attributes and functions, but not instances or lists.
--
Ian Bicking | ianb at colorstudy.com | http://blog.ianbicking.org
Paul D. Fernhout
2006-05-07 15:08:35 UTC
Permalink
Post by Ian Bicking
Zope went down that path with through-the-web development with the ZODB
as the image. I think everyone agrees that didn't work. Smalltalk has
pursued that with more vigor, but I was never comfortable with the
image. In some ways you can read my comments as me figuring out just
why I dislike the image model.
Well, everyone? :-) Check out http://www.1010wins.com/ for what was, last
I heard, a major Zope site.

Still, a lot of peopel agree with you, so there are clearly issues here.
For all I know, that group is unhappy?

I myself like images you can build from text when you want to, but that
has never been the focus of most Smalltalks (and isn't for Squeak so far).
But, I think a truly Pythonic approach might insist on building objects
from text, although it is true that we have pickle, which uses text, but
not as a Python program.
Post by Ian Bicking
I think it's important to figure out, because the image model seems very
compelling for an education environment.
And John also made some of those points indirectly. I think from a
"classroom" standpoint, teachers generally want to be in control of what
the student sees, at least at first, and they also have short classes ("45
minutes) where they do not want to waste time on configuration. So,
preparing an image for kids and seeing it pop up exactly like you made it,
whatever the hardware (like Squeak can do) is a big win in a classroom
setting. Of course, I'm not big on conventional classrooms :-), but I
think images are desirable for independent or informal learning as well,
which can happen in fits and starts, where you might do something
intensely for days and then not revisit something until months later. And
it would be nice if everything was just the way you left it. Also, as a
developer of (hopefully open) educational simulations, I see the value in
being able to deploy the simulation as an image which people could then
modify to their own needs. So this is an area of overlap regardless of
educational paradigm.

Granted though, if you want to learn about the details of the machine you
are on, or the notion of a software stack, like Kirby pointed to a week or
two ago, in terms of getting into the specifics of GNU/Linux, then images
are hiding stuff you might want to make visible. (Of course, you could
open a terminal window from your running image. :-)

I think a big issue with "images" is that they presume that you will put
in the time to learn the tools assembled in the image (assuming the image
is mainly about learning programming) rather than use some older ones you
are comfortable with already. It is much easier to type text on the
command line or use your favorite text editor than to learn an IDE
(especially when you are learning a new language at the same time). But
the value of learning an IDE can be immense in terms of letting you manage
complexity far beyond what you can do with a text editor.

It is funny how we can all accept that learning to play a musical
instrument like the flute might take years of concentrated study to even
get a good "tone" out of it, but we expect computers to be engaging on a
minute by minute basis. Or, we just accept that learning to touch type
takes days of practice. But computer IDEs? Do they really need to be like
video games, engaging and addictive from the first quarter?

John Holt wrote on this when he talked about "hard fun" (also mentioned
here recently in another context I think) and how playing music,
considering the suffering involved to get good at it, could hardly be
described as "fun", but there certainly is something there for many people
that keeps it engaging as a transcendental experience (as a sense of
"flow"). Still, I think people here are right when they suggest typing at
the command line an doing text processing produces feedback that keeps
people engaged. The question is, can a graphical IDE do that, and I think
the answer with Self might usually be "yes". I think the answer with
"Squeak" is sometimes "no" though, but I have real experience with that,
and have still never used Self. :-)

Still, the "E" in CP4E is about "Everyone", so I can see the value in
trying to make things accessible to broader audiences. My hope is that
both the expert and the novice can be satisfied by a better system, and I
think "Self" (or to a lesser extent "Squeak") helps show that way,
prudcing a system I can love as an expert, but (taking their word for it,
at least for Self :-) I think novices can warm to quickly as well. That
gets back to the point I made on innovation -- satisfying both needs at
once (e.g. expert and novice both love it) rather than compromising
somewhere between them (e.g. not so hard for novices, but not so
interesting for experts).
Post by Ian Bicking
Post by Paul D. Fernhout
I can see the value of all this from the GUI side, with various desired
display options defined in the class or prototype. But again, Python
object are (or should be :-) constructible from scratch without calling a
class' init function.
I don't understand what you mean here? Most objects aren't
constructible from scratch. Many objects are immutable, and can only be
recreated, not modified.
OK, good distinction. But the immutable ones are (always?) recreateable
from code? And the rest can be made by creating a bare object "object()"
and filling in its dictionary?
Post by Ian Bicking
Post by Paul D. Fernhout
x = object()
x
<object object at 0xb7e503b8>
... pass
...
Post by Ian Bicking
Post by Paul D. Fernhout
x.__class__ = Foo
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __class__ must be set to new-style class, not 'classobj' object
I do not yet understand that error.

I guess, there might also be objects that wrap external resources like
sometimes handles to bitmaps where those resources could not be accessed?

In Smalltalk, this is handled in part by the distinction between "new" and
"basicNew", e.g.:
http://lists.squeakfoundation.org/pipermail/squeak-dev/2003-May/057790.html
where "new" may call initialization methods with various side effects
(often just "self basicNew initialize"), but "basicNew" just gives you the
object of that class without much data in it (so you can call initialize
yourself or do something else). The message "basicNew" is what is used
typically by Binary Object Streaming systems when objects are recreated,
then they fill in the fields from what is in the file.
Post by Ian Bicking
Post by Paul D. Fernhout
So, given that a writer can inspect an instance and
just write out all the fields in its dictionary and their values it seems
like we can write out any object (though perhaps it may need to
recursively write out parts of embedded objects first, and then perhaps
patch up circular references at the end).
You mean pickle?
Well, a pickle-like system that writes out (hopefully readable) Python
program code, yes.
Post by Ian Bicking
There's a bunch of pieces.
Thanks for the elaboration on this. I need to think more on these points
you raise.

Still, it seems your focus here in what you outline as outstanding issues
is more on reading and preserving and otherwise handling human written
source code or the complexity of a large multi-module textually defined
program (which is understandable for you are writing an IDE in a sense,
where you want to give the user/developer help *before* the program is
running) then reading and preserving objects (where source code may be
just part of what is stored, and the user/developer is given help *while*
the program is running). Perhaps the difference is that with an IDE you
care more about how the objects are going to be created (given you are
helping the user to write programs to do just that), whereas with saving
and reloading an image I just care about anything that works and is
marginally understandable for debugging the save/load process, expecting
the coding to be done within the IDE on a fine grained basis (i.e. you are
just look at one function at a time in a browser, like in Smalltalk,
rather than scrolling through a file). Not to say producing clean readable
Python programs as images isn't a good goal down the road for me, but
clearly with an IDE it is your upfront goal. I think an innovative
convergance comes if a new system with an image works well enough that
people would choose using it to program over just editing long text files.

--Paul Fernhout
kirby urner
2006-05-07 15:53:34 UTC
Permalink
Post by Paul D. Fernhout
It is funny how we can all accept that learning to play a musical
instrument like the flute might take years of concentrated study to even
get a good "tone" out of it, but we expect computers to be engaging on a
minute by minute basis. Or, we just accept that learning to touch type
takes days of practice. But computer IDEs? Do they really need to be like
video games, engaging and addictive from the first quarter?
This question defines a long-running theme here on edu-sig and I think
you phrase it beautifully.

I just don't see getting away from the intricate syntax of Latinate
computer languages any time soon. They're intrinsic to the mix.
However, we may have higher level simulation languages, where just
dragging some ideogram or hieroglyph into a scene causes all these
emergent behaviors, thanks to algorithms encoded using lexical tokens.

Sometimes the knowledge domain we're hoping to model simply demands a
high end animation engine running in the background. The users of
this model don't participate in the source coding all that directly,
and have a more graphical IDE within which to set up their energy,
data, or currency flows. ESRI's use of embedded Python is a good
example: to the end user, it's drag and drop, but under the hood,
you're writing a Python script.

The trend in modern OSs is to provide 3D geometry capability through a
shared API in principle available to any hosted application. OpenGL,
Direct3D, Xgl... I'm thinking that education applications in the
"world" genre (like Squeak, like Uru, like ActiveWorlds) do well to
take advantage of this existing machinery and not reinvent these
wheels. But the glue layer, where the rubber meets the road, is still
lexical in nature. I don't care how pretty your canvas is, or what
kind of textured tube it came from (pneumatic, from Brazil?), it's
still Python or C# or SmallTalk or some Latinate doohinky under the
hood.

Which isn't to say we couldn't also go with Tibetan, Cherokee, Arabic,
Cyrillic or other unicode glyph language when committing lexical
tokens to a parser. In principle, source code doesn't have to be
Romanji. It just happens that's what most of it is so far, at this
point in world history, and it's working out pretty well. And as I've
said, it might be that the Kanji make more sense at a higher level
anyway, when we start with the graphical simulations and need ways of
counterbalancing various energies or whatever.

Kirby
Ian Bicking
2006-05-08 07:18:05 UTC
Permalink
Post by Paul D. Fernhout
Post by Ian Bicking
Zope went down that path with through-the-web development with the ZODB
as the image. I think everyone agrees that didn't work. Smalltalk has
pursued that with more vigor, but I was never comfortable with the
image. In some ways you can read my comments as me figuring out just
why I dislike the image model.
Well, everyone? :-) Check out http://www.1010wins.com/ for what was, last
I heard, a major Zope site.
Still, a lot of peopel agree with you, so there are clearly issues here.
For all I know, that group is unhappy?
There's a general consensus in the Zope community that through-the-web
editing and putting application code in the ZODB wasn't a good idea. So
they've moved on to other means of development, mostly with files on the
disk. At the same time, they've also moved away from the ideal of a web
development environment accessible to beginning programmers, which was
at least an early Zope goal. Though Plone is probably the exception to
both of these.

My impressions -- direct and indirect -- of what happens with typical
projects stored in the ZODB, is that they just had all of the normal
software engineering problems. But they weren't able to take advantage
of all the work people were doing in other environments -- version
control, Python's code layout (modules, packages, etc), and all the
other tools developers use. And maybe that's the only problem (though I
think there are others). On the measure of tools alone Smalltalk should
be fine, as they've written their own full stack of tools, even though
at the same time they pretty much isolate themselves from the mainstream
of tools.

I also hate the idea of extending Object, which is common in Smalltalk
(and Ruby, with no image), and my distaste for that might tinge my
feelings on images. Zope didn't add that, but it has its own ways of
introducing that same kind of complexity that I dislike.
Post by Paul D. Fernhout
Post by Ian Bicking
I think it's important to figure out, because the image model seems very
compelling for an education environment.
And John also made some of those points indirectly. I think from a
"classroom" standpoint, teachers generally want to be in control of what
the student sees, at least at first, and they also have short classes ("45
minutes) where they do not want to waste time on configuration. So,
preparing an image for kids and seeing it pop up exactly like you made it,
whatever the hardware (like Squeak can do) is a big win in a classroom
setting. Of course, I'm not big on conventional classrooms :-), but I
think images are desirable for independent or informal learning as well,
which can happen in fits and starts, where you might do something
intensely for days and then not revisit something until months later. And
it would be nice if everything was just the way you left it. Also, as a
developer of (hopefully open) educational simulations, I see the value in
being able to deploy the simulation as an image which people could then
modify to their own needs. So this is an area of overlap regardless of
educational paradigm.
I think there's a lot of practical problems with that. What happens
when you find a bug in the image? How do you figure out where code came
from? Is it system code, teacher code, peer code, your own code? If
you edit system code, you've made your image incompatible with anyone
else's image, and anyone who imports your change will probably be
corrupting their image.

And when you have this big ball of an image, the student has to choose
which line of continuity they want -- do they keep their code, or throw
it all away for the next class?

I'm all for making tight bundles of code with controlled environments;
that's important for everyone, not just classrooms. But there's another
line of control, which is how you integrate new packages into that
environment, and how you extract packages, and how you update packages.
A classroom should be as ready to do all of these things as
professional programmers, because they actually share all the same basic
needs -- fixing bugs, applying workarounds, sharing code, making code
reasonably portable (if only, for instance, to allow the teacher to run
it in their own environment).

Software engineering tools and methodology can be hard to adopt (even
for professional programmers), but there's also a lot of good ideas in
there that apply much more widely than just software. So I think it's
worth keeping all those processes in mind.
Post by Paul D. Fernhout
John Holt wrote on this when he talked about "hard fun" (also mentioned
here recently in another context I think) and how playing music,
considering the suffering involved to get good at it, could hardly be
described as "fun", but there certainly is something there for many people
that keeps it engaging as a transcendental experience (as a sense of
"flow"). Still, I think people here are right when they suggest typing at
the command line an doing text processing produces feedback that keeps
people engaged. The question is, can a graphical IDE do that, and I think
the answer with Self might usually be "yes". I think the answer with
"Squeak" is sometimes "no" though, but I have real experience with that,
and have still never used Self. :-)
Programming is definitely hard fun, and like music some people are very
much drawn to it and overcome all the hardness without being that
bothered. That probably describes the majority of the open source
community. But most people don't pursue music that seriously, even
given the opportunity -- hard fun isn't very fun for most people and for
any particular domain. I don't know if everyone has a hard fun that's
right for them, or not. I wish everyone had something, but
unfortunately I suspect that enjoying hard fun is itself something that
not everyone is prepared to do.
Post by Paul D. Fernhout
OK, good distinction. But the immutable ones are (always?) recreateable
from code? And the rest can be made by creating a bare object "object()"
and filling in its dictionary?
Post by Ian Bicking
x = object()
x
<object object at 0xb7e503b8>
... pass
...
Post by Ian Bicking
x.__class__ = Foo
File "<stdin>", line 1, in ?
TypeError: __class__ must be set to new-style class, not 'classobj' object
I do not yet understand that error.
you can't turn a new-style class into an old-style class by reassigning
__class__, but otherwise you can mess with that attribute pretty freely
(or mess with __class__.__bases__). object() also happens to not
accept attributes, though any subclass of object will. I'm not sure
what the justification is for that.
Post by Paul D. Fernhout
I guess, there might also be objects that wrap external resources like
sometimes handles to bitmaps where those resources could not be accessed?
Yes, that's very common. In general pickle-able objects can be
recreated; you can do the same basic thing with the new module, like
new.instance(Foo), and then update its __dict__ -- remembering that
assigning to attributes might not work, since those attributes might be
properties that expect the __init__ to have been called.

The object may register itself or do other things in __init__ as well,
so it's really hard to be sure you are doing the right thing.

Really, it's all the same issues pickle has, and pickle also has some
special methods so that most objects can be made pickleable. Some
things like open file objects just can't be pickled at all, ever --
though often you can make a pickleable wrapper that fulfills some more
abstract purpose, and use pickle's hooks to keep from trying to pickle
that objects entire __dict__ (which probably contains the unpickleable
file object).
Post by Paul D. Fernhout
Post by Ian Bicking
There's a bunch of pieces.
Thanks for the elaboration on this. I need to think more on these points
you raise.
Still, it seems your focus here in what you outline as outstanding issues
is more on reading and preserving and otherwise handling human written
source code or the complexity of a large multi-module textually defined
program (which is understandable for you are writing an IDE in a sense,
where you want to give the user/developer help *before* the program is
running) then reading and preserving objects (where source code may be
just part of what is stored, and the user/developer is given help *while*
the program is running). Perhaps the difference is that with an IDE you
care more about how the objects are going to be created (given you are
helping the user to write programs to do just that), whereas with saving
and reloading an image I just care about anything that works and is
marginally understandable for debugging the save/load process, expecting
the coding to be done within the IDE on a fine grained basis (i.e. you are
just look at one function at a time in a browser, like in Smalltalk,
rather than scrolling through a file). Not to say producing clean readable
Python programs as images isn't a good goal down the road for me, but
clearly with an IDE it is your upfront goal. I think an innovative
convergance comes if a new system with an image works well enough that
people would choose using it to program over just editing long text files.
In part I want to avoid a disconnect between the two styles of
development. This was another problem with Zope -- people would start
with the image/ZODB development, and then it was a really big leap to
get to the file-based development. So there was two classes of Zope
users, and they didn't always understand each other.

Also, I don't want to have to recreate version control tools, or
Python's module system, or the ability to share code freely, or any of
that stuff. I think a good way to avoid any problems with these tools
and processes is to just stick to conventional program representations.
--
Ian Bicking | ianb at colorstudy.com | http://blog.ianbicking.org
Paul D. Fernhout
2006-05-06 06:44:04 UTC
Permalink
Post by Ian Bicking
http://livelogix.net/logix/) makes me think that this could be done in
CPython now, with just some fiddling in the compile process. I think
the Python object model (which can't easily be changed) is already
flexible enough for this.
And ignoring some syntactic details you could do this in current CPython.
Interesting concept, to put it mildly. And also interesting under "future
work" they say:
http://livelogix.net/logix/future-work.html
"Although Python has provided a great launch pad for Logix, we may switch
to another platform at some point. Efficiency and security are two areas
that are somewhat lacking with a Python foundation. What are the
alternatives? Maybe Mono, maybe Parrot, maybe C--, maybe LLVM..."

I know that is one of the reasons I still think about doing something (at
least proof of concept) in Jython -- because it can piggy back on the Java
JVM security model, and I might also consider writing a low level routine
for handling networked programming in Java (if speed was an issue, after
doing it all first in Jython). [But, I've also been looking at working
with the Idle codebase too, by building on its RPC functionality.]

Still, the less I can mess with the syntax the better, I think. That's why
I lean towards just having one "Prototype" class.
Post by Ian Bicking
Post by Paul D. Fernhout
I think that Ian's suggestion is the most sensible strategy for proceeding
in that direction and continuing to maintain community interest in a
PySqueak inclined towards Self-like prototypes and a related GUI for
constructivist educational use (and other general use as well).
And if metaclasses turn out to not be the best approach,
still anything simple which preserves the Python syntax
while giving the new features (say, having all prototypes inherit from
a common class which overrides __getattr__ and __setattr__ to
simply look into the instance to find data and behavior?)
I think it could be easier than that. I think a lot of the more
declarative programming I do really has prototypes underneath it.
(Ironically in Javascript I never find a need for prototypes, except to
simulate classes.)
Of course, you probably don't have a Self-like environment for Javascript.
:-) Or is there one? I've never done much with JavaScript.

I did once listed about 100 reasons to use VisualWorks Smalltalk over C+++
without having to talk specifically about object-oriented programming
issues -- just focusing on the environment and the libraries and the VM
and issues like garbage collection and integrated fine-grained version
control.

Anyway, I tried to follow your example, but I am still left confused as to
how it is easier than creating GUI tools that manipulate all instances of
just one Prototype class? Your example still seems focused on making
classes. With one class, a few lines of code to search for values through
parent slots and you're done? Essentially, for any prototype-ish work, one
would just work with instances of this one class. Am I missing somethgin
vital here? Are you thinking about one class per one prorotype object? Is
that for performance reasons?
... def __getattr__(self, name):
... print name
...
Post by Ian Bicking
Post by Paul D. Fernhout
x = Prototype()
x.spam("hello")
spam
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'NoneType' object is not callable
Of course it fails trying to call the None returned by default in
__getattr___ because the code just prints the field name, but you see I
could just have that __getattr__ method look into a field of the object
and return the function, or if it was not there, then start looking into
parent slots and recursing until it found it or gave up with a call to a
"does not understand" function (itself hookable).

I do think there might be issues to resolve in how instances of this class
interact with other python classes. But I am not sure how complex those
issues are, since everything to Python still looks just like a typical
python class. All calls work the same way? Or do they?

The issues might have more to do with the GUI and it being able to handle
dealing with instances of other classes, but that could be done in the
usual way such as with inspectors and such that Idle defines. A bit
klunky, but probably serviceable as a start?

Anyway, something to think more on. A proof-of-concept Prototype class and
a GUI to manipulate it should not be that hard. (Famous last words. :-)

Designing programming systems is so easy when you stop caring about
performance (at least in the short term). :-) But the advice I was given
long ago is, slightly updated, is: by the time you get it debugged and
anyone has noticed it, computers will be fast enough to run it. :-)

Anyway, are there compelling reasons why creating one class per prototype
is useful or better? Or maybe I am just missing something here.

Perhaps it is confusing in that we are talking about two issues. One is
saving the state of a running Python program with arbitrary classes and
instances which you have modified while it runs, and the other is an
application building process centered around prototypes with classes being
more a legacy thing.
Post by Ian Bicking
I'm not really sure how to fit HyperCard into this -- I don't have a
strong feel for what it really means. I suppose one aspect is that the
source code is not at the core; instead the card stack is (or whatever
content-centric metaphor you use), and code is attached there. Ad hoc
structured code doesn't work that well with a class... you get something
def bar(self)...
foo = Foo()
And the class/instantiation is just a kind of boilerplate. OTOH,
modules are another model; if each content-context (aka card) was a
module, you get some of the structure without the conceptual overhead of
the class.
Yes, it would be that simple using classes I think.

Or it could be done using prototypes:

p = Prototype()
p.border = "dotted"
p.background_color = "red"
p.foreground_color = Color.red # if allow mixing classes and prototypes
p.parent = CARD_TEMPLATE_PREVIOUSLY_DEFINED

But I kind of see HyperCard as more like just one set of widgets in a
Morphic style interface.

Have you had a chance to watch the Self video?
Another source for it:
http://www.smalltalk.org.br/movies/
If you haven't, I recommend it highly.

--Paul Fernhout
Ian Bicking
2006-05-06 21:35:05 UTC
Permalink
Post by Paul D. Fernhout
Post by Ian Bicking
Post by Paul D. Fernhout
I think that Ian's suggestion is the most sensible strategy for proceeding
in that direction and continuing to maintain community interest in a
PySqueak inclined towards Self-like prototypes and a related GUI for
constructivist educational use (and other general use as well).
And if metaclasses turn out to not be the best approach,
still anything simple which preserves the Python syntax
while giving the new features (say, having all prototypes inherit from
a common class which overrides __getattr__ and __setattr__ to
simply look into the instance to find data and behavior?)
I think it could be easier than that. I think a lot of the more
declarative programming I do really has prototypes underneath it.
(Ironically in Javascript I never find a need for prototypes, except to
simulate classes.)
Of course, you probably don't have a Self-like environment for Javascript.
:-) Or is there one? I've never done much with JavaScript.
There are some more sophisticated development environments for
Javascript, but I've never used any of them, only source editing.
Post by Paul D. Fernhout
Anyway, I tried to follow your example, but I am still left confused as to
how it is easier than creating GUI tools that manipulate all instances of
just one Prototype class? Your example still seems focused on making
classes. With one class, a few lines of code to search for values through
parent slots and you're done? Essentially, for any prototype-ish work, one
would just work with instances of this one class. Am I missing somethgin
vital here? Are you thinking about one class per one prorotype object? Is
that for performance reasons?
I think my example confused you, since "class" was a misnomer. That is,
you *can* subclass non-classes using the class statement. I was using
that to mean "clone and update". I.e.:

class foo(bar):
def spam(self): print 'hi'

That means "clone bar, and set foo.spam to this function". The use of
the class statement is a little confusing, which is why I would like a
make statement.

To get to mechanics, basically this class statement means:

foo = bar.__metaclass__('foo', (bar,), {'spam': spam_func})

So with the right fiddling you can "subclass" an instance. Anyway, I
like the syntax, and find it more comfortable than direct assignment
(especially for methods).

For direct assignment, you might find the "magic_set" decorator I wrote
useful: http://svn.colorstudy.com/home/ianb/ruby_blocks.py (toward the
bottom)

It lets you do:

@magic_set(foo)
def spam(self): print 'hi'

which handles the closure to add instance methods directly to instances
(which doesn't work if done just through assignment), among other
assignments. It uses the name of the first argument (self, cls, or
anything else) to determine what kind of function you are trying to create.
--
Ian Bicking | ianb at colorstudy.com | http://blog.ianbicking.org
Paul D. Fernhout
2006-05-06 23:25:08 UTC
Permalink
Post by Ian Bicking
I think my example confused you, since "class" was a misnomer. That is,
you *can* subclass non-classes using the class statement. I was using
that to mean "clone and update".
OK, that makes more sense to me, and now I can see the cleverness of it.
Took a while; thanks for being patient with me. :-)

And thanks for the pointer to your other stuff and magic set. I'm a big
fan of those collection block operations BTW (although they came from
Smalltalk before Ruby :-). Is that stuff under the Python license, or
something else? I might want to put it into PataPata, and I hope to use
the Python/Jython license for core classes, and then the GPL for any
stand-alone applications.

--Paul Fernhout
Paul D. Fernhout
2006-05-07 04:09:16 UTC
Permalink
Ian-

Thanks again for this pointer.

I've added two more proof of concept files to PataPata.

The second one demonstrates inheritance with a parent and two children,
as well as graphically displaying the morphs. See:
http://svn.sourceforge.net/viewcvs.cgi/patapata/PataPata/proof_of_concept_002.py?view=markup
I started trying to do it in OpenGL (which I have had working before) and
got some errors so punted and chose wx and 2D for that. I don't like
making initial proof of concepts that rely on too many dependencies.
OpenGL remains a real possibility down the road, but this one problem just
shows how installation issues can bite you (in this case, I had commented
out the driver for it in my xorg.conf file when I was having other
problems related to one of my two ATI cards having problems driving its
secondary display head, and didn't care to restart X in the middle of my
development to try fixing that.)

The third P.O.C. demonstrates the problem your solution addresses.
http://svn.sourceforge.net/viewcvs.cgi/patapata/PataPata/proof_of_concept_003.py?view=markup

I found two other variants of solutions on the web (differences include
are who does the wrapping etc.), and I need to decide how best to proceed
on that.
Links to these three options including yours:
http://svn.colorstudy.com/home/ianb/ruby_blocks.py
http://zephyrfalcon.org/weblog/arch_d7_2002_11_16.html
http://lists.canonical.org/pipermail/kragen-hacks/2000-September/000264.html
[The latter two are more specific to Prototype inheritance in Python.]

Going to be traveling much of next week, so probably not much more
activity on this for a while. Frustrating to me as I think this is just
picking up some speed. A little OpenGL, a few Self-like GUI widgets for
inspecting values like in the movie of just rectangles and lines and text,
using a wrapper approach for inserting methods into prototypes, adding a
remote debugging process perhaps derived from Idle, making some program
writing code derived from pickle perhaps, dropping in some bitmap and icon
content from our garden simulator, and the result might be a nice proof of
concept constructivist educationally-oriented system in a week's work or
so. Obviously not everything, and with very rough edges, but something
that could show the basic ideas. Sigh. With distractions, and part-time,
be nice to get all that together by the end of June, if that,
realistically. No promises though.

Thanks again for your feedback.

--Paul Fernhout
Post by Ian Bicking
useful: http://svn.colorstudy.com/home/ianb/ruby_blocks.py (toward the
bottom)
@magic_set(foo)
def spam(self): print 'hi'
which handles the closure to add instance methods directly to instances
(which doesn't work if done just through assignment), among other
assignments. It uses the name of the first argument (self, cls, or
anything else) to determine what kind of function you are trying to create.
Dethe Elza
2006-05-08 17:47:14 UTC
Permalink
Post by Paul D. Fernhout
Of course, you probably don't have a Self-like environment for Javascript.
:-) Or is there one? I've never done much with JavaScript.
Javascript is a prototype-based language deriving directly from Self.
Emulating inheritance-type OO is possible, but kind of a hack, mainly
done for folks who are new to prototype-based languages.
Post by Paul D. Fernhout
Designing programming systems is so easy when you stop caring about
performance (at least in the short term). :-) But the advice I was given
long ago is, slightly updated, is: by the time you get it debugged and
anyone has noticed it, computers will be fast enough to run it. :-)
That hasn't worked well for Squeak, in my experience. Every time I get
a faster computer I try it out, and it's still too slow to use.

Also, I think one big reason people are leery of putting all their
methods and changes on the root object (or even allowing key objects
to be modified) is that introspecting objects to find out what
messages they can be expected to respond to is a crucial learning
path. That is why Python doesn't let you extend object, string, or
int, for example, in order to keep the system predictable and reduce
the impact of running dir(string) to something a person can
understand. If you did that on a javax.swing.JButton (and Jython
implemented dir() so that it showed all available methods, which it
doesn't) then you would be overwhelmed with hundreds of options, many
of which are implementation details of AWT or Swing, or other widgets,
and very few of which are useful to the common expectations and needs
of using a simple button widget.

So, performance is part of it, but comprehensibility (is that a word?)
is the more important part. And yes, I realize that prototype-based
languages don't have to be like that, but when you can add methods to
root objects, the tendency is to do so, and it can make things very
hard to maintain. I know Ruby allows this, but haven't had enough
experience with Ruby to know if it's a problem. In Javascript, it
definitely is a problem, with libraries like Prototype encouraging
"let's stick every method on the root object" mentality and cluttering
the namespace. In Objective-C there is a nice middle ground, where
you can have a new object layer that adds methods to existing classes
when it is imported. So you can add things where they feel *right,*
but you're not encouraged to do so willy-nilly. That works for me.
Post by Paul D. Fernhout
Post by Ian Bicking
I'm not really sure how to fit HyperCard into this -- I don't have a
strong feel for what it really means. I suppose one aspect is that the
source code is not at the core; instead the card stack is (or whatever
content-centric metaphor you use), and code is attached there. Ad hoc
structured code doesn't work that well with a class... you get something
I think Hypercard fits into the conversation because (like in Morphic
(Self or Squeak)), you can access the script behind every widget at
runtime, as if each widget has its own "view source" window, except
editable. Which would be cool for Python to adopt, I think.
Post by Paul D. Fernhout
But I kind of see HyperCard as more like just one set of widgets in a
Morphic style interface.
Yes, very similar ideas. Also the game The Incredible Machine, with
it's halo of options around each object (though not editable).

--Dethe

Loading...