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

Integer micro-benchmarks [Smalltalk Multi-Precision Numerics vis-a-vis Highly Optimized Fixed Size Integer C++ Numerics]

0 views
Skip to first unread message

David Simmons

unread,
Apr 23, 2001, 9:26:10 PM4/23/01
to
This benchmark is actually a reasonable test of compiler (loop) optimization
and integer numerics optimizations.

On a 1.2GHz Athlon processor with:
512 MB memory
Dual Raid ATA 100 IBM Hard drives
Windows 2000 Professional Service Pack 2

I ran two different tests. The first one loops to generate "only"
SmallInteger sums; the (900,000) loop. The second test is based on the
originally posted sample and performs the 1,000,000 count loop; and thus
generates a significant number of large integers.

For each test I launched the application, ran it once and discarded the
result and shutdown. Then I repeated this same procedure three more times
and used the mean of the three runs.

Unoptimized C++ code: (Visual Studio 6 Service Pack 5 w/processor pack 1)
730ms for loop over 900,000
808ms for loop over 1,000,000

Best optimized C++ inlined code: (Visual Studio 6 Service Pack 5 w/processor
pack 1)
332ms for loop over 900,000
2.1988 : 1 Unoptimized C++ Ratio
374ms for loop over 1,000,000
2.1604: 1 Unoptimized C++ Ratio
**
Variations in the 3rd decimal place of above numbers are the result of
windows performance counter precision and OS process/thread slicing
variations.

For the C++ code and SmallScript the QueryPerformanceCounters call was used
to obtain the millisecond timings. Presumably similar timers are used within
VisualWorks and Dolphin (but I don't know).

NOTE: Use of GetTickCount() has rounding loss that can result in reporting
of times which are up to 20ms less than actual time.
**

In the following tables, "shorter" times and "smaller" ratios are better.

In summary, a Smalltalk VM (without using adaptive type based inlining) can
achieve roughly a 4:1 ratio of performance relative to highly optimized C++
code performing "pure" integer numerics. SmallScript's v4 AOS Platform
VM/Jitter *has not* been agressively tuned for numerics or similar
operations so I would expect nominal improvements of some form as it
matures.

To get a sense of what further adaptive inline compilation can achieve I
note that SmallScript on the v4 vAOS Platform VM will execute the 900,000
loop case in 1,215ms when the triangle method is inlined. If we assumed that
the JIT/compiler was capable of hoisting the invariant calculation of 10
triangle out of the loop then we would see a time of 95ms for SmallScript on
the v4 AOS Platform VM.

Remember: The Smalltalk code is performing multi-precision arithmetic and
thus has a significant number of overflow and type checks it performs. An
agressive adaptive inlining JIT compiler could dynamically eliminate many of
the typechecks by calculating the type graph for the code-flow tree and
generating separate versions based on likely types. Presumably this would
also allow most of the intermediate values to be retained in registers
rather than in stack local memory. The resulting ratio for multi-precision
numerics would most likely somwhere around 2 : 1 with highly optimized C++
performing *non-multi-precision-arithmetic*.

I should also point out that this kind of test represents a *worst-case*
type of scenario for Smalltalk (dynamic/script language) performance (where
it is handling arbitrary/multi-precision arithmetic) vis-a-vis statically
typed and highly optimized C++ code performing fixed size integer truncated
arithmetic.
=================================
SmallScript v4 AOS Platform VM
1,328ms for loop over 900,000
1.819 : 1 Unoptimized C++ Ratio:
4.000 : 1 Optimized C++ Ratio
1,576ms for loop over 1,000,000 (GC tuning for tight memory raises this
to 1,874ms)
2.159 : 1 Unoptimized C++ Ratio (2.567 : 1)
4.747 : 1 Optimized C++ Ratio (5.644 : 1)

Cincom VisualWorks 5i3NC
1,457ms for loop over 900,000
1.9959 : 1 Unoptimized C++ Ratio:
4.3886 : 1 Optimized C++ Ratio
1,789ms for loop over 1,000,000
2.4507 : 1 Unoptimized C++ Ratio:
5.3886 : 1 Optimized C++ Ratio

Dolphin Smalltalk Professional 4.01
12,086ms for loop over 900,000
16.556 : 1 Unoptimized C++ Ratio:
36.404 : 1 Optimized C++ Ratio
13,434ms for loop over 1,000,000
18.403 : 1 Unoptimized C++ Ratio:
40.464 : 1 Optimized C++ Ratio

I did not test VisualAge, Squeak, GNU, Gemstone. I did an empirical
(1,000,000) loop test with Smalltalk/X from CampSmalltalk#1 and it ran in
roughly 5212ms (this is only rough because I had to run the test on
different hardware using SmallScript and C++ as a baseline for scaling the
result).

-- Dave Simmons
www.qks.com / www.smallscript.com

"Bob Nemec" <bo...@home.com> wrote in message
news:D72166C0036950F6.D162DFAA...@lp.airnews.net...
> bran...@cix.co.uk says...
> > To make the measurements less dependant on specific hardware, I suggest
> > we express speeds as a proportion of C++'s speed doing the same thing
but
> > using fixed integers.
> >
> Interesting idea: a standard set of cross-language, cross-platform
> benchmarks.
>
> However, in general I think benchmarks do Smalltalk a disservice.
> Small tight independent chunks of code are not Smalltalk's strength;
> large complex systems are.
>
> The standard argument (which I agree with) is that Smalltalk can scale
> better than any other language, and that the truth of that statement
> becomes more self evident the larger your systems get.
>
> FWIW: I ran your little benchmark on VA, VW, Squeak and GemStone
> (care to publish a Window EXE with your C++ code? ... no compiler on this
> machine).
> The ratios are:
> VW: 1.0
> VA: 3.37
> Sqeak: 18.13
> GS: 25.61
>
> Details...
> "VW 3500"
> #(550000000 3500)
> #(550000000 3475)
> #(550000000 3712)
>
> "VA 11790"
> (550000000 11790)
> (550000000 11797)
> (550000000 11787)
>
> "Squeak 63440"
> #(550000000 63411)
> #(550000000 63471)
>
> "GemStone 89650"
> anArray( 550000000, 88897)
> anArray( 550000000, 90400)
> --
> Bob Nemec
> Newcastle Objects
> bo...@home.com


Dave Harris

unread,
Apr 24, 2001, 1:15:00 PM4/24/01
to
pul...@qks.com (David Simmons) wrote (abridged):

> I ran two different tests. The first one loops to generate "only"
> SmallInteger sums; the (900,000) loop. The second test is based on the
> originally posted sample and performs the 1,000,000 count loop; and
> thus generates a significant number of large integers.

Does this mean SmallScript's SmallInteger range is smaller than
Dolphin's? I tried to pick numbers that would give a long enough period
to measure, but without overflowing the local SmallIntegers.

My loop was actually 10,000,000 iterations, ie 10 times the figures you
say. The actual numbers shouldn't matter too much, as long as they are
large enough to reduce timing error.


> NOTE: Use of GetTickCount() has rounding loss that can result in
> reporting of times which are up to 20ms less than actual time.

On my machine, that would be an error of less than 2%, which I felt was
insignificant.


> Dolphin Smalltalk Professional 4.01
> 12,086ms for loop over 900,000

> 36.404 : 1 Optimized C++ Ratio

I am surprised you got 36:1 here, because my machine was giving 16:1. I'm
using 4.00, though.


> Cincom VisualWorks 5i3NC
> 1,457ms for loop over 900,000

> 4.3886 : 1 Optimized C++ Ratio

Thanks.


> SmallScript v4 AOS Platform VM
> 1,328ms for loop over 900,000

> 4.000 : 1 Optimized C++ Ratio

Impressive. Thanks for the results.


> I should also point out that this kind of test represents a
> *worst-case* type of scenario for Smalltalk (dynamic/script
> language) performance (where it is handling arbitrary/multi-precision
> arithmetic) vis-a-vis statically typed and highly optimized C++
> code performing fixed size integer truncated arithmetic.

Yes; the idea was not to compare Smalltalk to fixed-size C++ code, but to
some variable-sized C++ code. The fixed-size code just provides a
baseline for measurements between different machines. I'm not sure it's
working, though, as the Dolphin results vary so much.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

David Simmons

unread,
Apr 24, 2001, 3:29:14 PM4/24/01
to
"Dave Harris" <bran...@cix.co.uk> wrote in message
news:memo.20010424...@brangdon.madasafish.com...

> pul...@qks.com (David Simmons) wrote (abridged):
> > I ran two different tests. The first one loops to generate "only"
> > SmallInteger sums; the (900,000) loop. The second test is based on the
> > originally posted sample and performs the 1,000,000 count loop; and
> > thus generates a significant number of large integers.
>
> Does this mean SmallScript's SmallInteger range is smaller than
> Dolphin's? I tried to pick numbers that would give a long enough period
> to measure, but without overflowing the local SmallIntegers.

(I am now writing this comment after having written the sections to this and
the next paragraph of comments in your post. Your line of inquiry about
SmallInteger ranges was right on -- see the my comments on the the "wrong"
reported loop counts in the next section. However, having written this
explanation of tag-bits and SmallInteger representation I thought I would
leave it here anyway).

I think most (if not all) Smalltalk's use the same SmallInteger encoding.

Here's how it works:

On a 32-bit cpu architecture the OOP pointers are 32-bits. Smalltalk is a
dynamically typed language which means that type information is not required
for any expression, and variables are generic (typeless) containers.
Therefore all objects pointers (OOPs) must be self describing. I.e., it must
be possible to ascertain an objects type/class from its pointer. (You
probably knew all this but it doesn't hurt to explain it for clarity).

For certain types of objects their form of use is significant enough that it
justifies attempting some form of optimized representation.

The typical technique is based on recognizing that pointers to "real"
objects will be aligned on some multiple of a power of 2. Typically aligned
on 4-byte or for modern cpu cache efficiency (16-byte or 32-byte)
boundaries. That means that a "real" pointer will always have its least
significant lower bits equal to zero. I.e., aligned to say 16-byte
boundaries means that every "real" pointer must be a multiple of 16 so the
lower 4 bits (2^4 == 16) will be clear.

Recognizing that fact means that a design can cleanly use those bits to
indicate a pointer to a "virtual" object. This technique is called tag-bit
pointers and has been long used in the Smalltalk and Lisp/Scheme communities
to efficiently encode certain object types. Lisp implementations tend to use
more bits (and thus have more virtual tag-bit types) than Smalltalk
implementations but the technique is still the same.

Ok, with that bit a background I can explain the SmallInteger
representation.

On the v4 AOS Platform VM, there are three types of virtual object pointers:
SmallInteger, Character, WeakId. These corespond the various lower (tag-bit)
combinations of (11, 10, 01). The 11 combination is used for SmallInteger
because it has a different parity than the other two forms, which enables
exploitation of the x86 processors parity status tracking and subsequent
branch use. Ideally, a cpu designed to support hi-performance (tag-bit)
virtual machines would have explicit tag-bit instructions and a type lookup
base-register to support hi-perf tag bit actions. [I should also not that
internally the virtual machine may use the XX00 next two bits to mark
various "real" object pointers it passes around internally -- but it is too
complicated to explain why].

This means that out of the 32-bits available for a virtual-object pointer,
two (2) are used for the type/tag bits. Of the remaining 30 bits available
to represent a SmallInteger value, the high-bit (1-bit) is used to hold the
sign. Thus a 30-bit SmallInteger uses a signed 29-bit magnitude represented
in 2's complement notation on the modern processors. This gives positive
numbers the range 0..0x1FFFFFFF and negative numbers the
range -(1...0x20000000). The maximum positive SmallInteger value,
0x1fffffff, is decimal value 536870911 which as an internal SmallInteger OOP
representation as 0x7FFFFFFF.

So, given the original benchmark example, we note that its resultant "sum"
for a loop of 10,000,000 iterations totalled to 550,000,000 and for a loop
of 9,000,000 the sum totalled 495,000,000. From those numbers we can see
that a sum of 495,000,000 is within the SmallInteger domain; but a sum of
550,000,000 exceeds the maximum positive SmallInteger value of 536,870,911.

>
> My loop was actually 10,000,000 iterations, ie 10 times the figures you
> say. The actual numbers shouldn't matter too much, as long as they are
> large enough to reduce timing error.

Ahh, foobar, my error!

In writing the last part of the preceding section's paragraph I see what
happened.

The counts values written in the table in my post are missing a decimal
place relative to the actual loop counts used for the reported times.

When I began the writeup of that post, I looked at the 10000000 number and
the 9000000 number and said to myself, these long numbers are hard to read,
I should put comma's in to break them up. So I prepared a template for
reporting the results of each benchmark. The cut-&-paste template was
written up with loop counts which were missing a decimal place.

I.e., While I was writing the template (with comma spaced count ranges -- to
be helpful in reading) I dropped the zero on each count. I then cut and
pasted that template for each of the different benchmarks. I then went and
spent the majority of the time filling in the template with the accurate set
of reported timing numbers for the 1 decimal place larger counts of
10,000,000 and 9,000,000 loops.

****
The times and ratios reported in my original post are accurate (for the
larger loop counts), they were cut and pasted values from the actual runs
(and I just re-verified them). The times reported in the tables within my
post are actually from runs with loop counts of 10,000,000 and 9,000,000 NOT
the table's reported counts of 1,000,000 and 900,000.

I can't believe I missed this loop count decimal place during my pre-post
proofread. I still have not gotten used to the speed of my new machines
1.2GHz processor and my gut instinct in reading it did not get triggered --
I was focusing my analytical thoughts on the ratio's.
****

>
>
> > NOTE: Use of GetTickCount() has rounding loss that can result in
> > reporting of times which are up to 20ms less than actual time.
>
> On my machine, that would be an error of less than 2%, which I felt was
> insignificant.
>
>
> > Dolphin Smalltalk Professional 4.01

> > 12,086ms for loop over 900,000 <<<< **** 9,000,000 ****


> > 36.404 : 1 Optimized C++ Ratio
>
> I am surprised you got 36:1 here, because my machine was giving 16:1. I'm
> using 4.00, though.

Did you build the C/C++ code using Visual Studio 6 with optimizations?

It really makes a difference which optimization settings you have on and
what C++ compiler you use. Borland C++, gnu, Intel, Microsoft,...

I just re-ran the benchmarks and got the same result.

>
>
> > Cincom VisualWorks 5i3NC
> > 1,457ms for loop over 900,000 <<<< **** 9,000,000 ****


> > 4.3886 : 1 Optimized C++ Ratio
>
> Thanks.
>
>
> > SmallScript v4 AOS Platform VM

> > 1,328ms for loop over 900,000 <<<< **** 9,000,000 ****


> > 4.000 : 1 Optimized C++ Ratio
>
> Impressive. Thanks for the results.

Note that, to be on par with C++ inlining, we want to compare to the inlined
SmallScript version which reports a time of 1163ms which is a 3.472 : 1
ratio.

I should add that cpu code cache and corresponding alignment for jitted code
in methods affects the performance. This means that the same code executed
in a different memory configuration or method layout *may* report different
run times +/- roughly 10%.

Andrea Ferro

unread,
Apr 24, 2001, 5:43:33 PM4/24/01
to

Foreword: I actually never found a chance to use smalltalk. Several years ago I
personally purchased a Smalltalk/V box just to have a look at this language as
part of my never satisfyed curiosity, but never succeded in professionally sell
the use of this language. Fiew months ago my curiosity had me link this NG and
just read posts. I currently have no idea of where that old box is. But this
thread intrigues me.

Second Foreword: I have just seen the other post from David (the one with the
explanation of small integers) but I'm replying to this post because it's the
one that made me go to take my own test session.

"David Simmons" <pul...@qks.com> wrote in message
news:SC4F6.17406$Jh5.17...@news1.rdc1.sfba.home.com...


> This benchmark is actually a reasonable test of compiler (loop) optimization
> and integer numerics optimizations.
>
> On a 1.2GHz Athlon processor with:
> 512 MB memory
> Dual Raid ATA 100 IBM Hard drives
> Windows 2000 Professional Service Pack 2

I'm on a PIII 700 with Win2K Pro SP1. Memory, disk and similar stuff should not
be influent for these tests.

> I ran two different tests. The first one loops to generate "only"
> SmallInteger sums; the (900,000) loop. The second test is based on the
> originally posted sample and performs the 1,000,000 count loop; and thus
> generates a significant number of large integers.

Makes sense (expecially after reading your correction in the other post)!

> For each test I launched the application, ran it once and discarded the
> result and shutdown. Then I repeated this same procedure three more times
> and used the mean of the three runs.

It shouldn't have been much different! I was not that paranoic: I just run the
tests.

> Unoptimized C++ code: (Visual Studio 6 Service Pack 5 w/processor pack 1)
> 730ms for loop over 900,000
> 808ms for loop over 1,000,000
>
> Best optimized C++ inlined code: (Visual Studio 6 Service Pack 5 w/processor
> pack 1)
> 332ms for loop over 900,000
> 2.1988 : 1 Unoptimized C++ Ratio
> 374ms for loop over 1,000,000
> 2.1604: 1 Unoptimized C++ Ratio

I'm using the VC7 beta 1 compiler. The number of switches is huge. It makes not
much sense to have it timed with "non optimized" since that's probably just
"minimally optimized" with minimally having a huge variance. I know VC7 is
better than VC6 and probably I'm much better at getting best optimizations from
a C++ compiler (I'm C++ expert) than you are, but my timings (on a supposedly
slower machines) for the best optimization are terribly different. To have
better results had to run the loop 10 times more than you and disable some
optimizations !!! Read ahead.

> **
> Variations in the 3rd decimal place of above numbers are the result of
> windows performance counter precision and OS process/thread slicing
> variations.

I attacked this by looping longer. Read ahead.

> For the C++ code and SmallScript the QueryPerformanceCounters call was used
> to obtain the millisecond timings. Presumably similar timers are used within
> VisualWorks and Dolphin (but I don't know).
>
> NOTE: Use of GetTickCount() has rounding loss that can result in reporting
> of times which are up to 20ms less than actual time.
> **

I suspect some smalltalk implementations may use that. But it really does not
matter if you do it so many times.

> To get a sense of what further adaptive inline compilation can achieve I
> note that SmallScript on the v4 vAOS Platform VM will execute the 900,000
> loop case in 1,215ms when the triangle method is inlined. If we assumed that
> the JIT/compiler was capable of hoisting the invariant calculation of 10
> triangle out of the loop then we would see a time of 95ms for SmallScript on
> the v4 AOS Platform VM.

Well. I'm not that expert of smalltalk. But I'll tell you how I did my test and
you eventually suggest me what to do.

> I should also point out that this kind of test represents a *worst-case*
> type of scenario for Smalltalk (dynamic/script language) performance (where
> it is handling arbitrary/multi-precision arithmetic) vis-a-vis statically
> typed and highly optimized C++ code performing fixed size integer truncated
> arithmetic.

Yes. I know. And in fact I was surprised that it really is this fast, beside the
fact that C++ is much faster than you think on a good implementation.

> Cincom VisualWorks 5i3NC
> 1,457ms for loop over 900,000
> 1.9959 : 1 Unoptimized C++ Ratio:
> 4.3886 : 1 Optimized C++ Ratio
> 1,789ms for loop over 1,000,000
> 2.4507 : 1 Unoptimized C++ Ratio:
> 5.3886 : 1 Optimized C++ Ratio

This is the one I'm using. And what I did is adding the following to Integer

Integer>>triangle
| result |
result := 0.
1 to: self do: [ :i | result := result + i].
^result

then selecting the following in a workspace and "print it"

|sum time|
sum := 0.
time := Time millisecondsToRun: [
9000000 timesRepeat: [
sum := sum + 10 triangle]].
Array with: sum with: time.

It did print:

#(495000000 2849)

Just to get rid of the little variations in measurements I tryed this:


|sum tot time|
tot := 0.
time := Time millisecondsToRun: [
10 timesRepeat: [
sum := 0.
9000000 timesRepeat: [
sum := sum + 10 triangle].
tot := tot + (sum / 1000000) ]].
Array with: tot with: time.

And got:

#(4950 28810)

On the C++ side I tried this:

#include <windows.h>
#include <iostream>

int triangle( int x );

int main()
{
LARGE_INTEGER start, end, freq;

QueryPerformanceFrequency(&freq);
int tot = 0;
QueryPerformanceCounter(&start);
for ( int j=0; j<10; j++ ) {
int sum=0;
for (int i = 0; i != 9000000; ++i)
sum += triangle( 10 );
tot+=sum / 1000000;
}
QueryPerformanceCounter(&end);

__int64 delta = end.QuadPart - start.QuadPart;
__int64 mils = delta * 1000 / freq.QuadPart;

std::cout << "Time = " << mils << " result=" << tot << std::endl;
}

and I had a second file with this:

int triangle( int x )
{
int result = 0;
for (int i = 1; i <= x; ++i)
result += i;
return result;
}

Despite it being in a different compilation unit, I had VC7 with all
optimizations on to optimize everithing away and just precompute the final
result and call std::cout with it as a constant!!!! So I disabled "Global
Optimization" (that is I told it to not optimize across compilation units) and
here we go:

Time = 5585 result=4950

The order of magnitude is the same as your case.

However note: Smalltalk always has all the code at hand. C++ generally compiles
one module at a time. If I tell VC7 to optimize across compilation units it goes
to inline the triangle function and ... it does even optimize it out by pre
computing the result!!

Note that it is REALLY smart! I played with it and I could get it to a point
that it did not optimize the call out completelly but noted that triangle had no
side effect and always returned the same result for the same input so ... it
translated

for ( int j=0; j<10; j++ ) {
int sum=0;
for (int i = 0; i != 9000000; ++i)
sum += triangle( 10 );
tot+=sum / 1000000;
}

into something like

tot+= triangle( 10 )*9;

Not bad for an optimizer!

--

Andrea Ferro

---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info http://www.brainbench.com/transcript.jsp?pid=2522556

David Simmons

unread,
Apr 24, 2001, 10:11:38 PM4/24/01
to

"Andrea Ferro" <And...@UrkaDVD.it> wrote in message
news:9c4sjf$qo$1...@serv1.iunet.it...
...nice stuff snipped for brevity...

> >
> > On a 1.2GHz Athlon processor with:
> > 512 MB memory
> > Dual Raid ATA 100 IBM Hard drives
> > Windows 2000 Professional Service Pack 2
>
> I'm on a PIII 700 with Win2K Pro SP1. Memory, disk and similar stuff
should not
> be influent for these tests.

I provided this so folks would know the basics of the machine configuration
when they read the numbers. The memory is only important as it indicates
whether or not virtual-memory issues might be an issue. The raid drive
comments are not pertinent to this post, but in general they make a big
difference for virtual-memory performance, application launch times, and
visual-studio compilation speeds.

>
> > I ran two different tests. The first one loops to generate "only"
> > SmallInteger sums; the (900,000) loop. The second test is based on the
> > originally posted sample and performs the 1,000,000 count loop; and thus
> > generates a significant number of large integers.
>
> Makes sense (expecially after reading your correction in the other post)!
>
> > For each test I launched the application, ran it once and discarded the
> > result and shutdown. Then I repeated this same procedure three more
times
> > and used the mean of the three runs.
>
> It shouldn't have been much different! I was not that paranoic: I just run
the
> tests.

The main reason for launching and quitting was to:

Jiggle the OS memory management and "working sets" of other applications.

This can affect code loading and hardware cache operations as well as
process/thread slicing interrupts for the active foreground application.

Also, all things being equal the application will load the second time into
the same physical memory space and the cpu caches will still contain fresh
data. This allows for more consistent runs.

It would have been an unfair test to launch say VisualWorks (or Dolphin)
once and run and then quit. Relative SmallScript size and launch times, they
both have many more elements to the IDE's/images and thus use significantly
more resources. In VisualWorks case I wanted to ensure it have every chance
to warm its caches.

Although I didn't explain it carefully, I also ran the VisualWorks and
Dolphin code two or three times within a single session for a given image
before taking readings -- to warm up any hardware caches as well as their
JIT caches. I did not do this for SmallScript on the AOS VM, I simply ran it
as a script which launches a new process each time.

Possibly SmallScript might have been faster if I did a couple runs before
taking a reading -- but I was more interested in a from scratch
script-execution number for SmallScript results. However the cache impact
should have only made a significant difference in the 10,000,000 run case --
where GC and allocation might come into play. On the cited platform, the
basic SmallScript AOS Platform VM lifecycle "launch to quit + some script"
is on the order of 30-50 ms.

Basically I wanted to compare the Smalltalk systems in the mode I expected
them to be most commonly used in. Since SmallScript scripts will generally
execute via launching as a single run process or via its DLL loaded within
some parent process executed and then unloaded each time, it was important
to me measure it accordingly. This mode is a different mode from traditional
Smalltalk IDE images such as we see products such as VisualWorks and
Dolphin.

>
> > Unoptimized C++ code: (Visual Studio 6 Service Pack 5 w/processor pack
1)
> > 730ms for loop over 900,000
> > 808ms for loop over 1,000,000
> >
> > Best optimized C++ inlined code: (Visual Studio 6 Service Pack 5
w/processor
> > pack 1)
> > 332ms for loop over 900,000
> > 2.1988 : 1 Unoptimized C++ Ratio
> > 374ms for loop over 1,000,000
> > 2.1604: 1 Unoptimized C++ Ratio
>
> I'm using the VC7 beta 1 compiler. The number of switches is huge. It
makes not
> much sense to have it timed with "non optimized" since that's probably
just
> "minimally optimized" with minimally having a huge variance. I know VC7 is
> better than VC6 and probably I'm much better at getting best optimizations
from
> a C++ compiler (I'm C++ expert) than you are, but my timings (on a
supposedly
> slower machines) for the best optimization are terribly different. To have
> better results had to run the loop 10 times more than you and disable some
> optimizations !!! Read ahead.

I'm not sure I followed what you're trying to say here. I certainly have VS7
and the corresponding C++ compiler for it. But I'd be surprised if VS7
generated dramatically different code than VS6 for this simple function
example unless you've turned on global optimization and enabled static
analysis and computation that resulted in some loop hoisting -- in which
case I'd expect much more than a factor of 10 difference.

Background comment: I'd should mention that I work in C++ (for a variety of
projects) probably at least as much as Smalltalk and use it extensively in
the VM architecture. I would say that I'm reasonably expert with the all
aspects of the language (including templates) and exploit many of the
features in the AOS Platform VM design. I'm certainly familiar with most if
not all its esoterica from the language standard and I'm intimate with the
quirks, extensions, implementation and performance issues of the Visual
Studio families C++ compiler.

So if there is a problem with the C++ number it is more like due to a real
error :-( on my part rather than a lack of understanding of C++. Or,
possibly just problems in the code generation of Visual Studio vis-a-vis
what a better static optimizer.

Better still for our true testing purposes of raw numerics performance, what
a hand coded assembly routine would do. I probably should hand code an
assembly version since I'm really expert in that area and issues of
pipelining -- I have often had to do this for small hot-spot areas where a
C++ (or other static language) compiler just wasn't satisfactory.

>
> > **
> > Variations in the 3rd decimal place of above numbers are the result of
> > windows performance counter precision and OS process/thread slicing
> > variations.
>
> I attacked this by looping longer. Read ahead.
>
> > For the C++ code and SmallScript the QueryPerformanceCounters call was
used
> > to obtain the millisecond timings. Presumably similar timers are used
within
> > VisualWorks and Dolphin (but I don't know).
> >
> > NOTE: Use of GetTickCount() has rounding loss that can result in
reporting
> > of times which are up to 20ms less than actual time.
> > **
>
> I suspect some smalltalk implementations may use that. But it really does
not
> matter if you do it so many times.

Sure, you're right, that's just good statistical analysis.

I should probably make the somewhat lame comments that my goal in publishing
the numbers was not to do carry out the same level of effort and review I
would do for a formal technical paper on the topic -- such as one might read
in an OOPSLA proceeding. I was not trying to be particularly rigorous. To be
fair I'm quite busy on SmallScript and related matters and taking the hours
to do the tests and report them approaches the limit of my regular flex-time
for this kind of stuff under my schedule.

Minor nit that should have made no difference, you put the totals
calculation inside the millisecond timing loop. Ahh, never mind. I see you
did the same with the subsequent C++ code.

As you probably know, unlike C++ the Smalltalk compiler can't optimize
(inline) messages away because it can't rely on method definitions being
invariant. I.e., between the time a method is compiled and when it is
invoked, the methods it references may be replaced with new versions. Thus,
even if type inferencing could ascertain the correct binding information
(which is possible in this example), it doesn't help.

The only place where type information and bindings can be reliably and
safely inlined, given a dynamic and adaptive versioning execution
architecture, is in the JIT which has the knowledge and timing to know when
an inlined method has become stale and regenerate (dynamically) the inline
references.

This kind of virtual machine execution architecture not only means that
adaptive compilation leads to more version/change tolerant systems, but also
means that, in the case where there are variants, the JIT can use
heuristically acquired variant knowledge to (simplify and) optimize for
actual use cases which a "pure" static compilation analysis could not.

> C++ generally compiles
> one module at a time. If I tell VC7 to optimize across compilation units
it goes
> to inline the triangle function and ... it does even optimize it out by
pre
> computing the result!!

Global optimization in VC7 is one of the new features I had been waiting
for -- I just hadn't tried to compile the AOS Platform VM with it because it
is too bleeding edge for me rely on -- I've been bitten too many times that
way -- particularly with VS releases. I use VS7 where required to work with
.NET related IDE operations, C#, VB, and debugging.

Note that just because it is in a different compilation unit, the compiler
actually does have all the code in hand and my understanding is that it can
also do some level of analysis on the binary-machine code within a library.
I'm really surprised that "Microsoft's" C++ compiler was sophisticated
enough at doing invariant analysis to the point of computing the entire
result at compile time. I guess all the Microsoft dollars spent by their
research group on advanced languages (including ML) has paid off and was
incorporated -- very sweet -- I had not tested for this case.

>
> Note that it is REALLY smart! I played with it and I could get it to a
point
> that it did not optimize the call out completelly but noted that triangle
had no
> side effect and always returned the same result for the same input so ...
it
> translated
>
> for ( int j=0; j<10; j++ ) {
> int sum=0;
> for (int i = 0; i != 9000000; ++i)
> sum += triangle( 10 );
> tot+=sum / 1000000;
> }
>
> into something like
>
> tot+= triangle( 10 )*9;
>
> Not bad for an optimizer!

I would add that I've actually seen VS6 do seemingly similarly impressive
static analysis and reduction -- especially with inlining --including in
early VS6 before SP2 releases being too agressive with register coloring and
getting it wrong ;-). It begins to rival some of the better FORTRAN
optimizers -- but there are much better hardcore C++ compilers and VS6. I
don't know about VS7, although, given some of the Microsoft.NET platform
numerics I can see why it might have been worth investing a lot in the
static analysis :(.

A reasonable implementation of an adapative inlining JIT should have been
able to analyze the entire Smalltalk code set into a single computed
result -- and minimally should have been able to convert the 10 triangle
invariant away by moving out of the loop. It is probably worth obtaining a
copy of SELF and trying it -- or seeing how this performs in Java on a
HotSpot VM.

However, at the end of the day, the test we were originally interested in
were not in comparing static compilation invariant analysis. After all,
static analysis should be able to compute the entire problem at compile
time -- which, surprisingly, VS7 was actually capable of doing. That was
where my comment in my original post about how a SmallScript JIT with
adaptive inlining, invoking the call with a single argument (the nLoops
parameter) would have run the entire test in 95ms.

In my tests I wrote the C++ code as a series of functions. I built this as a
DLL and then invoked it directly from SmallScript.

static int triangle(int nInnerSum);
extern "C" DLLExport
void TimeTriangle(int nLoops, int nInnerSumInterations);

Where the central body of TimeTriangle was:

{
...
for(int i = 0; i != nLoops; ++i)
sum += triangle(nInnerSumInterations);
...
}

I'm assuming that VS7 would move (hoist) the triangle() invocation outside
the loop and substitute its computed value. So, build the test with VS6 or
one of the GNU compilers. Or see if you can turn off the loop invariant
analyzer or introduce some volatile constructs or place the
nInnerSumInterations into a shared global to throw off the compiler's
aliasing analyzer.

The static analysis and subsequent computation is not testing the actual
numeric performance issues we were interested in, although the loop
invariant hoisting is.

-- Dave S.

Dave Harris

unread,
Apr 25, 2001, 10:18:00 PM4/25/01
to
pul...@qks.com (David Simmons) wrote (abridged):
> Did you build the C/C++ code using Visual Studio 6 with optimizations?

Yes. The default set of optimisations (in release mode) for speed rather
than code size.

Steve Wart

unread,
Apr 25, 2001, 10:31:29 PM4/25/01
to
Here is some more silliness.

If you take the #triangle method and turn it into a block closure, as below,
in VW it takes almost 10 seconds (on my 333 PII)

"c.l.s. benchmark"
|sum time triangle result |
sum := 0.
triangle := [ :int|
result := 0.
1 to: int do: [ :i | result := result + i].
result ].

time := Time millisecondsToRun: [
10000000 timesRepeat: [
sum := sum + (triangle value: 10)]].
^Array with: sum with: time.

If you modify the above code so that the "result" instance variable is a
block temp, i.e.

triangle := [ :int| | result |
result := 0.
1 to: int do: [ :i | result := result + i].
result ].

It executes in under 7 seconds (same as if #triangle were a method on
Integer).

Something to do with the reification of the block temp I suppose [I only
know about this from reading a post by Allen Wirfs-Brock on the Squeak list
this am] :) Smalltalk MT does not allow block temps.

Does python have closures? That would be interesting to see.

Cheers,
Steve

David Simmons

unread,
Apr 25, 2001, 11:50:11 PM4/25/01
to
"Steve Wart" <sw...@deadspam.com> wrote in message
news:5MLF6.98590$166.1...@news1.rdc1.bc.home.com...

> Here is some more silliness.
>
> If you take the #triangle method and turn it into a block closure, as
below,
> in VW it takes almost 10 seconds (on my 333 PII)

Really! 10 seconds versus 7 seconds?

SIDEBAR: Man squeak sucks idle/cpu cycles. I just downloaded squeak. I left
it open and tried to run a benchmark in something else. It skewed the
benchmark by 25%.

Hmm. Ok, I quit squeak.

The execution time difference for SmallScript was around 4% relative to
having the <result> variable be local to the block. Internally the
difference is the direct result of the JIT not making the extra effort to
avoid redundant load/store access on an multi-level indirection of a shared
variable.

I guess that's not so surprising. Over the years I've been very aggressive
in having both the Smalltalk compiler and the VM optimize
closures/continuations, and related exception/curtailing scenarios.

Good goobley goo. I just ran it on VW and got the times:

1784ms for 9,000,000 loops using <result> local to the block.

4102ms for 9,000,000 loops using <result> as a method temp (shared with the
block).

The same runs on SmallScript were:
1313ms vs 1380ms respectively

NOTE: This is the exact same hardware on ran the previously posted tests on.

-- Dave S.

Steve Wart

unread,
Apr 26, 2001, 12:46:44 AM4/26/01
to
1.2GHz Athlon, Win2K SP2, 512Mb RAM -> David
333 PII, Win2K SP1, 192Mb RAM -> Steve
[I gotta get in Redmond's good books :)]

"David Simmons" <pul...@qks.com> wrote ...
> "Steve Wart" <sw...@deadspam.com> wrote ...


> > Here is some more silliness.
> >
> > If you take the #triangle method and turn it into a block closure, as
below,
> > in VW it takes almost 10 seconds (on my 333 PII)
>
> Really! 10 seconds versus 7 seconds?
>

> Good goobley goo. I just ran it on VW and got the times:
>
> 1784ms for 9,000,000 loops using <result> local to the block.
>
> 4102ms for 9,000,000 loops using <result> as a method temp (shared with
the block).
>

How come I have about a 30% difference and yours is over 100%? Is this a CPU
caching thing?

> The same runs on SmallScript were:
> 1313ms vs 1380ms respectively

This is the AOS VM? I wonder how it would do on the .NET VM? If you are not
at liberty to say, tap twice :)

Does SmallScript come with AOS?

Steve

Eliot Miranda

unread,
Apr 26, 2001, 1:00:31 AM4/26/01
to
Writing the benchmark as Dave Harris did in VisualWorks incurs a 4%
overhead for non-local variable access that you're not interested in
measuring. i.e. the assignment to sum from within the Time
millisecondsToRun: block is expensive. Further, to increase timing
consistency its good to get the code cache in a consistent, warm state.
In VW you can flush the code cache using a garbage collection. Then you
can run the benchmark code for one iteration to compile it and the run
it the desired number of times to collect the measurements. So for
example here's how I'd write the benchmark to illustrate the cost of the
non-local temporary access while attempting to eliminate timing jitter
due to code cache state and compilation overhead:

| n bms |
bms := Array
with:
[|sum time|


sum := 0.
time := Time millisecondsToRun:

[n timesRepeat: [sum := sum + 10 triangle]].
Array with: sum with: time]
with:
[|sum time|


sum := 0.
time := Time millisecondsToRun:

[ | innerSum |
innerSum := 0.
n timesRepeat: [innerSum := innerSum + 10
triangle].
sum := sum + innerSum].
Array with: sum with: time].
ObjectMemory garbageCollect. "flush code cache"
n := 1.
bms collect: [:ea| ea value]. "run once to get code compiled"
n := 10000000.
bms collect: [:ea| ea value] "perform the measurements" #(#(550000000
5349) #(550000000 5133))

5133 - 5349 / 53.49 -4.03814

and as Dave Simmons measurements put SmallScript at 1,576ms vs VW at
1,789ms VW is probably more like 1,717ms :)

Petty, moi?
--
_______________,,,^..^,,,____________________________
Eliot Miranda Smalltalk - Scene not herd

David Simmons

unread,
Apr 26, 2001, 2:48:09 AM4/26/01
to
"Steve Wart" <sw...@deadspam.com> wrote in message
news:UKNF6.98935$166.1...@news1.rdc1.bc.home.com...

> 1.2GHz Athlon, Win2K SP2, 512Mb RAM -> David
> 333 PII, Win2K SP1, 192Mb RAM -> Steve
> [I gotta get in Redmond's good books :)]

That's not how I got the machine if that's what you're thinking.

As I mentioned in some other posts, you can build my exact machine
configuration for under $2,000 (which is amazing to me). Actually, you can
build a better machine now for that money. I built my machine a few months
ago for under $2000.

My brother is in the process of building two new machines (w/slight
variances between them), each for under $2000 with the spifiest graphics
cards for games, DVD, sound system, ATA 100 raided 7200 RPM drives, 512MB
memory, and 1.3GHz Duron with the 266Mhz FSB. Earlier today, someone told
me you can buy the 1.7GHz Pentium processor for $350 now -- unbelievable...

As to the Win2K SP2, you just have to pay the annual MSDN fees of ~$600 for
professional subscription, or $2000 for universal subscription. Which is
basically on par with Apple's ADC fees for being a developer -- actually its
the model Microsoft copied and improved upon.

>
> "David Simmons" <pul...@qks.com> wrote ...
> > "Steve Wart" <sw...@deadspam.com> wrote ...
> > > Here is some more silliness.
> > >
> > > If you take the #triangle method and turn it into a block closure, as
> below,
> > > in VW it takes almost 10 seconds (on my 333 PII)
> >
> > Really! 10 seconds versus 7 seconds?
> >
> > Good goobley goo. I just ran it on VW and got the times:
> >
> > 1784ms for 9,000,000 loops using <result> local to the block.
> >
> > 4102ms for 9,000,000 loops using <result> as a method temp (shared with
> the block).
> >
> How come I have about a 30% difference and yours is over 100%? Is this a
CPU
> caching thing?

I don't know. I've re-checked the runs though because this stands out as
weird.

We should look further into this anomaly to understand it because it makes
the benchmarking numbers hard to properly assess.

Maybe Eliot could answer this one?

My only guess is that using a method temp is resulting in some kind of
context being allocated every time the block is evaluated. If so, it might
be a bug in the copying-block analyzer of the compiler?

>
> > The same runs on SmallScript were:
> > 1313ms vs 1380ms respectively

By the way, the Squeak (latest non-alpha version) runs on my box yielded:

20,940ms and 18,827ms respectively.

>
> This is the AOS VM?

Yes.

> I wonder how it would do on the .NET VM? If you are not
> at liberty to say, tap twice :)

Hmm, well, sorta. Tap once: Let's just say its markedly slower.

>
> Does SmallScript come with AOS?

Yes. Both the SmallScript compiler and a corresponding execution engine (the
core AOS Platform VM) will be free.

The SmallScript compiler and scripting/dynamic language support libraries
for the Microsoft.NET Platform will not be free. As to other frameworks,
tools, etc -- that will be determined on a case by case basis.

The AOS Platform is a quasi language independent
object-model/virtual-machine which is now in its 4th major generation since
I first designed it back at the end of 1990. That design was derived
(extensively influenced) from work I did on C based (vm) object systems
beginning back in 1986.

SmallScript began its life in 1998 as a new language that is derived from my
work in creating and evolving QKS Smalltalk from 1991 to 1998. SmallScript
includes all of the smalltalk "language" (not the ANSI Smalltalk frameworks
or Smalltalk-80 stuff) plus many other extensions.

-- Dave S.

>
> Steve

Steve Wart

unread,
Apr 26, 2001, 9:15:19 AM4/26/01
to

"David Simmons" <pul...@qks.com> wrote in message ...

> "Steve Wart" <sw...@deadspam.com> wrote ...
> > 1.2GHz Athlon, Win2K SP2, 512Mb RAM -> David
> > 333 PII, Win2K SP1, 192Mb RAM -> Steve
> > [I gotta get in Redmond's good books :)]
>
> That's not how I got the machine if that's what you're thinking.
>
Sorry if it came across the wrong way -- it was just a joke. My machine is
just over 3 years old now. But I wanna G4 :)

> > Does SmallScript come with AOS?
>
> Yes. Both the SmallScript compiler and a corresponding execution engine
(the
> core AOS Platform VM) will be free.
>
> The SmallScript compiler and scripting/dynamic language support libraries
> for the Microsoft.NET Platform will not be free. As to other frameworks,
> tools, etc -- that will be determined on a case by case basis.

So I can use SmallScript for free if I don't care about calling .NET
services? Which platforms are you planning to support with the AOS
VM/SmallScript? Mac/Linux/Windows at least?

> The AOS Platform is a quasi language independent
> object-model/virtual-machine which is now in its 4th major generation
since
> I first designed it back at the end of 1990. That design was derived
> (extensively influenced) from work I did on C based (vm) object systems
> beginning back in 1986.

What do you mean by "quasi language independent" -- that it supports
SmallScript and the "convential" AOS Smalltalk? Will it support python, for
example?

Steve (swart at bigserver dot com) -- .sig in progress
http://www.visualknowledge.com


David Simmons

unread,
Apr 26, 2001, 4:20:23 PM4/26/01
to
"Steve Wart" <sw...@deadspam.com> wrote in message
news:HbVF6.101237$166.1...@news1.rdc1.bc.home.com...

>
> "David Simmons" <pul...@qks.com> wrote in message ...
> > "Steve Wart" <sw...@deadspam.com> wrote ...
> > > 1.2GHz Athlon, Win2K SP2, 512Mb RAM -> David
> > > 333 PII, Win2K SP1, 192Mb RAM -> Steve
> > > [I gotta get in Redmond's good books :)]
> >
> > That's not how I got the machine if that's what you're thinking.
> >
> Sorry if it came across the wrong way -- it was just a joke. My machine is
> just over 3 years old now. But I wanna G4 :)

Oh geez, no need to apologize. But given this is a public venue, I want to
minimize the likelyhood that communications get distorted. Of late, a few
reported or re-discussed items have been unintentionally mis-stated in some
web sites, postings, and discussions that are circulating.

At this stage I have worked at keeping the activity as low (bandwidth) key
as possible while maintaining a necessary visible presence in certain key
areas. You can expect that pattern to remain until various pieces are
available for public review.

As to a G4...
I also use a dual 500MHz G4 for the PPC MacOSX work. I am an old hardcore
Mac developer -- its where our Smalltalk began its life. However, sad but
true, at this point in time I'll take my Win2K box with an AMD Duron chipset
anyday.

>
> > > Does SmallScript come with AOS?
> >
> > Yes. Both the SmallScript compiler and a corresponding execution engine
> (the
> > core AOS Platform VM) will be free.
> >
> > The SmallScript compiler and scripting/dynamic language support
libraries
> > for the Microsoft.NET Platform will not be free. As to other frameworks,
> > tools, etc -- that will be determined on a case by case basis.
>
> So I can use SmallScript for free if I don't care about calling .NET
> services? Which platforms are you planning to support with the AOS
> VM/SmallScript? Mac/Linux/Windows at least?

Free Base System: x86 Win32 platforms, x86 Linux and FreeBSD, MacOSX PPC.

Paid Base System: Microsoft.NET Tools and Platform Support

Others are always possible (and desired) at some future point.

>
> > The AOS Platform is a quasi language independent
> > object-model/virtual-machine which is now in its 4th major generation
> since
> > I first designed it back at the end of 1990. That design was derived
> > (extensively influenced) from work I did on C based (vm) object systems
> > beginning back in 1986.
>
> What do you mean by "quasi language independent" -- that it supports
> SmallScript and the "convential" AOS Smalltalk? Will it support python,
for
> example?

This 4th generation of the AOS Platform has been developed and tested for
dynamic (and dynamically typed) languages and is geared as an adaptive
virtual machine jitting model. Specific work has not been done, in this
generation, for implementing a particular statically typed (compiled)
language. The object model and internal architecture are designed with such
languages in mind. But, there are areas in the architecture that have not
been fleshed out and validated. So, it is really wrong to declare it as a
generic language independent UVM.

As to Python specifically, I want to stress that work is currently focused
on delivering the .NET, PPC, and x86 platform versions. The SmallScript
language layer and related general compiler frameworks are basically
completed and have been for some time.

The compiler architecture and SmallScript language design has, from its
inception, been geared for enabling hi-performance support of a variety of
Scripting languages. Out of the dirth of scripting languages available,
Python and PHP are at the top of our well-known candidate list. There are
parties who have either expressed an interest in or are working on languages
such as Scheme, JScript, and Basic.

Once the other pieces are in place, more attention will be focused on work
in Python and PHP. Reality dictates that direct compilation/execution
support for Java and C# are also worthy of serious consideration at some
stage.

As an aside, the execution performance numbers for SmallScript/Smalltalk are
directly indicative of the level of performance one could expect for Python
or PHP on the same platform.

>
> Steve (swart at bigserver dot com) -- .sig in progress
> http://www.visualknowledge.com

-- Dave S.


Andrea Ferro

unread,
Apr 26, 2001, 7:17:22 PM4/26/01
to
"David Simmons" <pul...@qks.com> wrote in message
news:unqF6.19479$Jh5.19...@news1.rdc1.sfba.home.com...
>
...

> Better still for our true testing purposes of raw numerics performance, what
> a hand coded assembly routine would do. I probably should hand code an
> assembly version since I'm really expert in that area and issues of
> pipelining -- I have often had to do this for small hot-spot areas where a
> C++ (or other static language) compiler just wasn't satisfactory.

There's not much data cache work involved here. It's most register stuff. And
code is so tiny that should go to cache at first pass.

I'm talking assembler/C/C++ here, not smalltalk, obviously.

You can trick around the triangle algorithm by changing it to (x*x+x)>>1 but
this is just a bit too much to ask from any optimizer (beside the problem of
overflow).

I've posted the VC7 generated assembly (removed all the SEGMENT, ASSUME and
other meta stuff) just a couple of minutes ago.

> > However note: Smalltalk always has all the code at hand.
>
> As you probably know, unlike C++ the Smalltalk compiler can't optimize
> (inline) messages away because it can't rely on method definitions being
> invariant. I.e., between the time a method is compiled and when it is
> invoked, the methods it references may be replaced with new versions. Thus,
> even if type inferencing could ascertain the correct binding information
> (which is possible in this example), it doesn't help.
>
> The only place where type information and bindings can be reliably and
> safely inlined, given a dynamic and adaptive versioning execution
> architecture, is in the JIT which has the knowledge and timing to know when
> an inlined method has become stale and regenerate (dynamically) the inline
> references.
>
> This kind of virtual machine execution architecture not only means that
> adaptive compilation leads to more version/change tolerant systems, but also
> means that, in the case where there are variants, the JIT can use
> heuristically acquired variant knowledge to (simplify and) optimize for
> actual use cases which a "pure" static compilation analysis could not.

That is exactly why I would expect smalltalk to be either slower than it is (if
it does things over again as it did in the 70s) or much faster. Someone was
surprised to see your SmallScript benchmarks. I was not. I know nothing of
SmallScript, but that it is being done right now. And that means that, having
the time and budget to do it at state of the art, it can actually do VERY FAST.

Pushing your reasoning to the extreme it could find out at run time that
triangle is invariant for invariant arguments and once it called it once it
could optimize the loop with a multiplication. However there's a balance to put
in the equation. That kind of heuristic would be itself expensive and not all
programs are just tight loops. This takes me to a curiosity of mines.

Fiew years ago I heard rumours of experiments to add some sort of type awareness
to Smalltalk. Now, making smalltalk statically typed is a nonsense. But
*allowing* type specification of parameters, return types and some other
semantic aids (like the concept of constness to indicate a method is not
supposed to modify the object) could maybe enable very optimized execution. What
is the *current* smalltalk community position on this sort of reasoning.

/DisclaimerOn
I do not want to start a flame on this. I'm not suggesting in any way that
Smalltalk should be typed. I'm just asking what reasoning is behind NOT even
allowing that sort of meta information. Smalltalk now has namespaces and parcels
and protocols and other usefull stuff that was no-no for Smaltalkers in the
past. An *optional* meta info that tells to the JIT and to the compiler that a
method has no side effects or that it returns an object guaranteed to be of a
given class should not actually change the language. Or does it?
/DisclaimerOff

> Global optimization in VC7 is one of the new features I had been waiting
> for -- I just hadn't tried to compile the AOS Platform VM with it because it
> is too bleeding edge for me rely on -- I've been bitten too many times that
> way -- particularly with VS releases. I use VS7 where required to work with
> .NET related IDE operations, C#, VB, and debugging.
>
> Note that just because it is in a different compilation unit, the compiler
> actually does have all the code in hand and my understanding is that it can
> also do some level of analysis on the binary-machine code within a library.
> I'm really surprised that "Microsoft's" C++ compiler was sophisticated
> enough at doing invariant analysis to the point of computing the entire
> result at compile time. I guess all the Microsoft dollars spent by their
> research group on advanced languages (including ML) has paid off and was
> incorporated -- very sweet -- I had not tested for this case.

It does it on triangle. Then it can do it on a loop that sums triangle results
(say 9000000 times). If you put the third loop on that ... somehow it doesnt. So
it is not perfect. No clue why. But still it's pretty good.

For example with this code (same if you put it in different files or all in
one):

int triangle( int x )
{
int result = 0;
for (int i = 1; i <= x; ++i)
result += i;
return result;
}

int loop()


{
int sum=0;
for (int i = 0; i != 9000000; ++i)
sum += triangle( 10 );

return sum;
}
int callLoop()
{
int tot = 0;
for ( int j=0; j!=10; ++j )
tot += (loop() / 1000000);
return tot;
}

the assembly generated is:

?triangle@@YIHH@Z PROC NEAR ; triangle, COMDAT
mov ecx, 1
xor eax, eax
cmp edx, ecx
jl SHORT $L274
npad 5
$L272:
add eax, ecx
inc ecx
cmp ecx, edx
jle SHORT $L272
$L274:
ret 0
?triangle@@YIHH@Z ENDP ; triangle

?loop@@YIHXZ PROC NEAR ; loop, COMDAT
mov eax, 495000000 ; 1d8119c0H
ret 0
?loop@@YIHXZ ENDP ; loop

?callLoop@@YIHXZ PROC NEAR ; callLoop, COMDAT
xor eax, eax
mov ecx, 10 ; 0000000aH
$L280:
add eax, 495 ; 000001efH
dec ecx
jne SHORT $L280
ret 0
?callLoop@@YIHXZ ENDP ; callLoop


Go figure why it did not precompute 4950 in callLoop!!


> I would add that I've actually seen VS6 do seemingly similarly impressive
> static analysis and reduction -- especially with inlining --including in
> early VS6 before SP2 releases being too agressive with register coloring and
> getting it wrong ;-). It begins to rival some of the better FORTRAN
> optimizers -- but there are much better hardcore C++ compilers and VS6. I
> don't know about VS7, although, given some of the Microsoft.NET platform
> numerics I can see why it might have been worth investing a lot in the
> static analysis :(.

hehe. Yes. VC6 had problems in coloring. And I guess VC7 is not perfect yet too.
But MS is really doing great stuff in this area. And I guess .NET virtual
environment is also not bad.

> A reasonable implementation of an adapative inlining JIT should have been
> able to analyze the entire Smalltalk code set into a single computed
> result -- and minimally should have been able to convert the 10 triangle
> invariant away by moving out of the loop. It is probably worth obtaining a
> copy of SELF and trying it -- or seeing how this performs in Java on a
> HotSpot VM.

hmmmm I'm still to keep up with Smalltalk "news". I'll take self some time in
the future. I told you, no matter how much I like this sort of languages I
couldn't yet "sell" their use here in Italy. But maybe that's because I'm doing
too much embedded stuff!

> In my tests I wrote the C++ code as a series of functions. I built this as a
> DLL and then invoked it directly from SmallScript.
>
> static int triangle(int nInnerSum);
> extern "C" DLLExport
> void TimeTriangle(int nLoops, int nInnerSumInterations);
>
> Where the central body of TimeTriangle was:
>
> {
> ...
> for(int i = 0; i != nLoops; ++i)
> sum += triangle(nInnerSumInterations);
> ...
> }
>
> I'm assuming that VS7 would move (hoist) the triangle() invocation outside
> the loop and substitute its computed value.

For some reason it is not. I maybe overlooking something: it's 1:15 am :-)

Ian Upright

unread,
Apr 26, 2001, 8:27:41 PM4/26/01
to
"Andrea Ferro" <And...@UrkaDVD.it> wrote:

>hmmmm I'm still to keep up with Smalltalk "news". I'll take self some time in
>the future. I told you, no matter how much I like this sort of languages I
>couldn't yet "sell" their use here in Italy. But maybe that's because I'm doing
>too much embedded stuff!

So are you implying that you likely couldn't sell the use of .NET either?

Ian

Andrew Hunt

unread,
Apr 26, 2001, 8:29:49 PM4/26/01
to
> Out of the dirth of scripting languages available,
> Python and PHP are at the top of our well-known candidate list. There are
> parties who have either expressed an interest in or are working on languages
> such as Scheme, JScript, and Basic.

Have you taken a look at Ruby?

It's remarkably clean, dynamic, fully OO, and open source. I find I can
wrote more code in Ruby faster, and with fewer errors, than any other
language I know (and I've tried quite a few).

For more info, try:

www.ruby-lang.org

and

www.rubycentral.com


Enjoy!

--
Andrew Hunt, The Pragmatic Programmers, LLC.
Innovative Object-Oriented Software Development
web: http://www.pragmaticprogrammer.com email: an...@pragmaticprogrammer.com
--
Books by Andrew Hunt and David Thomas:
"The Pragmatic Programmer" (Addison-Wesley 2000)
"Programming Ruby" (Addison-Wesley 2001)
--

David Simmons

unread,
Apr 27, 2001, 2:29:03 AM4/27/01
to
"Andrew Hunt" <an...@toolshed.com> wrote in message
news:slrn9ehfb...@workbench.toolshed.com...

> > Out of the dirth of scripting languages available,
> > Python and PHP are at the top of our well-known candidate list. There
are
> > parties who have either expressed an interest in or are working on
languages
> > such as Scheme, JScript, and Basic.
>
> Have you taken a look at Ruby?

Yes, I have indeed. I've known about Ruby and monitored it for a couple of
years now. I have the Ruby book and I've watched its attention rise and then
fall relatively quickly. Its newsgroup/discussion lists are pretty dardn
quiet and the website is not particularly active -- maybe I've just not been
monitoring the right areas?

>
> It's remarkably clean, dynamic, fully OO, and open source. I find I can
> wrote more code in Ruby faster, and with fewer errors, than any other
> language I know (and I've tried quite a few).

That's high praise indeed.

SmallScript is itself a complete and rich language, which I not so humbly
will suggest to you exceeds the facilities and ease of use of Ruby.

But truth to tell that is not the real issue in selecting the scripting
languages on the above list. The principal criteria are first and foremost
popularity (user-base and depth/breadth of the frameworks/codebase) and
second the clarity and capacity of the language. Perl would have been on the
list but, given a choice, it didn't meet my second criteria.

>
> For more info, try:
>
> www.ruby-lang.org
>
> and
>
> www.rubycentral.com
>
>
> Enjoy!

Cheers!

-- Dave S.

David Simmons

unread,
Apr 27, 2001, 2:48:35 AM4/27/01
to

"Andrea Ferro" <And...@UrkaDVD.it> wrote in message
news:9caaru$75k$1...@serv1.iunet.it...

> "David Simmons" <pul...@qks.com> wrote in message
> news:unqF6.19479$Jh5.19...@news1.rdc1.sfba.home.com...
> >
> ...
> > Better still for our true testing purposes of raw numerics performance,
what
> > a hand coded assembly routine would do. I probably should hand code an
> > assembly version since I'm really expert in that area and issues of
> > pipelining -- I have often had to do this for small hot-spot areas where
a
> > C++ (or other static language) compiler just wasn't satisfactory.
>
> There's not much data cache work involved here. It's most register stuff.
And
> code is so tiny that should go to cache at first pass.

My comment here had more to do with looking at pipelining (instruction
scheduling) issues and ensuring that we really tested similar numerics
rather than invariant optimizations. As you say, the instruction and data
caches are basically irrelevant to the c++/assy code.

The comments regarding the instruction and data caches were for the
10,000,000 case which generated LargeInteger values in Smalltalk and
therefore invoked many other parts of the execution engine (possibly
including one or more aspects of the automatic garbage collector
facilities).

...snip interesting stuff...

> Fiew years ago I heard rumours of experiments to add some sort of type
awareness
> to Smalltalk. Now, making smalltalk statically typed is a nonsense. But
> *allowing* type specification of parameters, return types and some other
> semantic aids (like the concept of constness to indicate a method is not
> supposed to modify the object) could maybe enable very optimized
execution. What
> is the *current* smalltalk community position on this sort of reasoning.

You're probably referring to StrongTalk? Or you may be referring to early
information regarding my work on SmallScript?

In any case, as I understand it, StrongTalk was not designed with the goals
you're describing.

SmallScript's intrinsic type system does enable those goals and can make
extensive use of optional type information. The type system is formalized
and integrated in with the language (including the mixin/MI interface
system). As a result the type system enables transparent FFI marshalling,
overloaded methods (multi-methods), etc.

> /DisclaimerOn
> I do not want to start a flame on this. I'm not suggesting in any way that
> Smalltalk should be typed. I'm just asking what reasoning is behind NOT
even
> allowing that sort of meta information. Smalltalk now has namespaces and
parcels
> and protocols and other usefull stuff that was no-no for Smaltalkers in
the
> past. An *optional* meta info that tells to the JIT and to the compiler
that a
> method has no side effects or that it returns an object guaranteed to be
of a
> given class should not actually change the language. Or does it?
> /DisclaimerOff

...snip more interesting comments...

> hmmmm I'm still to keep up with Smalltalk "news". I'll take self some time
in
> the future. I told you, no matter how much I like this sort of languages I
> couldn't yet "sell" their use here in Italy. But maybe that's because I'm
doing
> too much embedded stuff!

Actually, its interesting you should say that. A 4:1 performance ratio for a
worst case numerics scenario is not indicative of general performance. I
would suggest that general purpose code on that same architecture would
perform roughly equal to C++.

Certainly the object allocation and GC would exceed performance of
non-auto-(stack)-objects. The adaptive nature of the JIT enables optimizing
various constructs that a static compiler could not.

But most important of all is that an virtual machine opcode instruction set
is *much* more compact in memory than statically compiled code and therefore
it should be possible to support significantly more (easily upgradable)
functionality in the same memory footprint. A dynamic language architecture
allows restructuring of classes (objects) and their behavior on the fly
without ever quitting an application -- that and many other dynamic language
features are quite attractive for mobile computing, agent technology,
factory automation systems, and data collection and processing facilities.

...snip more interesting stuff...

Cheers,

-- Dave S.

David Simmons

unread,
Apr 27, 2001, 5:48:05 AM4/27/01
to
"David Simmons" <pul...@qks.com> wrote in message
news:Pk8G6.23922$Jh5.23...@news1.rdc1.sfba.home.com...

> "Andrew Hunt" <an...@toolshed.com> wrote in message
> news:slrn9ehfb...@workbench.toolshed.com...
> > > Out of the dirth of scripting languages available,
> > > Python and PHP are at the top of our well-known candidate list. There
> are
> > > parties who have either expressed an interest in or are working on
> languages
> > > such as Scheme, JScript, and Basic.
> >
> > Have you taken a look at Ruby?
>
> Yes, I have indeed. I've known about Ruby and monitored it for a couple of
> years now. I have the Ruby book and I've watched its attention rise and
then
> fall relatively quickly.

Updating my earlier post now that I've gone and re-examined their site,
events, and newsgroup.
---
Hmmm... Maybe it just has seasonal lulls.

There Tampa conference this fall will be an interesting indicator. I have
the distinct impression that a large if not dominant portion of the user
base is in Japan. I wonder why their conferenced wasn't held there?

> Its newsgroup/discussion lists are pretty dardn
> quiet and the website is not particularly active -- maybe I've just not
been
> monitoring the right areas?

I just went a renewed my link to its newsgroup and I see it has quite a lot
of activity in recent weeks. My news service is not archiving more than a
month or so on this group so I can't see further back.

I also notice a number of familiar folks posting in their group...

Andrew Hunt

unread,
Apr 27, 2001, 8:28:31 AM4/27/01
to
On Fri, 27 Apr 2001 09:48:05 GMT, David Simmons <pul...@qks.com> wrote:
> > >
> > > Have you taken a look at Ruby?
> >
> > Yes, I have indeed. I've known about Ruby and monitored it for a couple of
> > years now. I have the Ruby book and I've watched its attention rise and
> then
> > fall relatively quickly.
>
> Updating my earlier post now that I've gone and re-examined their site,
> events, and newsgroup.
> ---
> Hmmm... Maybe it just has seasonal lulls.

Everything does :-) The newsgroup is a bustling place, and the posting
volume has been monotonicly increasing pretty much since its inception.
Now, it is cross-fed from a mailing list, and there have been sporadic
outages and delivery problems, so perhaps you just happened to hit it
at a bad time.

> There Tampa conference this fall will be an interesting indicator. I have
> the distinct impression that a large if not dominant portion of the user
> base is in Japan. I wonder why their conferenced wasn't held there?

Because more and more folks in the US are becoming interested in Ruby
and starting to learn and use it. There was a large Ruby presence at
an open-source conference in Tokyo, BTW.

> I just went a renewed my link to its newsgroup and I see it has quite a lot
> of activity in recent weeks.

Since the beginning of the year, at least.

> I also notice a number of familiar folks posting in their group...

Many of the XP crowd have taken a liking to Ruby. I find it very useful
for "spiking" to understand a solution. It's very nearly friction-free
when it comes to refactoring.

> > > It's remarkably clean, dynamic, fully OO, and open source. I find I can
> > > wrote more code in Ruby faster, and with fewer errors, than any other
> > > language I know (and I've tried quite a few).
> >
> > That's high praise indeed.

That's the idea :-)

> > SmallScript is itself a complete and rich language, which I not so humbly
> > will suggest to you exceeds the facilities and ease of use of Ruby.

I've not seen SmallScript, but I will put it on my todo list. After all, I
am a pragmatic sort of person.

> > But truth to tell that is not the real issue in selecting the scripting
> > languages on the above list. The principal criteria are first and foremost
> > popularity (user-base and depth/breadth of the frameworks/codebase) and
> > second the clarity and capacity of the language. Perl would have been on
> the
> > list but, given a choice, it didn't meet my second criteria.

Ruby's popularity is growing internationally, slowly but steadily. Dave
and I wrote an article on Ruby for the January (25th anniversary issue)
of Dr. Dobb's Journal, we've just had a stellar review on slashdot.org,
the community is growing in size and capability on a daily basis.

It may not be here yet, but it's coming.

/\ndy

Courageous

unread,
Apr 27, 2001, 12:17:24 PM4/27/01
to

>Ruby's popularity is growing internationally, slowly but steadily. Dave
>and I wrote an article on Ruby for the January (25th anniversary issue)
>of Dr. Dobb's Journal, we've just had a stellar review on slashdot.org,
>the community is growing in size and capability on a daily basis.

You're posting to a _Python_ newsgroup. What's so special about
Ruby? I've been the website before, and haven't been particularly
impressed. The authors need to work on detailed documentation
pretty badly, it seems.

C//

Steve Holden

unread,
Apr 27, 2001, 12:33:05 PM4/27/01
to
"Courageous" <jkra...@san.rr.com> wrote in message
news:e77jetondditre9sp...@4ax.com...
He's actually also posting to the SmallTalk advocacy list and comp.object:
you're just *reading* it in c.l.py ... there's a difference.

Personally I found it quite interesting that SmallTalkers also see postings
advocating Ruby, and I know that some Pythonistas are quite interested in
it. Still seems a bit like someone sticking a microphone in your face on the
sidewalk and asking whether you'd liek to try a new brand of soap powder,
but hey, it's a free 'Net.

I looked at Ruby, briefly, and didn't really like the flavor as much as
Python. Unless I'm thinking of another language altogether the syntax is
warty, with a Perl-ish use of punctuation which might make programs shorter,
but doesn't help with comprehension.

Just my 2c.

regards
Steve

[note I apparently don't get access to com.lang.smalltalk.advocacy]


Andrew Hunt

unread,
Apr 27, 2001, 1:19:04 PM4/27/01
to
On Fri, 27 Apr 2001 16:17:24 GMT, Courageous <jkra...@san.rr.com> wrote:
>
> >Ruby's popularity is growing internationally, slowly but steadily. Dave
> >and I wrote an article on Ruby for the January (25th anniversary issue)
> >of Dr. Dobb's Journal, we've just had a stellar review on slashdot.org,
> >the community is growing in size and capability on a daily basis.
>
> You're posting to a _Python_ newsgroup.

Not on purpose. I'm replying to a posting on comp.object which
happens to be cross-posted to your Python group.

> What's so special about Ruby?

Well, since you asked:

It's fully OO, without excuses.
It has iterators.
It supports unlimited length integers that automatically promote as needed (as
in SmallTalk).
Whitespace in the input isn't significant :-)

There's more, but I won't waste your time if you aren't interested. We've
got a presentation or two on www.pragmaticprogrammer.com if you are
interested.

> The authors need to work on detailed documentation
> pretty badly, it seems.

Well, Dave and I wrote a 620 page book detailing the language
and the libraries. It's also available free in HTML or XML
form.

Does that count?

Andrew Hunt

unread,
Apr 27, 2001, 1:27:07 PM4/27/01
to
On Fri, 27 Apr 2001 16:33:05 GMT, Steve Holden <sho...@holdenweb.com> wrote:
>
> Personally I found it quite interesting that SmallTalkers also see postings
> advocating Ruby, and I know that some Pythonistas are quite interested in
> it.

Some Perl folk too. And that's as it should be; use the right tool for
the job regardless of dogma.

> I looked at Ruby, briefly, and didn't really like the flavor as much as
> Python. Unless I'm thinking of another language altogether the syntax is
> warty, with a Perl-ish use of punctuation which might make programs shorter,
> but doesn't help with comprehension.

Umm, that's not *quite* right. It does happen to have some Perl-like
shortcuts, but I view those as training wheels for folks coming to Ruby
from Perl.

I personally like the style and dynacism of Ruby. For instance, to declare
a class that inherits from another class you simply have:

class Foo < Bar
def myMethod
File.new ("test.dat", "w") { |f|
f.puts "Hello world!"
}
end
end

Here, class Foo inherits from class Bar. Except that class Bar is just an
expression that returns a Class object. In this case it's a constant, but
you could just as easily have:

class Foo < someMagicRoutine(someArgument, somethingElse)

File is a real object, we'll call open on it. The opened file object is
passed to the block as local variable f, where we can call puts (named as
in libc) to put a string to the file. At the conclusion of the block,
the file is closed automatically.

Doesn't look much like Perl to me. Oh, and that's just one way to
use files -- you don't have to use them in a block, but I find it
handy to make sure I've really closed a file :-)

Steven D. Majewski

unread,
Apr 27, 2001, 2:02:27 PM4/27/01
to

On Fri, 27 Apr 2001, Andrew Hunt wrote:

> I personally like the style and dynacism of Ruby. For instance, to declare
> a class that inherits from another class you simply have:
>
> class Foo < Bar
> def myMethod
> File.new ("test.dat", "w") { |f|
> f.puts "Hello world!"
> }
> end
> end

What do the vertical bars around the f ("|f|") above indicate ?

( Maybe it's those extra non alphanumeric operator looking chars
that make folks think of Perl -- even if they are used differently,
to someone that doesn't read Ruby, it looks like more "line noise".)

-- Steve Majewski


Johann Hibschman

unread,
Apr 27, 2001, 2:32:15 PM4/27/01
to
Steven D Majewski writes:

>> class Foo < Bar
>> def myMethod
>> File.new ("test.dat", "w") { |f|
>> f.puts "Hello world!"
>> }
>> end
>> end

> What do the vertical bars around the f ("|f|") above indicate ?

That indicates that the block takes one argument, which is named "f".

In Python, this would be:

def File_new (filename, func_to_call):
try:
file_obj = open (filename, 'w')
func_to_call (file_obj)
finally:
file_obj.close()

def block_function (f): # i.e. this is what that |f| means...
f.write ("Hello, world!\n")

File_new ("test.dat", block_function)


The real difference here is that the file object "f" is closed upon
exit from File_new, even if block_function stashed a reference to "f"
somewhere else. That's probably not that important; this is a case
where Python's reference-counting does the right thing, and where
garbage collection has a slightly harder time.


> ( Maybe it's those extra non alphanumeric operator looking chars
> that make folks think of Perl -- even if they are used differently,
> to someone that doesn't read Ruby, it looks like more "line noise".)

Parts of it are icky, but it's not as bad as it seems at first glance.
The '$' only appears on global variables, while '@' is a shortcut for
"self.", which I don't mind having. "sqrt(@b**2 - 4*@a*@c)" is a bit
more readable for me than "sqrt(self.b**2 - 4*self.a*self.c)".

Anyway, I like Ruby. I don't like it enough to recode all of my
existing python modules in Ruby, but I do like it enough to keep
playing with it.


--
Johann Hibschman joh...@physics.berkeley.edu

Andrea Ferro

unread,
Apr 27, 2001, 12:30:33 PM4/27/01
to
"Ian Upright" <ian-...@upright.net> wrote in message
news:vifheto0jmk2ermdg...@4ax.com...

For the embedded stuff surely not. For the platform in general I'm beginning to
talk to people of where MS is heading (actually presenting it not as a MS
imposition of sort but as MS way of attacking a more general direction of
evolution and talking of IBM research on WebServices and their acceptance of
SOAP and so on). The reaction is IMO fear-driven conservactionism.

They say it is useless. They say they already can have two programs talk with
sokets. They say all sort of things you can expect from somenone not seing the
picture. They do not perceive it as an anabling technology that could (if the
promises are met) make the Internet change from a network for umans to a network
for computers.

When Java came people was just beginning to understand HTML. Pages were static.
Java won it's place here for animations and special effects. There's almost no
"system with a web interface". They started doing that a couple of years ago
when some finantial services (Banks mostly) started enabling account balance
checking on the internet. Systems are mostly non internet enabled. There's
practically no case of two companies managing order-ship-account and stuff
electronically: everithing is on paper (that's a legal concern too).

It is my opinion that no SW shop will be able to "sell" .NET here. But MS will.
And we'll use .NET because it's there. VC7 is better than VC6. VB.NET and
ASP.NET are cool to play with. They'll use them for that reason, not for
technical resons.

Most companies are not internet. They have a Win95 machine with dialup everibody
uses to check e-mails. The web site is on a ISP machine and changes once in two
years. It's there because it must be, not because it gives a service. Large
companies do business on AS400. Those having NT do because they have a SW not
supported on Win98.

I even know of a SW shop doing C++ development with 20 developers working there
... and at an interview, when I asked what design methodology they used ... it
came out they do not even write /* */ comments in the sources "because that's
not needed". I almost falled out of the chair. Then of course they allocate 3-4
weeks to change the app so that configuration is stored on SQL DB instead of
.ini files.

That's the mainstream. Then, of course, there are the exceptions. Agusta does
elicopters (not only civil ones) and have state of the art SW labs. In ADA. And
many others too. There's some very good SW developed here too. Even commercial
or business. But the mainstream culture is pretty low. Many developers are good.
Many could be good in a good environment.

Smalltalk? .NET? Well, someone is using them or will. But most SW shops
management knows nothing of those and if the management does not know the
programmers should not use. Dilbert rules.

Piet van Oostrum

unread,
Apr 28, 2001, 1:34:54 PM4/28/01
to
>>>>> Johann Hibschman <joh...@physics.berkeley.edu> (JH) writes:

JH> Steven D Majewski writes:
>>> class Foo < Bar
>>> def myMethod
>>> File.new ("test.dat", "w") { |f|
>>> f.puts "Hello world!"
>>> }
>>> end
>>> end

>> What do the vertical bars around the f ("|f|") above indicate ?

JH> That indicates that the block takes one argument, which is named "f".

In other words, a lambda expression.

JH> In Python, this would be:

In Python you could then also use the lambda expression.
lambda f: f.puts("Hello World") or write rather than puts

JH> def File_new (filename, func_to_call):
JH> try:
JH> file_obj = open (filename, 'w')
JH> func_to_call (file_obj)
JH> finally:
JH> file_obj.close()

JH> def block_function (f): # i.e. this is what that |f| means...
JH> f.write ("Hello, world!\n")

JH> File_new ("test.dat", block_function)

What about open("test.dat", "w").write ("Hello world")?
--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://www.cs.uu.nl/~piet [PGP]
Private email: P.van....@hccnet.nl

David Simmons

unread,
Apr 28, 2001, 4:26:00 PM4/28/01
to
"Andrew Hunt" <an...@toolshed.com> wrote in message
news:slrn9ejav...@workbench.toolshed.com...

> On Fri, 27 Apr 2001 16:33:05 GMT, Steve Holden <sho...@holdenweb.com>
wrote:

Hi /\ndy,

About an hour or so after your last post to me, I realized you're one of the
two authors on the "Programming Ruby" book.

Which, of course, was the Ruby book I was telling you I had ;-).

...snip...


>
> I personally like the style and dynacism of Ruby. For instance, to
declare
> a class that inherits from another class you simply have:
>
> class Foo < Bar
> def myMethod
> File.new ("test.dat", "w") { |f|
> f.puts "Hello world!"
> }
> end
> end

A SmallScript version could be written as:
=========================================
class name=Foo extends=Bar {
method {
myMethod
File('test.dat','w') << 'Hello world!'.
}
}

<!-- Run it here -->
{Foo().myMethod}

======

--- OR as single line scripts with just:

{File('test.dat','w') << 'Hello world!'}

--- OR ---

{File('test.dat','w').write('Hello world!')}

--- OR ---

{File('test.dat','w').puts('Hello world!')}

=========================================

The above assumes you have a class <File> with a constructor that takes two
arguments (<aFilePath>,<aFilePermissions>) which returns instances that
implement the <IStream> interface. The "garbage collector and/or exit"
finalization will automatically close the <File> streams left open in the
above examples.

The same SmallScript compiler will also process this (XML form of Smalltalk)
identically:
=============================

<class name=Foo extends=Bar>
<?method class=Foo [ "<-- specifying class is unnecessary"
myMethod
(File open: 'test.dat' withPermissions: 'w')
nextPutAll: 'Hello world!'
]?>
</class>
[Foo new myMethod].

--- Which is Equivalent To ---
class name=Foo extends=Bar.
method class=Foo [
myMethod
(File open: 'test.dat' withPermissions: 'w')
nextPutAll: 'Hello world!'
].
[Foo new myMethod].

---
[(File open: 'test.dat' withPermissions: 'w') nextPutAll: 'Hello world!']

=============================


But perhaps more interesting is when we want to use module packaging,
namespace (scope) binding, and argument typing, as in the following script.

NOTE: Without all the numerous explanatory comments, the following code is
simple.
====================
module name=MyModule dll=Kernel32
{
<!--
Description: Within our module, override any <String> arg calls
to <File> #write(<>) or #puts(<>).

Note: The subsequent 'module=MyModule' attribute is redundant
because it is implied by nesting a method for an
external
class within our (deployment packaging) module.
-->
method class=File scope=MyModule module=MyModule
{ "" ^- Scope limits visibility of this method
::write(<>) "" <- declare an alternate name for this method
puts(<String> aString)
" ^- limits method binding to types of Strings"
/*
When we are invoked, log a message to stderr
and then invoke the general version.
*/

"Because we declared that our module act as a namespace for the
Kernel32.DLL, via dll=, we can call any of its entry points
without needing to declare them."

| fileName | := String(MAX_FILE_PATH).
fileName.size(GetModuleFileName(null,fileName,fileName.size)).

"" Log the message here
stderr << '`nWe just used a custom File::write(<>) version'.
' from module: ' << fileName.

"" Invoke the standard write routine here
return self::File.write(aString)
(*
We could have qualified the #write message via these
other forms:

self #File.write(...)
self #::File.write(...)
*)
}

<!-- Now execute custom version -->
{File('test.dat','w'.puts('Hello world!`n')}

<!-- Now execute standard version because of type discrimination -->
{File('test.dat','w'.puts(42)}
}

<!-- Now execute standard version because this eval/immediate method
is outside the module scope -->
{File('test.dat','w'.puts('`nHello world!')}

====================

I intentionally used a wide variety of the different comment styles allowed
(there are additional forms including Unicode variants). The comment forms
also enable an extensible form of JavaDoc.

Normally, I would adopt one comment style and use it consistently.

I should also point out that, in general, the SmallScript parse tree
facilities enable an IDE or similar tool to rewrite/transform/present source
code into either of the various SmallScript and Smalltalk like styles that
were shown in these examples.

-- Dave S.

Alex Martelli

unread,
Apr 29, 2001, 7:09:43 AM4/29/01
to
"David Simmons" <pul...@qks.com> wrote in message
news:sHFG6.29131$Jh5.25...@news1.rdc1.sfba.home.com...
[snip]

> > a class that inherits from another class you simply have:
> >
> > class Foo < Bar
> > def myMethod
> > File.new ("test.dat", "w") { |f|
> > f.puts "Hello world!"
> > }
> > end
> > end
>
> A SmallScript version could be written as:
> =========================================
> class name=Foo extends=Bar {
> method {
> myMethod
> File('test.dat','w') << 'Hello world!'.
> }
> }

And the Python equivalent would be:

class Foo(Bar):
def myMethod(self):
open('test.dat','w').write('Hello world!\n')

so there doesn't seem to be much of a difference in
capabilities at this level -- very different syntax sugar,
of course, but rather similar semantics.

> > Here, class Foo inherits from class Bar. Except that class Bar is just
an
> > expression that returns a Class object. In this case it's a constant,
but
> > you could just as easily have:
> >
> > class Foo < someMagicRoutine(someArgument, somethingElse)

Sure, same semantics in Python, of course.


Alex

Andrew Hunt

unread,
Apr 30, 2001, 10:38:10 AM4/30/01
to
On Fri, 27 Apr 2001 14:02:27 -0400,
Steven D. Majewski <sd...@Virginia.EDU> wrote:
>
>
> On Fri, 27 Apr 2001, Andrew Hunt wrote:
>
> > I personally like the style and dynacism of Ruby. For instance, to declare
> > a class that inherits from another class you simply have:
> >
> > class Foo < Bar
> > def myMethod
> > File.new ("test.dat", "w") { |f|
> > f.puts "Hello world!"
> > }
> > end
> > end
>
> What do the vertical bars around the f ("|f|") above indicate ?

A local variable to the block, used to pass the parameter from File.new.

> ( Maybe it's those extra non alphanumeric operator looking chars
> that make folks think of Perl -- even if they are used differently,
> to someone that doesn't read Ruby, it looks like more "line noise".)

Doesn't Smalltalk use vertical bars as well? I don't think that
qualifies as line noise. The @-prefix on instance variables might,
and I'll admit to not liking that very much when I first saw Ruby.
However, most Java or C++ programs I've seen tend to use *some* sort
of naming convention for instance variables, either myFoo or _Foo or
something like that. Given the choice between myFoo and @foo, I'll
take @foo.

/\ndy

Andrew Hunt

unread,
Apr 30, 2001, 10:46:17 AM4/30/01
to
On 27 Apr 2001 11:32:15 -0700, Johann Hibschman
<joh...@physics.berkeley.edu> wrote:

>
> The real difference here is that the file object "f" is closed upon
> exit from File_new, even if block_function stashed a reference to "f"
> somewhere else.

But only because the block-form of new is written to provide that as
a convenience. You can use the same sort of transactional control to
put up bust cursors, or for database transactions, or whatever. It's
not an intrinsic feature of files, just a handy thing.

> Parts of it are icky, but it's not as bad as it seems at first glance.
> The '$' only appears on global variables, while '@' is a shortcut for
> "self.", which I don't mind having. "sqrt(@b**2 - 4*@a*@c)" is a bit
> more readable for me than "sqrt(self.b**2 - 4*self.a*self.c)".
>
> Anyway, I like Ruby. I don't like it enough to recode all of my
> existing python modules in Ruby, but I do like it enough to keep
> playing with it.

I don't like *any* language enough to go back and rewrite stuff :-)

/\ndy

Andrew Hunt

unread,
Apr 30, 2001, 10:48:56 AM4/30/01
to
On 28 Apr 2001 19:34:54 +0200, Piet van Oostrum <pi...@cs.uu.nl> wrote:

> What about open("test.dat", "w").write ("Hello world")?

There are a bucket of shortcuts in Ruby that could do the
same as the code I posted, including the equivilant of the call above.
I wasn't trying to show the shortest way to write Hello World, but rather
give a taste of what the language "looks like".

/\ndy

phil hunt

unread,
Apr 30, 2001, 12:23:42 PM4/30/01
to
On Mon, 30 Apr 2001 14:38:10 -0000, Andrew Hunt <an...@toolshed.com> wrote:
>> > class Foo < Bar
>> > def myMethod
>> > File.new ("test.dat", "w") { |f|
>> > f.puts "Hello world!"
>> > }
>> > end
>> > end
>>
>> What do the vertical bars around the f ("|f|") above indicate ?
>
>A local variable to the block, used to pass the parameter from File.new.
>
>> ( Maybe it's those extra non alphanumeric operator looking chars
>> that make folks think of Perl -- even if they are used differently,
>> to someone that doesn't read Ruby, it looks like more "line noise".)
>
>Doesn't Smalltalk use vertical bars as well?

Yes.

> I don't think that
>qualifies as line noise.

I find them rather aesthetically pleasing.

> The @-prefix on instance variables might,

Yuk. It's $one $of $the $things $I $dislike $about $Perl.

And PHP, for that matter.

--
*****[ Phil Hunt ***** ph...@comuno.freeserve.co.uk ]*****
"Mommy, make the nasty penguin go away." -- Jim Allchin, MS head
of OS development, regarding open source software (paraphrased).

Darren New

unread,
Apr 30, 2001, 1:00:59 PM4/30/01
to
Andrew Hunt wrote:
> > What do the vertical bars around the f ("|f|") above indicate ?
> A local variable to the block, used to pass the parameter from File.new.

It's been too long since I used Smalltalk, but doesn't |f| inside a
smalltalk block declare a block-local temporary, rather than an argument? I
thought it was something like

[ f: g: |q r| code goes here ]
that says "f" and "g" are arguments, q and r are temps?

If I'm remembering right, I'd say it's a minor faux pas to use syntax from
Smalltalk and have it mean something subtly different.

--
Darren New / Senior MTS & Free Radical / Invisible Worlds Inc.
San Diego, CA, USA (PST). Cryptokeys on demand.
schedule.c:7: warning: assignment makes calendar_week
from programmer_week without a cast.

Dave Harris

unread,
Apr 30, 2001, 2:22:00 PM4/30/01
to
dn...@san.rr.com (Darren New) wrote (abridged):

> It's been too long since I used Smalltalk, but doesn't |f| inside a
> smalltalk block declare a block-local temporary, rather than an
> argument? I
> thought it was something like
>
> [ f: g: |q r| code goes here ]
> that says "f" and "g" are arguments, q and r are temps?

Close. There's an extra bar and the colons go the other side of the
variables.

[ : f : g | |q r| code goes here]

It as if there were an invisible message selector keywords before the
arguments. Compare with method definitions:

with: f and: g


|q r|
code goes here

the "with" and "and" are part of the method's name, so the block is like
an anonymous method.


> If I'm remembering right, I'd say it's a minor faux pas to use syntax
> from Smalltalk and have it mean something subtly different.

Well, it's not like this part of Smalltalk is ideal.

Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

Greg Ewing

unread,
May 1, 2001, 12:49:37 AM5/1/01
to
Andrew Hunt wrote:
>
> Here, class Foo inherits from class Bar. Except that class Bar is just an
> expression that returns a Class object. In this case it's a constant, but
> you could just as easily have:
>
> class Foo < someMagicRoutine(someArgument, somethingElse)

Just thought I'd check whether Python can do this
too, and it can:

Python 1.5.2 (#1, Nov 29 1999, 13:42:43) [GCC 2.8.1] on sunos5
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> class Bar:
... pass
...
>>> def f():
... return Bar
...
>>> class Foo(f()):
... pass
...
>>>

--
Greg Ewing, Computer Science Dept, University of Canterbury,
Christchurch, New Zealand
To get my email address, please visit my web page:
http://www.cosc.canterbury.ac.nz/~greg

Andrew Hunt

unread,
May 1, 2001, 7:11:54 AM5/1/01
to
On Tue, 01 May 2001 16:49:37 +1200, Greg Ewing <s...@my.signature> wrote:
> Andrew Hunt wrote:
> >
> > Here, class Foo inherits from class Bar. Except that class Bar is just an
> > expression that returns a Class object. In this case it's a constant, but
> > you could just as easily have:
> >
> > class Foo < someMagicRoutine(someArgument, somethingElse)
>
> Just thought I'd check whether Python can do this
> too, and it can:

Excellent. Glad to hear it. Can you continue to dynamically add methods
to classes at runtime? (I would guess yes, but thought I'd ask). Can
you be notified when this happens?

But really, folks, I don't want to get into a "my language can beat up
your language debate". Python is a fine and capable language. I
personally do not care for the whitespace thing, the use of magic
__method__ names, having to use the self. prefix for instance
variables, and (IIRC) parts of the object model. I like Ruby because
it follows the Principle of Least Surprise -- once you know the basic
philosophy and rules, there are few exceptions to remember. You can
guess at stuff you do not know and it works, first time. I've not had
that effect happen with any other language, including Python.

/\ndy

Frank Mitchell

unread,
May 1, 2001, 6:43:05 AM5/1/01
to
phil hunt wrote:
>
> On Mon, 30 Apr 2001 14:38:10 -0000, Andrew Hunt <an...@toolshed.com> wrote:
> > The @-prefix on instance variables [in Ruby] might,

>
> Yuk. It's $one $of $the $things $I $dislike $about $Perl.

The '@' and '$' prefixes indicate instance variables and global
variables, respectively. This differes from Perl in that:

1. The prefixes indicate scope, not type. (I still get weirded out that
in Perl it's %myhash but $myhash{key} ...)

2. The ugly line-noise aspect discourages you from using globals, and
from using raw instance variables instead of accessor methods. (In Ruby
you can define ivars and their accessors without using the @ at all.)
Globals are a big OO no-no, and generally you want only one routine
modifying an instance variable, and ideally only one routine accessing
it directly. So it all works out, kinda ...

--
Frank Mitchell (fra...@bayarea.net)

Darren New

unread,
May 1, 2001, 12:32:57 PM5/1/01
to
Dave Harris wrote:
> Close. There's an extra bar and the colons go the other side of the
> variables.
>
> [ : f : g | |q r| code goes here]
>
> It as if there were an invisible message selector keywords before the
> arguments.

That's why I didn't remember. I never clued in that's what the syntax was
supposed to represent. (One of the hazards of simple syntax, I guess.)

> Well, it's not like this part of Smalltalk is ideal.

True. But it *is* pretty minimal. :-)

--
Darren New / Senior MTS & Free Radical / Invisible Worlds Inc.
San Diego, CA, USA (PST). Cryptokeys on demand.

Invasion in chinese restaurant:
ALL YOUR RICE ARE BELONG TO US!

Martin von Loewis

unread,
May 1, 2001, 4:14:25 PM5/1/01
to
an...@toolshed.com (Andrew Hunt) writes:

> Excellent. Glad to hear it. Can you continue to dynamically add methods
> to classes at runtime? (I would guess yes, but thought I'd ask).

Yes, you can.

> Can you be notified when this happens?

No, you cannot (atleast not if you use the standard dictionary type).

Regards,
Martin

Greg Ewing

unread,
May 1, 2001, 11:28:37 PM5/1/01
to
Martin von Loewis wrote:

>
> an...@toolshed.com (Andrew Hunt) writes:
>
> > Can you continue to dynamically add methods to classes at runtime?
>
> Yes, you can.

You can also change the class of an object and rearrange
the inheritance hierarchy at runtime, just in case you
were wondering. And add or remove instance variables
dynamically, too (I don't think that one is so easy in
Smalltalk).

James A. Robertson

unread,
May 2, 2001, 12:10:45 AM5/2/01
to
Greg Ewing wrote:
>
> Martin von Loewis wrote:
> >
> > an...@toolshed.com (Andrew Hunt) writes:
> >
> > > Can you continue to dynamically add methods to classes at runtime?
> >
> > Yes, you can.
>
> You can also change the class of an object and rearrange
> the inheritance hierarchy at runtime, just in case you
> were wondering. And add or remove instance variables
> dynamically, too (I don't think that one is so easy in
> Smalltalk).

Sure it is.

MyClass addInstVarName: 'foo'

MyClass removeInstVarName: 'foo'

>
> --
> Greg Ewing, Computer Science Dept, University of Canterbury,
> Christchurch, New Zealand
> To get my email address, please visit my web page:
> http://www.cosc.canterbury.ac.nz/~greg

--
James A. Robertson
Product Manager (Smalltalk), Cincom
jar...@mail.com
<Talk Small and Carry a Big Class Library>

David Simmons

unread,
May 2, 2001, 2:34:33 AM5/2/01
to
"Greg Ewing" <s...@my.signature> wrote in message
news:3AEF7EE5...@my.signature...

> Martin von Loewis wrote:
> >
> > an...@toolshed.com (Andrew Hunt) writes:
> >
> > > Can you continue to dynamically add methods to classes at runtime?
> >
> > Yes, you can.
>
> You can also change the class of an object and rearrange
> the inheritance hierarchy at runtime, just in case you
> were wondering. And add or remove instance variables
> dynamically, too (I don't think that one is so easy in
> Smalltalk).

Sure you can; Smalltalk has been doing that kind of thing for decades.
Smalltalk is probably one of the premier languages for meta-object protocol
(schema) operations like your describing. It certainly helped to pioneer
this kind of technology along with Lisp.

In Smalltalk, there is just about nothing you can't dynamically restructure
in a running application. In many Smalltalk dialects that includes adding
arbitrary fields/variables and attributes to individual objects, changing a
class object into something else; or adding unique (instance specific)
behavior to individual objects.

-- Dave S.

Darren New

unread,
May 2, 2001, 12:16:06 PM5/2/01
to
James A. Robertson wrote:
> > were wondering. And add or remove instance variables
> > dynamically, too (I don't think that one is so easy in
> > Smalltalk).
>
> Sure it is.
> MyClass addInstVarName: 'foo'
> MyClass removeInstVarName: 'foo'

This is a little different from Python, tho.

In smalltalk, addInstVarName adds the instance variable to the *class* and
then updates all instances to now have that variable in them. (A relatively
high-overhead operation, yes.) IIRC, it might also have to recompile some or
all of the class code?

In Python, you add instance variables to individual instances. Not all
instances of the same class must have the same set of instance variables.
(In one sense, all instances of a class have the same instance variables,
but one of those instance variables is a dictionary mapping instance
variable names to values, and the syntax makes this mostly invisible.)

I think if you want to add an instance variable to all instances of a class,
you need to write a loop to iterate over all those instances. I'm not sure
whether you could find them.

phil hunt

unread,
May 2, 2001, 12:09:45 PM5/2/01
to
On Wed, 02 May 2001 04:10:45 GMT, James A. Robertson <jar...@mail.com> wrote:
>Greg Ewing wrote:
>>
>> Martin von Loewis wrote:
>> >
>> > an...@toolshed.com (Andrew Hunt) writes:
>> >
>> > > Can you continue to dynamically add methods to classes at runtime?
>> >
>> > Yes, you can.
>>
>> You can also change the class of an object and rearrange
>> the inheritance hierarchy at runtime, just in case you
>> were wondering. And add or remove instance variables
>> dynamically, too (I don't think that one is so easy in
>> Smalltalk).
>
>Sure it is.
>
>MyClass addInstVarName: 'foo'
>
>MyClass removeInstVarName: 'foo'

In Python you can an instance variale to *just one* instance of a
class with all the other instances remaining unchanged.

--
*****[ Phil Hunt ***** ph...@comuno.freeserve.co.uk ]*****

Pstream class library for C++: a Parsing Stream library that
facilitates writing lexical analysers and other programs
that parse data files. Available on an open source license from
<http://www.vision25.demon.co.uk/oss/phlib/intro.html>

James A. Robertson

unread,
May 2, 2001, 1:12:29 PM5/2/01
to
Darren New wrote:
>
> James A. Robertson wrote:
> > > were wondering. And add or remove instance variables
> > > dynamically, too (I don't think that one is so easy in
> > > Smalltalk).
> >
> > Sure it is.
> > MyClass addInstVarName: 'foo'
> > MyClass removeInstVarName: 'foo'
>
> This is a little different from Python, tho.
>
> In smalltalk, addInstVarName adds the instance variable to the *class* and
> then updates all instances to now have that variable in them. (A relatively
> high-overhead operation, yes.) IIRC, it might also have to recompile some or
> all of the class code?

You recompile the subclasses (not their methods) if there are any

>
> In Python, you add instance variables to individual instances. Not all
> instances of the same class must have the same set of instance variables.
> (In one sense, all instances of a class have the same instance variables,
> but one of those instance variables is a dictionary mapping instance
> variable names to values, and the syntax makes this mostly invisible.)
>
> I think if you want to add an instance variable to all instances of a class,
> you need to write a loop to iterate over all those instances. I'm not sure
> whether you could find them.
>
> --
> Darren New / Senior MTS & Free Radical / Invisible Worlds Inc.
> San Diego, CA, USA (PST). Cryptokeys on demand.
> Invasion in chinese restaurant:
> ALL YOUR RICE ARE BELONG TO US!

--

Ben Wolfson

unread,
May 2, 2001, 2:21:19 PM5/2/01
to
In article <3AF032C6...@san.rr.com>, "Darren New" <dn...@san.rr.com>
wrote:

[in Python, ]


> instances of the same class must have the same set of instance
> variables. (In one sense, all instances of a class have the same
> instance variables, but one of those instance variables is a dictionary
> mapping instance variable names to values, and the syntax makes this
> mostly invisible.)
>
> I think if you want to add an instance variable to all instances of a
> class, you need to write a loop to iterate over all those instances. I'm
> not sure whether you could find them.

You can add attributes to either classes or instances in Python.

Python 2.1 (#1, Apr 21 2001, 18:56:55)
[GCC 2.96 20000731 (Red Hat Linux 7.0)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> class C:
def __init__(self):
self.someval = 5

>>> c = C()
>>> C.someotherval = 'no'
>>> c.someval
5
>>> c.someotherval
'no'
>>> c.yetanotherval = (1,5)
>>> c.yetanotherval
(1, 5)
>>>

--
Barnabas T. Rumjuggler
"Et tu, Brute?" sedulous.
-- barry in indy, in apihna

Andrew Hunt

unread,
May 2, 2001, 4:15:47 PM5/2/01
to
On Wed, 2 May 2001 17:09:45 +0100, phil hunt
<ph...@comuno.freeserve.co.uk> wrote:

> On Wed, 02 May 2001 04:10:45 GMT, James A. Robertson <jar...@mail.com> wrote:
> >Greg Ewing wrote:
> >>
> >> Martin von Loewis wrote:
> >> >
> >> > an...@toolshed.com (Andrew Hunt) writes:
> >> >
> >> > > Can you continue to dynamically add methods to classes at runtime?
> >> >
> >> > Yes, you can.
> >>
> >> You can also change the class of an object and rearrange
> >> the inheritance hierarchy at runtime, just in case you
> >> were wondering. And add or remove instance variables
> >> dynamically, too (I don't think that one is so easy in
> >> Smalltalk).
> >
> >Sure it is.
> >
> >MyClass addInstVarName: 'foo'
> >
> >MyClass removeInstVarName: 'foo'
>
> In Python you can an instance variale to *just one* instance of a
> class with all the other instances remaining unchanged.

You can do the same in Ruby; both instance variables and methods
can be added to an individual instance as well as a class. You can
also traverse all the living objects in the system for various nefarious
purposes, if you're so inclined.

/\ndy

Alex Martelli

unread,
May 2, 2001, 3:25:42 PM5/2/01
to
"Darren New" <dn...@san.rr.com> wrote in message
news:3AF032C6...@san.rr.com...

> James A. Robertson wrote:
> > > were wondering. And add or remove instance variables
> > > dynamically, too (I don't think that one is so easy in
> > > Smalltalk).
> >
> > Sure it is.
> > MyClass addInstVarName: 'foo'
> > MyClass removeInstVarName: 'foo'
>
> This is a little different from Python, tho.
...

> In Python, you add instance variables to individual instances. Not all
> instances of the same class must have the same set of instance variables.
> (In one sense, all instances of a class have the same instance variables,
> but one of those instance variables is a dictionary mapping instance
> variable names to values, and the syntax makes this mostly invisible.)

OK, you can frame it this way...

> I think if you want to add an instance variable to all instances of a
class,
> you need to write a loop to iterate over all those instances. I'm not sure
> whether you could find them.

...however, when looking for any attribute (no syntax distinction
between 'variable' or 'method') over an instance object, if not
found in the __dict__ of the *instance*, it's next looked up in that
of the __class__ (and then up the __bases__ DAG thereof).

Thus, if somewhere you do
foo.__class__.newname = 23
now foo.newname, AND bar.newname for any instance bar sharing
as its class (or among its bases, if not otherwise shadowed by
inheritance) will also be 23. Specific instances may override that --
bar.newname = 45 now sets only the 'newname' attribute in the
dictionary of instance bar, without modifying that in other instances
such as foo -- but until and unless .newname is bound to something
specific for a given instance, it will delegate to the class and up the
inheritance DAG.

Not a very common object model, yep, but I find it very useful in
many practical cases.


Alex

Greg Ewing

unread,
May 4, 2001, 1:38:00 AM5/4/01
to
"James A. Robertson" wrote:
>
> MyClass addInstVarName: 'foo'
>
> MyClass removeInstVarName: 'foo'

Presumably that implies recompiling all of MyClass's
methods, and searching out and updating all of it's
instances -- a much more heavyweight operation than
the Python equivalent.

It's not exactly the same thing, either -- Python
instance variables are added on a per-instance basis,
whereas that is adding one to all instances.

That's not to say the Python way is necessarily
better, just different.

Eliot Miranda

unread,
May 9, 2001, 5:35:27 PM5/9/01
to

Greg Ewing wrote:
>
> "James A. Robertson" wrote:
> >
> > MyClass addInstVarName: 'foo'
> >
> > MyClass removeInstVarName: 'foo'
>
> Presumably that implies recompiling all of MyClass's
> methods, and searching out and updating all of it's
> instances -- a much more heavyweight operation than
> the Python equivalent.

Yes, ish. One doesn't actually need to recompile. Instead one can
update the bytecoded methods. VisualWorks does this, and is much faster
than compilation. The updating of instances can be done lazily [What's
the word for reducing an overhead by spreading it around? I'm thinking
of a word similar to "mitigated", but nothing comes to mind now...] by
mutating the class into a null wrapper who's doesNotUnderstand: method
updates the instance and sets its class to the new one before forwarding
the message. I believe this is done in CLOS, and it may be done in some
dialects of Smalltalk; I only know that VisualWorks doesn't do this.

But the advantage is that instance variable access is quick, because its
an indexing operation, not a key lookup. Further, enumerating all
instances is very quick in typical development contexts. On my 400MHz
Pentium II allInstances in an 8 meg heap with 165k objects takes 20
milliseconds. Most times one modifies a class there are relatively few
subclasses affected so the instance update time is unlikely to take more
than a second.

How does Python avoid the overhead? Does it instead make inst var
access slower? If so, IMO it is making the wrong trade-off; instance
variables are accessed much, much more frequently than classes are
changed.


> It's not exactly the same thing, either -- Python
> instance variables are added on a per-instance basis,
> whereas that is adding one to all instances.

Right. But there are ways of doing this on a per-object basis or
per-class basis in Smalltalk. In fact the classic example comes from
the CLOS MOP. It allows one to specify if instance variables are
implemented by indexing a la Smalltalk or via hash-lookup. So if one
has a class with lots of inst vars, most of which are never accessed
during normal usage the hash-table approach is a win, but in other
contexts it would be a loose. While this is possible in Smalltalk
there's no formalized API. This is the kind of thing that needs to be
facilitated in a proper Smalltalk MOP.


> That's not to say the Python way is necessarily
> better, just different.

Right. Just as long as they know what the costs are :)


--
_______________,,,^..^,,,____________________________
Eliot Miranda Smalltalk - Scene not herd

Dave Harris

unread,
May 10, 2001, 1:29:00 AM5/10/01
to
eli...@pacbell.net (Eliot Miranda) wrote (abridged):

> [What's the word for reducing an overhead by spreading it around?
> I'm thinking of a word similar to "mitigated", but nothing comes
> to mind now...]

Amortised.

0 new messages