Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why does Dynamic Typing really matter?!?

4 views
Skip to first unread message

Jason Smith

unread,
Feb 6, 2003, 5:57:21 AM2/6/03
to
Hi All

I'm doing some research into language constructs, particularly dynamic
typing. What I'm looking for are examples in dynamically typed
languages that clearly illustrate the benefits that dynamic typing
give to a solution to a problem. I'm aware that dynamic typing
provides the following,


But what I want need is an solution to a problem that would not be
possible to replicate in a statically typed language...

Can anyone pt me in the right direction or provide a small example?

Thanks
Jason.

Daniel Dittmar

unread,
Feb 6, 2003, 6:40:37 AM2/6/03
to
Jason Smith wrote:
> But what I want need is an solution to a problem that would not be
> possible to replicate in a statically typed language...

Reflection: calling a method with a specific name of an object whose type is
unknown at compile time.
You might say that Java is a statically typed language and allows this. But
this is implemented by using the Object class for most values, thus backing
out to dynamic types.

SQL programming: in most languages, you cannot specify the types of columns
of a specific SELECT. Again, Java resorts to either the Object class or by
pushing the responsability to the programmer who has to choose a specific
type (ResultSet.getInt) which may fail at runtime.

XML: all data in an XML file or a DOM is of type string, but the schema may
specify that it is really an integer.

You could extend programming languages to be SQl or XML schema aware. But
then you'd lose much of the flexibility for which SQL and XML were choosen
in the first place.

Daniel

Laura Creighton

unread,
Feb 6, 2003, 6:10:15 AM2/6/03
to
> --
> http://mail.python.org/mailman/listinfo/python-list

Get a copy of _Design Patterns_ and then a copy of _Design Patterns
Smalltalk Companion_. Walk through the patterns one by one. Many
(I think more than half) of the Smalltalk ones discuss why theirs
is simpler than the C++ one due to the fact that Smalltalk is dynamially
typed. For a final cut, get Pattern Hatching, where you can watch
John Vlissides finally decide that something was 'not a pattern' because
it was too easy to do in Smalltalk :-)

But if it is Python code you wanted ...

I wrote this a while ago (hmm, quite a while since I needed to
import nested_scopes) when somebody wanted to see the Decorator
Pattern. Boy is it simple in Python ....

from __future__ import nested_scopes
import Tkinter

class WrappedWidget:
def __init__(self, frame, widgetType=Tkinter.Label, **kw):
self._widget=widgetType(frame, **kw)
self.bind("<ButtonPress-1>", self.gotPressed)

def __getattr__(self, name):
if name.startswith("__") and name.endswith("__"):
raise AttributeError, name
else:
return getattr(self._widget, name)

def gotPressed(self, event):
print 'I got Pressed!'
self.configure(bg='red')

###########################
if __name__ == '__main__':

root = Tkinter.Tk()
quit = Tkinter.Button(root, text="QUIT", fg="red", command=root.quit)
quit.pack(side='left')

Lab=WrappedWidget(root, fg='green', text='Label (default)')
Lab.pack(side='left', fill='both', expand = 1)

mydict={'fg':'yellow', 'text':'Button'}
But=WrappedWidget(root, Tkinter.Button, **mydict)
But.pack(side='left', fill='both', expand = 1)
root.mainloop()
--------------------------------------------


Simon Burton

unread,
Feb 6, 2003, 9:01:20 AM2/6/03
to Jason Smith
On Thu, 06 Feb 2003 02:57:21 +0000, Jason Smith wrote:

> Hi All
>
> I'm doing some research into language constructs, particularly dynamic
> typing. What I'm looking for are examples in dynamically typed
> languages that clearly illustrate the benefits that dynamic typing
> give to a solution to a problem. I'm aware that dynamic typing
> provides the following,
>

???

>
> But what I want need is an solution to a problem that would not be
> possible to replicate in a statically typed language...
>
> Can anyone pt me in the right direction or provide a small example?
>
> Thanks
> Jason.


It's not just about end results; dynamic typing allows
the developer to move code across types during prototyping and
rapid development. These advantages won't show up from looking
at (only) examples.

Simon Burton.

Peter Hansen

unread,
Feb 6, 2003, 8:57:49 AM2/6/03
to
Jason Smith wrote:
>
> I'm doing some research into language constructs, particularly dynamic
> typing. What I'm looking for are examples in dynamically typed
> languages that clearly illustrate the benefits that dynamic typing
> give to a solution to a problem. I'm aware that dynamic typing
> provides the following,

Oh, believe me, it provides much more than that! ;-)

> But what I want need is an solution to a problem that would not be
> possible to replicate in a statically typed language...

Although I wouldn't claim that there is NOT such a thing, I'm also
not sure that the existence of solutions which cannot be replicated
with statically typed languages is at all biggest benefit of a
dynamically typed language.

For me, Python provides as a result of its dynamic typing, much
higher productivity as I simply don't spend time worrying about
punching the keys that produce all that static typing information
for the compiler to use to tell me where I need a type case or
something like that.

Python also makes life simpler when I can provide an object which
has the necessary "interface" (in the sense of supporting the
method that will be called on it in the context in which I'm using)
without actually having to be derived from a specific parent class
or interface (i.e. with the necessity of providing all kinds of
methods which aren't needed in the context in question).

This is extremely useful for automated testing, such as is used in
Extreme Programming so heavily, especially for providing mock
objects to decouple sections of the system during testing. For
this reason alone, I think dynamically typed languages are often
more productive by a long shot in an XP environment than any
statically typed languages.

-Peter

Paul Rubin

unread,
Feb 6, 2003, 9:14:18 AM2/6/03
to
chastel...@hotmail.com (Jason Smith) writes:
> Can anyone pt me in the right direction or provide a small example?

Try a Lisp book, like Lispcraft or even Structure and Interpretation
of Computer Programs.

The trendy Lisp descendant du jour though seems to be O'Caml, which is
statically typed (it's an ML dialect). I haven't done any programming
with it yet but would like to try. I really like what I've seen in
the docs.

Andrew Koenig

unread,
Feb 6, 2003, 9:18:31 AM2/6/03
to
Jason> But what I want need is an solution to a problem that would not
Jason> be possible to replicate in a statically typed language...

Forget it -- the closest you're going to find will be a program
that is significantly more difficult in a statically typed
language than in a dynamically typed one.

After all, you can always write an interpreter for a dynamically
typed language in a statically typed language.

--
Andrew Koenig, a...@research.att.com, http://www.research.att.com/info/ark

Cameron Laird

unread,
Feb 6, 2003, 9:53:40 AM2/6/03
to
In article <3E4269DD...@engcorp.com>,

All true, of course. I'll dramatize this in what strikes me
as Maoist rhetoric: we support dynamic typing not to change
types, but to ignore types. Types are a false overdetermin-
ation, as, at an earlier time and at a lower level, memory
addresses were. Memory and type management are just two of
several functions best left to the computer, so that coders
can concentrate on application-level concepts.
--

Cameron Laird <Cam...@Lairds.com>
Business: http://www.Phaseit.net
Personal: http://phaseit.net/claird/home.html

Alex Martelli

unread,
Feb 6, 2003, 10:11:13 AM2/6/03
to
Cameron Laird wrote:
...

> All true, of course. I'll dramatize this in what strikes me
> as Maoist rhetoric: we support dynamic typing not to change
> types, but to ignore types. Types are a false overdetermin-

Good point! It's rare (though interesting) to want to CHANGE
a given object's type -- for an interesting simple case see:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68429
(BTW, despite the doubts expressed in comments, the approach
does work with new-style classes too, to some extent).

but, it's not a deep and desperate need anyway (I do not know
of any case where I'd suffer a BIG loss of productivity if it
was impossible to change an object's type on the fly, _IF_
the whole system uses signature-polymorphism as below).


Relying on signature polymorphism instead of types is FAR more
frequent -- thus "ignoring types" in some sense except for
their signatures. C++'s templates are a decent example IMHO
(syntactically not so good, complicated, limited, but still a
decent example of the power of signature polymorphism). When
I was getting started with Python (as a C++ expert) there was
a "feeling" to it, for me, AS IF I was getting all of the good
things of templates without needing any effort to get them;-).


> ation, as, at an earlier time and at a lower level, memory
> addresses were. Memory and type management are just two of
> several functions best left to the computer, so that coders
> can concentrate on application-level concepts.

Good parallel. Of course in both cases I want to be able to
recover some control -- e.g. to check for memory leaks, or
to debug the cause of some type-error -- but by default and
most of the time, being able to avoid the issue helps;-).


Alex

David Eppstein

unread,
Feb 6, 2003, 10:53:10 AM2/6/03
to
In article <623cd325.03020...@posting.google.com>,
chastel...@hotmail.com (Jason Smith) wrote:

> But what I want need is an solution to a problem that would not be
> possible to replicate in a statically typed language...

Take a look at OS X's Cocoa undo manager.

Basically, every time you run a function that you want to be undoable,
you call the undo manager with the function that would be used to undo
it. The undo manager remembers these calls and performs them later when
undos are requested. It does redos by similarly remembering the calls
that would be used to undo what happened while it was doing an undo.
In practice this leads to very concise and straightforward looking code
that handles infinite levels of undo.

This was originally written in Objective C but due to the PyObjC bridge
can be performed just as well in Python. Here is a quick cut-down
example:

class MyDocument:
def rows(self):
return self._rows

def setRows_(self,r):
undo = undoManager().prepareWithInvocationTarget_(self)
undo.setRows_(self._rows)
self._rows = r

The "prepareWithInvocationTarget_" routine returns a special object
which remembers the methods called on it and calls them back on its
argument later. The return value of prepareWithInvocationTarget_ is a
value that acts like it has the same type as the argument, in that it
takes the same method calls, but the behavior is completely different.
I don't think this could be accomplished in a statically typed language.
Of course statically typed ui packages still may have undo managers but
they're more cumbersome.

--
David Eppstein UC Irvine Dept. of Information & Computer Science
epps...@ics.uci.edu http://www.ics.uci.edu/~eppstein/

Kaz Kylheku

unread,
Feb 6, 2003, 12:49:54 PM2/6/03
to
chastel...@hotmail.com (Jason Smith) wrote in message news:<623cd325.03020...@posting.google.com>...

> Hi All
>
> I'm doing some research into language constructs, particularly dynamic
> typing. What I'm looking for are examples in dynamically typed
> languages that clearly illustrate the benefits that dynamic typing
> give to a solution to a problem. I'm aware that dynamic typing
> provides the following,
>
> But what I want need is an solution to a problem that would not be
> possible to replicate in a statically typed language...

This is impossible, because of a little piece of theory known as
Turing completeness.

Any two languages that have the same level of access to the platform
in which they are running, and are both Turing complete, can---in
principle---solve all of the same problems, to the point that two
different programs written in one and the other exhibit identical
externally-visible behaviors.

However, one program may be significantly more complex, larger, and
much more difficult to understand, let alone maintain.

Dynamic typing allows programmers to write much smaller, more
expressive code.

It really is necessary; it's not just some tool that you can pull out
to solve a specific type of problem. It's generally useful in every
nook and cranny in a large program.

Compile-time declarations of type should be the exception, rather than
the rule! Static typing is an optimization technique---it lets the
compiler banish some of the run-time type information from the
representation of an object, and generate tight machine code.

There are all kinds of situations in which you don't care about the
type of an object, and want a variable that can represent any type.
For example ``shim functions'' that are interposed between two layers
in a program may just want to transparently communicate whatever those
layers want to say to each other.

Static typing is like having a specialized road for nearly every kind
of vehicle. Motorcycles go on this type of road, minivans go here,
large trucks go here, sub-compact sedans here, and so forth. You end
up with horrible inconveniences; there is way too much pavement
everywhere, and you can't go wherever you want in a straightforward
way. To get from point A to point B, you have to do stupidities, like
changing vehicles several times, wrapping your car inside a truck to
smuggle it through a trucking road, making several motorcycle trips
back and forth to get your goods across some point, and so forth.

It's a lot better to have a generic road shared by everyone. There are
fewer roads, and no artificial inconveniences.

> Can anyone pt me in the right direction or provide a small example?

How about the stupid circle-ellipse problem that OO flunkies like to
discuss over coffee?

This goes away even for mutable objects, when you have a dynamic type
system that lets you adjust the class of an object during its
lifetime.

The circle and ellipse really have two types: the manifest type
assigned by the programming language (which is invariably assumed to
be Java or C++) and the understood type which comes from the numeric
relationship of the object properties.

The whole crux of the matter is that the member variables of ellipse
can be mutated such that its understood type becomes ``circle''; but
the manifest type does not change. The programming language can fix
that: adjust the manifest type to match. The object then becomes a
language-level circle as well as a de-facto circle, and so methods
specializations over circle are now activated for that object for as
long as it remains a circle.

That would be an extreme example of the application of dynamic typing:
not all dynamic type systems support changing type at run time.

Kaz Kylheku

unread,
Feb 6, 2003, 12:52:28 PM2/6/03
to
"Daniel Dittmar" <daniel....@sap.com> wrote in message news:<b1thjl$phm$1...@news1.wdf.sap-ag.de>...

> XML: all data in an XML file or a DOM is of type string, but the schema may
> specify that it is really an integer.

This is an atrocious stupidity of XML, not an advantage of dynamic
typing.

If XML was designed by intelligent people, its data elements would be
properly typed, so the parser would put out strings, integers,
symbols, lists, vectors, complex numbers, floats, rationals, etc.

Mark McEahern

unread,
Feb 6, 2003, 12:11:51 PM2/6/03
to
[David Eppstein]

> Basically, every time you run a function that you want to be undoable,
> you call the undo manager with the function that would be used to undo
> it. The undo manager remembers these calls and performs them later when
> undos are requested. It does redos by similarly remembering the calls
> that would be used to undo what happened while it was doing an undo.
> In practice this leads to very concise and straightforward looking code
> that handles infinite levels of undo.

Fascinating. IIRC, Undo is covered as an example in the GoF Patterns book.
I wonder, though, would Undo be handled even more simply as an Aspect? That
is, rather than having to stuff some special incantation into the innards of
every function that you want to undo-enable, an Aspect Oriented Programming
approach would involve specifying the candidates for undo (I think this is
what join points are all about?) and then the special undo magic would Just
Happen (tm)?

I think the challenge with doing AOP in Python is deciding when/how you
define your join points.

(I'm hoping someone who actually knows something about AOP responds with
something more substantive than my vague wonderings. <wink>)

Cheers,

// m

-


David Eppstein

unread,
Feb 6, 2003, 12:26:39 PM2/6/03
to
On 2/6/03 11:11 AM -0600 Mark McEahern <mark...@mceahern.com> wrote:
>> Basically, every time you run a function that you want to be undoable,
>> you call the undo manager with the function that would be used to undo
>> it. The undo manager remembers these calls and performs them later when
>> undos are requested. It does redos by similarly remembering the calls
>> that would be used to undo what happened while it was doing an undo.
>> In practice this leads to very concise and straightforward looking code
>> that handles infinite levels of undo.
>
> Fascinating. IIRC, Undo is covered as an example in the GoF Patterns
> book. I wonder, though, would Undo be handled even more simply as an
> Aspect? That is, rather than having to stuff some special incantation
> into the innards of every function that you want to undo-enable, an
> Aspect Oriented Programming approach would involve specifying the
> candidates for undo (I think this is what join points are all about?) and
> then the special undo magic would Just Happen (tm)?

>From my limited understanding of AoP (we have a true expert here, Crista
Lopes, maybe I should ask her) it doesn't save you from the necessity of
writing actual code. You would still need to write the magic incantations,
but you could keep them in a separate aspect and not have to look at them
unless you wanted to think about undoing. Which could be good, if it
helped keep your view of the code simple, or bad, if it led you to forget
to keep the undo aspect synchronized with the rest of your code.

Jeremy Fincher

unread,
Feb 6, 2003, 1:19:11 PM2/6/03
to
cla...@lairds.com (Cameron Laird) wrote in message news:<v44tnkp...@corp.supernews.com>...

> All true, of course. I'll dramatize this in what strikes me
> as Maoist rhetoric: we support dynamic typing not to change
> types, but to ignore types. Types are a false overdetermin-
> ation, as, at an earlier time and at a lower level, memory
> addresses were. Memory and type management are just two of
> several functions best left to the computer, so that coders
> can concentrate on application-level concepts.

That's not an argument against static typing, it's an argument against
explicit typing. An implicitly statically typed language (one that
infers types at compile time, like ML) allows you to "ignore types" as
well as providing static assurance of type safety.

Jeremy

Daniel Dittmar

unread,
Feb 6, 2003, 1:06:54 PM2/6/03
to

This is just the point. When the programming language does not support
dynamic types, then there are three choices of accessing these values:
- compile the schema into the program (sometimes called data binding)
- return an abstract type and let the application do a downcast after a type
query (poor man's dynamic typing)
- have special accessor methods for every possible type (the JDBC approach),
which is only useful if the programmer has an idea on what the types will be
at run time (poor man's data binding)

Daniel

Jeremy Fincher

unread,
Feb 6, 2003, 1:22:21 PM2/6/03
to
Paul Rubin <phr-n...@NOSPAMnightsong.com> wrote in message news:<7xbs1p8...@ruckus.brouhaha.com>...

> The trendy Lisp descendant du jour though seems to be O'Caml, which is
> statically typed (it's an ML dialect).

Which definitely makes it not-a-Lisp-descendant ;)

Jeremy

Scott David Daniels

unread,
Feb 6, 2003, 3:43:23 PM2/6/03
to
Jason Smith wrote:
> ... I want need is an solution to a problem that would not be

> possible to replicate in a statically typed language...
>
> Can anyone pt me in the right direction or provide a small example?
>
> Thanks
> Jason.

While I wouldn't claim this is truly useful,
I would think self-apply would be tough in a statically
typed language (from what I recall of type theory).

def self_apply(x):
return x(x)

Show me a static typing for that (or for the args it takes).
------

On an only slightly more useful note:

def identity(whatever):
return whatever

class cell(object):
__slots__ = ['car', 'cdr']

def __init__(self, a, b):
self.car = a
self.cdr = b

def __repr__(self):
return 'cell(%s, %s)' % (self.car, self.cdr)

def free(self):
global _freelist

self.cdr = _freelist
self.car = identity
_freelist = self

def _allocate(whatever):
return cell(_allocate, whatever)

_freelist = _allocate(None)

def cell_alloc(a, b):
global _freelist
result = _freelist
_freelist = _freelist.car(_freelist.cdr)
result.car = a
result.cdr = b
return result


Deriving a static typing for _freelist might drive you nuts.

-Scott David Daniels
Scott....@Acm.Org

Giovanni Bajo

unread,
Feb 6, 2003, 7:24:02 PM2/6/03
to

"David Eppstein" <epps...@ics.uci.edu> ha scritto nel messaggio
news:eppstein-7A1A00...@news.service.uci.edu...

> In article <623cd325.03020...@posting.google.com>,
> chastel...@hotmail.com (Jason Smith) wrote:
>
> > But what I want need is an solution to a problem that would not be
> > possible to replicate in a statically typed language...
>
> Take a look at OS X's Cocoa undo manager.
>
> Basically, every time you run a function that you want to be undoable,
> you call the undo manager with the function that would be used to undo
> it. The undo manager remembers these calls and performs them later when
> undos are requested. It does redos by similarly remembering the calls
> that would be used to undo what happened while it was doing an undo.
> In practice this leads to very concise and straightforward looking code
> that handles infinite levels of undo.

This can be done in any statically-typed language in which functions are
first-class objects. This is not the case of C++ for instance, but it can be
faked quite easily with functors (boost::function). Once I have functors
(first-class object functions), I can implement the above very easily.
Actually, I've already done it some years ago.
I think there are much more important benefits with dynamic typing.

Giovanni Bajo


Alex Martelli

unread,
Feb 6, 2003, 7:36:24 PM2/6/03
to
Jeremy Fincher wrote:
...

>> as Maoist rhetoric: we support dynamic typing not to change
>> types, but to ignore types. Types are a false overdetermin-
...

> That's not an argument against static typing, it's an argument against
> explicit typing. An implicitly statically typed language (one that
> infers types at compile time, like ML) allows you to "ignore types" as
> well as providing static assurance of type safety.

To SOME extent. Haskell does, thanks to typeclasses, more than
SML. CAML and O'CAML reduces polymorphism to the point that
you have to write +. when adding floats, vs + when addint ints --
to claim that this lets you ignore types is ridiculous.

How much signature based polymorphism does the language
support? That is one key question. Haskell potentially offers a
lot, if you get your typeclasses right; various ML dialects offer
less, or none at all -- not supporting the concept of "classes of
types" (Haskell's typeclasses), they thereby don't let functions
you code be all that generic (except maybe in a few limit cases
such as SML supporting + on both floats and ints by special
casing). Type inference is good, but without typeclasses it does
not offer all that much over plain type declarations. WITH some
typeclass concept, it gets similar advantages to C++'s templates
(a bit better in some ways, a bit inferior in others, but overall
about as useful IMHO). Python happens to be yet smoother
(though it COULD use the concept of a typeclass or protocol
and adaptation thereto -- there's a PEP about that...).


Alex

Jason Smith

unread,
Feb 6, 2003, 7:54:58 PM2/6/03
to
Hi Alex

> but, it's not a deep and desperate need anyway (I do not know
> of any case where I'd suffer a BIG loss of productivity if it
> was impossible to change an object's type on the fly, _IF_
> the whole system uses signature-polymorphism as below).

"signature" polymorphism is the same as "explicit" bounded
quantification over types? i.e. haskell, forall a.b => a -> [String]
-> b etc...instead of letting the static inferencing take over..?

[snip C++ Templates]

I was under the impression that C++ templates were nothing more then a
macro hack by the preprocessor, though I would love to hear
otherwise..? please fill me in...

Thanks heaps...
J.

Jp Calderone

unread,
Feb 6, 2003, 7:57:31 PM2/6/03
to
On Fri, Feb 07, 2003 at 12:36:24AM +0000, Alex Martelli wrote:
> Jeremy Fincher wrote:
> > [snip]

>
> How much signature based polymorphism does the language
> support? That is one key question. Haskell potentially offers a
> lot, if you get your typeclasses right; various ML dialects offer
> less, or none at all -- not supporting the concept of "classes of
> types" (Haskell's typeclasses), they thereby don't let functions
> you code be all that generic (except maybe in a few limit cases
> such as SML supporting + on both floats and ints by special
> casing).

Jeremy probably knows better than I, but doesn't Caml support a similar
system to Haskell's typeclasses? I forget the name, but something to effect
of ...

type <symbol> =
<name0> of <type0>
| <name1> of <type1>
| ...;

Once upon a time, I wrote a serializer in Caml, and I used these to write
generic functions for groups of types.

Jp

--
#!/bin/bash
( LIST=(~/.netscape/sigs/*.sig)
cat ${LIST[$(($RANDOM % ${#LIST[*]}))]}
echo --$'\n' `uptime` ) > ~/.netscape/.signature
--
up 53 days, 3:50, 4 users, load average: 0.41, 0.40, 0.33

Jason Smith

unread,
Feb 6, 2003, 10:39:33 PM2/6/03
to
Hi Laura

Thanks for ur reply....sorry for the incomplete msg, sent it a bit
prematurely!

The book sounds very informative, will def pick up a copy, to bad our
local uni library is behind the times....

This sort of information is exactly what I'm after, I need to justify
a thesis question, that being adding extra, be it instructions, etc..
to the CLR to optimise the compilation of languages that are
dynamically typed...I'm looking at Soft typing as a method to increase
the range of programs I can type statically and for those that I can't
allow the CLR to perform dynamic type checks...

I'm not that familiar with python syntax, actually not familiar at
all, I'm mostly a Haskell hacker...

Thanks again
J.

Jason Smith

unread,
Feb 6, 2003, 11:01:18 PM2/6/03
to
Hi Daniel

Cheers, yes, Java performs a type check before assigning a class
created by reflection to a non-object typed reference, do u know if it
still performs a type check on Object typed references? I guess this
would be a implementation detail...I'm not familiar with XML to much
degree and will investigate what u have mentioned further.

Thanks again
J.

Donn Cave

unread,
Feb 6, 2003, 11:18:46 PM2/6/03
to
Quoth Jp Calderone <exa...@intarweb.us>:

| On Fri, Feb 07, 2003 at 12:36:24AM +0000, Alex Martelli wrote:
|> Jeremy Fincher wrote:
|> > [snip]
|> How much signature based polymorphism does the language
|> support? That is one key question. Haskell potentially offers a
|> lot, if you get your typeclasses right; various ML dialects offer
|> less, or none at all -- not supporting the concept of "classes of
|> types" (Haskell's typeclasses), they thereby don't let functions
|> you code be all that generic (except maybe in a few limit cases
|> such as SML supporting + on both floats and ints by special
|> casing). =20

|
| Jeremy probably knows better than I, but doesn't Caml support a similar
| system to Haskell's typeclasses? I forget the name, but something to effect
| of ...
|
| type <symbol> =3D

| <name0> of <type0>
| | <name1> of <type1>
| | ...;
|
| Once upon a time, I wrote a serializer in Caml, and I used these to write
| generic functions for groups of types.

Variants - you'd use them to define a set of types over which a
function should be defined, but it's a different way to approach
the problem than Haskell's classes. In my very inexpert guess,
it might work out about the same in terms of lines of code, but
Haskell's type classes are extensible. If lots of people were
using your serializer for one thing and another, I'd guess they
would be coming back to you for every new case and asking you to
add | <name122> of <type122> etc. to that type, and possibly their
support functions also.

With type classes, it's up to them to make their new type an
"instance" of your class and define the necessary functions.

The Caml version could probably be designed to do the same thing,
but not as transparently so to speak. I guess essentially you'd
be re-inventing the typeclass, as a record of functions that
implement the abstract interface for each (user) data type.

Donn Cave, do...@drizzle.com

Donn Cave

unread,
Feb 6, 2003, 11:20:59 PM2/6/03
to
Quoth k...@ashi.footprints.net (Kaz Kylheku):
...

| Static typing is like having a specialized road for nearly every kind
| of vehicle. Motorcycles go on this type of road, minivans go here,
| large trucks go here, sub-compact sedans here, and so forth. You end
| up with horrible inconveniences; there is way too much pavement
| everywhere, and you can't go wherever you want in a straightforward
| way. To get from point A to point B, you have to do stupidities, like
| changing vehicles several times, wrapping your car inside a truck to
| smuggle it through a trucking road, making several motorcycle trips
| back and forth to get your goods across some point, and so forth.

And you never send your bus into a grocery store by accident.

Donn Cave, do...@drizzle.com

Donn Cave

unread,
Feb 6, 2003, 11:48:11 PM2/6/03
to
Quoth "Donn Cave" <do...@drizzle.com>:
[... about Haskell type classes etc. ]

| The Caml version could probably be designed to do the same thing,
| but not as transparently so to speak. I guess essentially you'd
| be re-inventing the typeclass, as a record of functions that
| implement the abstract interface for each (user) data type.

And of course OCaml does support similar functionality through its
module system.

Donn Cave, do...@drizzle.com

Alex Martelli

unread,
Feb 7, 2003, 4:59:29 AM2/7/03
to
Jason Smith wrote:

> Hi Alex
>
>> but, it's not a deep and desperate need anyway (I do not know
>> of any case where I'd suffer a BIG loss of productivity if it
>> was impossible to change an object's type on the fly, _IF_
>> the whole system uses signature-polymorphism as below).
>
> "signature" polymorphism is the same as "explicit" bounded
> quantification over types? i.e. haskell, forall a.b => a -> [String]
> -> b etc...instead of letting the static inferencing take over..?

Nope. You can perfectly well let type inferencing do its
job -- but when it sees for example a + b it will infer that
a and b are in SOME type in class Num -- it won't infer the
exact type YET, because all types in class Num have a (+),
e.g. as Prelude.hs says:

class (Eq a, Show a) => Num a where
(+), (-), (*) :: a -> a -> a
[etc]

i.e., any type a is in class Num if there exist (+), (-) and (*)
as binary functions onto a (and also belongs to classes Eq and
Show, etc, etc).

Basically this is signature polymorphism at compile-time --
and so are C++'s templates, in a way that's not quite as
explicit or elegant, but has a few advantages of its own
in practical terms. Python does it at runtime -- slower
(and you need unit tests to catch some errors Haskell would
catch during the compilation phase -- but, as you DO need
unit tests anyway to catch most errors, no real problem),
not explicit, reasonably elegant IMHO, *very* practical.


> I was under the impression that C++ templates were nothing more then a
> macro hack by the preprocessor, though I would love to hear
> otherwise..? please fill me in...

The preprocessor doesn't know about types, so it can't do
zilch with templates. If I write, e.g:

template <class T>
T accumulate(T x)
{
static T gg;
gg += x;
return gg;
}

then by C++ semantics, accumulate must be instantiated exactly
once for each different type it's called with -- and implicitly
can only be called with a type that support copy construction
(because the argument x is passed by value, and thus also is
the result returned), default construction (because of the way
gg is declared), and operator +=. (A type with an inaccessible
destructor would also be inacceptable). This set of operators
and special methods that must be available on T make up the
(implicit) "signature" T must respect to be acceptable here
to the C++ compiler.

So, I can call accumulate(23) and get one compile-time
instantiation of the template with T set to int, then
accumulate(2.3) and get another with T set to double, and
when I then call accumulate(45) it must be the first one
that's used again (so the result is 68).

(Then it gets hairy because you can, and in some cases must,
explicitly control the instantiations -- but, hey, I NEVER
accused C++ of being _SIMPLE_ in any way...:-).


Alex

Laura Creighton

unread,
Feb 7, 2003, 4:30:43 AM2/7/03
to
> Hi Laura
>
> Thanks for ur reply....sorry for the incomplete msg, sent it a bit
> prematurely!
>
> The book sounds very informative, will def pick up a copy, to bad our
> local uni library is behind the times....

I don't think that your university library should be so behind the
times as to not have a copy of Design Patterns. They may not have a
copy of Design Patterns Smalltalk Companion, or Pattern Hatching.
DPST was designed to be read the way I suggested you read it ... with
DP (the original) in the other hand. It is not written with the
designer of a compiler or interpreter in mind, but rather an
applications programmer. What you get is a sense of 'this is a lot
shorter' and 'I can build a better abstraction of my problem in
Smalltalk because everything is an object', and the like. (Also a
sense of, multiple inheritance, <which Smalltalk doesn't have>, would
sure be convenient at times.) _You_ may, of course, get a sense of 'in
Haskell we do it _best_'.

If you don't know any Smalltalk a small detour to learn the syntax may
be in order. I forgot to mention that before, apologies.

Good luck,
Laura Creighton

Michael Hudson

unread,
Feb 7, 2003, 7:25:56 AM2/7/03
to
Jp Calderone <exa...@intarweb.us> writes:

> Jeremy probably knows better than I, but doesn't Caml support a similar
> system to Haskell's typeclasses? I forget the name, but something to effect
> of ...
>
> type <symbol> =
> <name0> of <type0>
> | <name1> of <type1>
> | ...;
>
> Once upon a time, I wrote a serializer in Caml, and I used these to write
> generic functions for groups of types.

The key difference between that and Haskell's typeclasses is that you
list all the possibilities in the declaration, whereas you can add to
a Haskell typeclass in a different module.

As someone else mentioned, Ocaml's modules provide similar
functionality (albeit in a rather different way).

At least, I think so. Yeech, it's been a while since I did any FP...

Cheers,
M.

--
The Programmer's Quick Guide To Python (Time Machine version):
You try to shoot yourself in the foot, only to realize that
there's no need, since Guido thoughtfully shot you in the foot
years ago. -- Nick Mathewson, comp.lang.python

Hrvoje Nezic

unread,
Feb 7, 2003, 8:37:10 AM2/7/03
to comp.lang.python
I am not a fan of dynamic typing. I have just
read again what Bertrand Meyer says about
dynamic vs static typing in his book
"Object Oriented Software Construction (2nd edition)"
and I tend to agree with him. I think that his arguments
are very sound (as usual, of course).

I think that both static and dynamic typing have
advantages and disadvantages. Perhaps this
is a matter of habit, but I like static typing more.

Among other things, Bertrand Meyer mentions
readability, and I agree with him (based on my
own experience).
You could argue that by not writing comments
or documentation strings, you write less code
(which is supposed to be good), but I don't think that such
reasoning is very smart. In my view, the same holds
for not writing type declarations.
Writing types documents what are you doing, or what
you intend to do.


Andrew Dalke

unread,
Feb 7, 2003, 9:44:47 PM2/7/03
to
David Eppstein:

> Take a look at OS X's Cocoa undo manager.
>
> Basically, every time you run a function that you want to be undoable,
> you call the undo manager with the function that would be used to undo
> it. The undo manager remembers these calls and performs them later when
> undos are requested. It does redos by similarly remembering the calls
> that would be used to undo what happened while it was doing an undo.
> In practice this leads to very concise and straightforward looking code
> that handles infinite levels of undo.

Can you or someone point me to a web page describing how to
implement do/undo/redo frameworks? I've been looking around
and found a few references, but would like a few more to make sure
I understand things rightly. Eg, I found the Cocao undo manager example
very interesting.

Andrew
da...@dalkescientific.com


David Eppstein

unread,
Feb 8, 2003, 12:41:09 AM2/8/03
to
In article <b21qof$sde$1...@slb5.atl.mindspring.net>,
"Andrew Dalke" <ada...@mindspring.com> wrote:

> Can you or someone point me to a web page describing how to
> implement do/undo/redo frameworks? I've been looking around
> and found a few references, but would like a few more to make sure
> I understand things rightly. Eg, I found the Cocao undo manager example
> very interesting.

For anyone else looking for them, the Cocoa undo manager docs are at
<http://developer.apple.com/techpubs/macosx/Cocoa/Reference/Foundation/Ob
jC_classic/Classes/NSUndoManager.html>
it doesn't say what the implementation looks like, but at least I think
the full API might be helpful.

An alternative technique I tried before getting the Cocoa one to work
for me: the undo controller stores two stacks of undo items, the undo
stack and the redo stack. Each item contains two functions, one to undo
and one to redo. To undo an action, pop the undo stack, call the popped
item's undo function, and push the item onto the redo stack. To redo an
item, pop the redo stack, call the popped item's redo function, and push
the item onto the undo stack. To perform a new action that can be
undone, put a new item onto the undo stack, clear out the redo stack,
and call the new item's redo function. It's a little less flexible and
more cumbersome than the Cocoa version, but it works.

A couple things to be careful of:

- It's very important that you tell the undo manager about any change
that any other undoable action depends on. If you do an action, then
change your data structures in a way that the undo manager doesn't see,
then undo your action, you could easily end up in an inconsistent state.

- For similar reasons, you should make sure that all pending changes
finish happening before you make an undoable action. Specifically, in
Cocoa, I was having a problem that when you edit a text item, the edit
isn't visible to the code until you finish it and move to another item.
If you start an edit and hit undo, the undo manager undoes whatever
you did previously, but you're still left in the middle of editing
something that may not exist any more after the undo. Result:
inconsistencies again. Solution: intercept undo/redo requests and force
any pending edits to finish before the requests reach the undo manager.

Edward K. Ream

unread,
Feb 8, 2003, 5:22:41 AM2/8/03
to
Leo implements undo using the same "string of beads" model found in yellow
box. It supports unlimited undo/redo in a very demanding environment, i.e.,
in an outliner in which a) outline nodes may be inserted, deleted, moved,
sorted, etc., b) text corresponding to nodes may be changed and c) the two
kinds of operations may be intermixed freely.

Here is the overview of undo from LeoPy.leo:

[starts]
Unlimited undo is straightforward; it merely requires that all commands that
affect the outline or body text must be undoable. In other words, everything
that affects the outline or body text must be remembered.

We may think of all the actions that may be Undone or Redone as a string of
beads (undo nodes). Undoing an operation moves backwards to the next bead;
redoing an operation moves forwards to the next bead. A bead pointer points
to the present bead. The bead pointer points in front of the first bead when
Undo is disabled. The bead pointer points at the last bead when Redo is
disabled. An undo node is a Python dictionary containing all information
needed to undo or redo the operation.

The Undo command uses the present bead to undo the action, then moves the
bead pointer backwards. The Redo command uses the bead after the present
bead to redo the action, then moves the bead pointer forwards. All undoable
operations call setUndoParams() to create a new bead. The list of beads does
not branch; all undoable operations (except the Undo and Redo commands
themselves) delete any beads following the newly created bead.

I did not invent this model of unlimited undo. I first came across it in
the documentation for Apple's Yellow Box classes.
[ends]

BTW, Python makes implementing this relatively easy. Each "bead" is simply
a dictionary containing whatever is needed to undo _and_ redo the operation.
setUndoParams has a **keywords parameter. The caller specifies whatever is
needed as keyword arguments; setUndoParams puts the items of the keywords
dict into the bead's dict.

Full details are in LeoPy.leo at
http://sourceforge.net/project/showfiles.php?group_id=3458 See the node
called @file leoUndo.py. There is some complex machinery involved behind the
scenes, and I have found that adding new undoable operations is
straightforward.

You will need to download and install leo2.py 3.10 to read LeoPy.leo,
although you could read the "raw" code of leoUndo.py at Leo's CVS site:
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/leo/leo/leoUndo.py?rev=1.37&content-type=text/vnd.viewcvs-markup

HTH

Edward
--------------------------------------------------------------------
Edward K. Ream email: edr...@tds.net
Leo: Literate Editor with Outlines
Leo: http://personalpages.tds.net/~edream/front.html
--------------------------------------------------------------------


Andrew Dalke

unread,
Feb 8, 2003, 12:52:54 PM2/8/03
to
Edward K. Ream:

> BTW, Python makes implementing this relatively easy. Each "bead" is
simply
> a dictionary containing whatever is needed to undo _and_ redo the
operation.
> setUndoParams has a **keywords parameter. The caller specifies whatever
is
> needed as keyword arguments; setUndoParams puts the items of the keywords
> dict into the bead's dict.

One of the papers I read used

class BaseCommand:
def Do(self):
...
def Undo(self):
...
def ReDo(self):
self.Do()

I bring this up because it said in a few cases, redoing needed different
behaviour
than doing. For example, the original Do may do a pop-up to get more
information
from the user, or verify a change, or give a "tip of the day" while the redo
shouldn't
do the same thing again.

> You will need to download and install leo2.py 3.10 to read LeoPy.leo,
> although you could read the "raw" code of leoUndo.py at Leo's CVS site:

I did try to install Leo a few weeks ago but ran into some problems.
I posted them in the thread "Hacking Heaven - Leo+XEmacs Integrated"
http://groups.google.com/groups?selm=b176jl%24vrg%241%40slb5.atl.mindspring.
net

Doesn't mean I can't take a look at the source code though :)

Andrew
da...@dalkescientific.com


Bernhard Herzog

unread,
Feb 8, 2003, 1:47:06 PM2/8/03
to
"Andrew Dalke" <ada...@mindspring.com> writes:

> Edward K. Ream:
> > BTW, Python makes implementing this relatively easy. Each "bead" is
> simply
> > a dictionary containing whatever is needed to undo _and_ redo the
> operation.
> > setUndoParams has a **keywords parameter. The caller specifies whatever
> is
> > needed as keyword arguments; setUndoParams puts the items of the keywords
> > dict into the bead's dict.
>
> One of the papers I read used
>
> class BaseCommand:
> def Do(self):
> ...
> def Undo(self):
> ...
> def ReDo(self):
> self.Do()

IMO undoing shouldn't be handled by the commands directly. This approach
might work well for documents with a relatively simple structure such as
e.g. a simple text editor where you can express all actions as
insertions and deletions.

For more complex documents the objects that make up the document should
take the burden of collecting the information of what needs to be done
when operations on them have to be undone. After all the objects are
responsible for the action in the first place and know best what
internal state needs to be remembered. With this approach the commands
only need to deal with undo in a very abstract and uniform way.

The approach I took in Sketch is described in
http://sketch.sourceforge.net/Doc/devguide-19.html


Recently I've started to think about a somewhat enhanced undo scheme.

In most programs the undo/redo history is completely linear. Once you
undo an operation you can redo it or you can do some different action.
If you don't redo your redo information is lost.

It might be useful to remember the redo information in that case so that
instead of a linear undo/redo model you get a tree. Of course there
would have to be a good way to communicate to the user what this tree
looks like which I'm not sure how to do.

The one program I regularly use that does not follow the common linear
model is Emacs which sort of uses a linearization of the above tree
model. Undoing in emacs is an action that itself can be undone. There is
no real concept of redo. Redoing is done by undoing the undo. For a
better description see
http://www.gnu.org/manual/emacs-20.3/html_node/emacs_19.html

Bernhard

--
Intevation GmbH http://intevation.de/
Sketch http://sketch.sourceforge.net/
MapIt! http://www.mapit.de/

Neil Hodgson

unread,
Feb 8, 2003, 5:29:36 PM2/8/03
to
Edward K. Ream:

> Leo implements undo using the same "string of beads" model found in yellow
> box. It supports unlimited undo/redo in a very demanding environment,
i.e.,
> in an outliner in which a) outline nodes may be inserted, deleted, moved,
> sorted, etc., b) text corresponding to nodes may be changed and c) the two
> kinds of operations may be intermixed freely.

Does Leo support "scoped undo" where you select a subset of the document
and ask for changes to be undone only for that code?

I'd really like to offer this for Scintilla but can't figure out a good
way to do it. Most of my thinking has involved splitting the document into
3: prolog, changing, and epilog where the prolog and epilog are constant
texts outside the changing scope and the changing text is a copy of the
original document which is undone with markers to show which section is
published back into the user-viewable document. But then I try and work out
how to graft the undo histories together (so you can do a scoped undo on one
section then on another) and I get really lost.

Neil


Edward K. Ream

unread,
Feb 8, 2003, 10:48:13 PM2/8/03
to
> Does Leo support "scoped undo" where you select a subset of the
document
> and ask for changes to be undone only for that code?

No. There seems to be no end to the number of improvements that can be made
to editors :-)

Actually, Leo might make this possible. The text is naturally divided into
trees and subtrees, so specifying a subtree in which to do the undo would be
easy. Alas, undoable operations can also change the tree structure. The
problem is less of implementation details than in trying to figure out how
to make a limited undo well defined.

In any event, all undo "beads" specify a "vnode" (part of the tree) on which
the operation is done...

Edward K. Ream

unread,
Feb 9, 2003, 9:35:03 AM2/9/03
to
> Actually, Leo might make this possible. The text is naturally divided
into
> trees and subtrees, so specifying a subtree in which to do the undo would
be
> easy.

However, Leo's clone features can have any change affect arbitrarily many
nodes (vnodes) in a tree. One could restrict operations to a list of
underlying shared text (list of tnodes), but that hardly seems like it would
be natural.

My own experience is that restricting the range of operations (e.g., to a
subtree, or selected text) is usually what is wanted. Messing with flexible
undo seems both hard and not all that useful. YMMV.

Doesn't Photoshop have some kind of flexible undo? If so, I would study
their model carefully.

David Eppstein

unread,
Feb 9, 2003, 2:38:09 PM2/9/03
to
In article <rGt1a.1528$6a2.5...@kent.svc.tds.net>,

"Edward K. Ream" <edr...@tds.net> wrote:

> Doesn't Photoshop have some kind of flexible undo? If so, I would study
> their model carefully.

As far as I can tell as a user of Photoshop, it has the usual linear
undo history, with two exceptions:
(1) Normally, as with most linear undo history systems, a new operation
clears out the redo part of the history. But if you immediately undo an
operation, it vanishes from the undo history and the previous redo
history is restored.
(2) You can assign names to states in the history, and return to those
named states. But these states do not carry any history with them, so
when you return to them, the undo/redo history is cleared out.

0 new messages