Avi Bryant: Ruby IS-A Smalltalk

A short audio presentation (Avi speaks for less than ten minutes, I guess), about the lessons the Ruby community should learn from Smalltalk. It's mainly about turtles-all-the-way-down, but Self (fast VMs), GemStone (transactional distributed persistence), Seaside (web frameworks) are also mentioned briefly.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

What didn't work?

It would have been nice to hear not only about all the things Smalltalk got right, but what they didn't get right, too. Some guesses:

People seem to prefer files to images, as one of the last questions points out.

"Turtles all the way down" can be good, as he says, but it can also be counterproductive when you're reinventing the wheel, like having to write your own version control system that is unfamiliar to new users of the language.

strengths and weaknesses

To analyze mixes of pros and cons, it's useful to start with an idea that strengths are often their own weaknesses, and vice versa. (I dunno how familiar others find this, but I think it's obligatory to see both positive and negative consequences of choices. Sometimes weakness in a choice is only that you exhausted a choice, then have fewer choices.) Anyway, this vein of thinking churns many ideas when you need them.

Any positive attribute of a system is a problem — perhaps only a mild one — when looked at differently. (Sometimes negative attributes have good sides too, but this isn't as common as the reverse, because there's some kind of preservation of trouble principle involved, maybe related to entropy.)

I'm a Smalltalk fan, and I plan to do another, but I don't like everything associated with it like images. One cool attribute of traditional Smalltalk systems is "integrated" effects (eg IDEs), but integration has the effect of tying things together, which means you gather dependencies and have to answer to anything connected to the integrated environment. So integration decreases independence.

If you could choose whether or not you got integration effects, independent of language choice, this would make tech choices more a la carte (which is good). Choosing a language syntax should not require you buy everything someone once associated with it. But languages tend to get their reputations blurred with the "operating system" of its execution environment. Smalltalk the language is conflated with Smalltalk the operating system (eg images and other runtime effects). Similarly, Java in J2EE has the Java language blurred with standard libraries.

I've more comments, but I need to go.

the past is a foreign country

Without watching and listening, I'd note

  • that was back when object orientation was a new idea
  • people seem to prefer what they already know

Hard to say

-It could be a timing issue: at the time Smalltalk started, CPU usage was very important and memory was tight so this gave Smalltalk a big disadvantage, by the time CPUs improved enough that this didn't matter anymore C/C++ had became mainstream and Smalltalk has lost its novelty: the programming industry is very much a fashion industry..

-It could be a community issue: apparently (from the speech) commercials implementation of Smalltalk are much better currently than open source's ones, this may inder the building of a Smalltalk community.

-It could be a syntax issue: Smalltalk syntax is quite hard to learn when you're used to other languages and as Smalltalk is seldom used as a first language (yes, I know about OLPC), this is an issue..
I never understood why Smalltalkers didn't workaround this issue by changing the Smalltalk syntax to make it a bit more Cish: in practice that's what Ruby did and currently Ruby is a success whereas Smalltalk isn't.

a bit more Cish

I never understood why Smalltalkers didn't ...

They didn't want to have a Cish syntax :-)

And isn't that what Objective-C was about?

Of course, Objective C left out...

...Smalltalk's most interesting feature.

Not the pseudo-English "put: theSquarePeg in: theRoundHole" syntax. :)

Not dynamic dispatch, which is easy to greenspun up in C.

But blocks (which are dang near *impossible* to emulate in C). (Of course, many C programmers of the time regarded lexical scoping as a bit of Pascal nastiness that C was better off without...)

Not to mention safety.

Not to mention safety.

Add something to C...

...and you'll still have the unsafe properties of C. Unless you take something away; which neither C++ nor Objective-C have done.

I must confess

I must confess that I never really understood the point of Objective-C, because it seems to give you the worst of both worlds.

Another case where the libraries and tools sell the language

The basic point of Objective-C was to support the NeXTStep UI libraries and associated tools, which for the time ('91, IIRC) were very high quality and had a lovely programming model. A lot of the language design decisions behind Objective-C were taken to optimize the programming model for that particular niche. The results were extremely enjoyable to work in, although since Apple has taken over the lack of progress has begun to take it's toll.

To that extent, the designers of Objective-C learned the lessons of Smalltalk very well.

duck typing

Andreas Rossberg: I must confess that I never really understood the point of Objective-C...

The technical advantage with respect to C++ was duck typing: Objective-C was able to do very fluid implementations of generics based on object protocol interfaces without static typing. So you could have the speed of C++ with the wild west freedom of Python.

It was a viable compromise niche between C and Smalltalk. Where I worked in the early 90's, folks expert in C++ laughed at Bud Tribble and Objective-C, which led me to believe my project was doomed since this attitude toward Objective-C was far too narrow. The C++ folks believed you could type everything the one true correct way without painting yourself into a corner. (I bailed on them before they became irrelevant.)

I disagree

I know it is like cursing in church here but I can come up with a resonable argument against blocks in a object orientated language. I think this argument originates from Bertrand Meyer of eiffel.
In short when you compare an object and a block as a module of code you see that the object has good boundaries but a block get everything thrown in from the scopes above and that makes the object the better module.
Also there are some other interesting properties of objective-c you seem to miss.
Objective-c like Smalltalk sends messages and that makes a difference with other object orientated languages. And when you look for example at the squeak morphic interface you see some use of this for example
on: #mouseEnter send: #aMouseEnter: to: self
they are not using blocks here altho they are available in squeak.
Like squeak and for example pypy the objective-c runtime (and the compiler) is written in a subset of the language it self that is also pretty cool and you can manipulate that runtime at runtime.

edit:
found a paper that explains it better than I can see chapter 6 of
http://www.metaobject.com/papers/Higher_Order_Messaging_OOPSLA_2005.pdf

I says it's a graphics issue

For much of the 80s, prior to the emergence of Java on the scene (and when ST's competition was things like C, very early and immature C++, Pascal, and gobs of COBOL)... the prevalent computer system in the business world consisted of eithar

a) mainframes and/or minicomputers, tied to dumb (text-only) green-screen terminals

b) Very early IBM PCs and compatibles, with 640k ram (enough for anybody!) or less; generally with monochrome displays with 640-480 resolution

c) The occasional Mac. Even less common, one of the Mac's 68-k based competitors (an Atari ST or an Amiga).

d) Older CP/M hardware

e) 8-bit "home computers" from the likes of Apple/Atari/Commodore/TI (generally consider inappropriate for the office, but found there nonetheless).

The only one of these conducive at all to a Smalltalk environment is probably c), and even then, barely. The sort of workstations that could do a good job hosting Smalltalk back then were *expensive*--and generally only deployed to technical professionals doing CAD and other design activities. Certainly not to secretaries, managers, accountants, and other users of stovepipe software.

The relative lack of success

The relative lack of success of ST was discussed extensively in many place (including here), which is why I guess Avi didn't concentrate on it. The suggestions for the future of Ruby seem to me to be more interesting (and, of course, controversial).

You can't have one without the other

He's talking about how great Smalltalk is, but you can't just say "copy us" without an honest appraisal of what they did wrong, as well.

Rhetorical device?

without an honest appraisal of what they did wrong, as well.

I suspect that Avi's goal was to spur the Ruby community to think about what comes after Rails. Suggesting that Ruby should actually be Smalltalk with a different syntax was likely just his way of being deliberately provocative. Somebody of his caliber would likely recognize that there's little gain in literally reinventing Smalltalk with a different syntax.

It would be nice if the Ruby community could evaluate Smalltalk and then articulate how it wants to be different and why. At the same time, Avi's point is well taken that whatever differences Ruby wants to have, Smalltalk is still a rich wellspring to learn from.

late '80s mid '90s

Without wishing to go over old ground, you seem to have missed-out the period from the late '80s through the mid '90s (when Java emerged) - the period I was paid to write Smalltalk :-)

True.

By then, machines capable of running Smalltalk were starting to appear for reasonable prices. Around that time is when the PC started to assert itself as the dominant type of office "terminal"; when reasonable-cost networking started to appear; when the first processor in the x86 line (the 386) to have a decent memory model showed up, when the first PC display technology (VGA) that was any good appeared.

What happened?

A few guesses:

* Prior to 1995, when Windows 95 appeared, the existing OS's for the PC still had the 640k barrier to deal with, and/or numerous kludges around it. The exception was, of course, OS/2--which was incompetently marketed by IBM, who at that time was still regarded as the Evil Greedy Monopoly of the day (MS had not yet displaced them for this title). Linux and other PC Unices were all toys.
* C/C++ became further entrenched--displacing Pascal on low-end machines--as MS based the Windows API on C++ (and wrote the thing largely in C/C++--MS-DOS was written in assembly language). C was already established as the systems language for Unix.
* The RDBMS became more and more an established part of the enterprise architecture. Larry Ellison became filthy rich.
* The Internet went from academic research network to what it is today with the introduction of the web browser. Also, MS started acting more and more like Evil Greedy Monopolists, prompting a certain Unix systems vendor to promote its new language as a cross-platform language for enterprise apps. I'm speaking of course, of Java.
* As Java was a) free as in beer, b) marketed to death, and c) ubiquitously deployed despite MS's attempts to squash it--Smalltalk, already a minor player in the business apps market--was toast.

Of course, ST is now getting its revenge in the form of its children, such as Ruby. OTOH, it can be argued that Java is a son of Smalltalk as well--it's more similar to ST than C++ was. But a statically typed version of Smalltalk needs to have a type system more powerful that what Java 1.0 had. (Even nowadays, Java's type system is barely adequate...)

But a statically typed

But a statically typed version of Smalltalk needs to have a type system more powerful that what Java 1.0 had.

Java's and C#'s type systems are nowhere close to good enough, as they are nominally typed; if they were structural, then I'd agree with you. Java/C# are in the Simula object tradition, not the Smalltalk tradition.

Actually, it sounds like we DO agree...

A statically-typed language which seeks to emulate Smalltalk needs to in particular emulate duck typing, which means structural (sub)typing. No need to write a bunch of interfaces everywhere.

One of the key mistakes that many Simula-inspired languages have made IMHO, is the simultaneous use of inheritance for both code reuse, and subtyping. Smalltalk uses inheritance for code reuse, but it isn't necessary for subtyping in Smalltalk. Inheritance *is* necessary for subtyping in C++, Java, and (last I checked) C#. Not to mention Eiffel and a few others.

Occasionally it is useful to have closed abstractions--functions which accept only objects according-to-Hoyle ducks, rather than any datatype which happens to have a "quack()" method. But more often than not, what you really want is functions whose domain is anything capable of quacking and flying.

When inheritance is decoupled from subtyping, restrictions on multiple inheritance become No Big Deal. When you have to inherit to subtype, single-inheritance is a problem.

I think I quoted the wrong

I think I quoted the wrong snippet; I was objecting to "OTOH, it can be argued that Java is a son of Smalltalk as well". ;-)

But yes, I agree with your follow-up here.

What happened?

Sorry I'm missing the point of these guesses, and Ehud's probably correct in thinking that this has been discussed to death previously on LtU.

The Vendors...

I really blame the vendors for Smalltalk's lack of success. Their licensing schemes were out of reach for most (runtime royalties are not a good thing). It should be remembered that the Turbo line from Borland was less than $100.

I never understood why

I never understood why Smalltalkers didn't workaround this issue by changing the Smalltalk syntax to make it a bit more Cish: in practice that's what Ruby did and currently Ruby is a success whereas Smalltalk isn't.

All that Ruby did to make a more C-like Smalltalk was use the receiver-dot-method calling convention. Is "foo.bar()" really any easier to understand than "foo bar" after all? I find Smalltalk's syntax to be one of the easiest to explain to people.

Only to beginners

[[I find Smalltalk's syntax to be one of the easiest to explain to people.]]

Only to beginners, when I was taught Smalltalk as I already knew BASIC, Pascal, C, I didn't like at all Smalltalk's syntax.

You shouldn't dimiss so easily this issue, perhaps it's only a fad, but currently Ruby is fashionable, while Smalltalk isn't..
Which is weird as Ruby is Smalltalk, I agree with Avy here.

My view is: Ruby has a better syntax: better for programmers already knowing C, shell, Perl..

How do you explain this?

Ambiguity?

My only problem with smalltalk's syntax is apparent ambiguity. I could never find an answer to this from a compiler writers standpoint. Say you have a block [ a b c | a this: b that: c ]. How do you tell if the message involved translates as (a this:that:(b,c)) or ((a this:(b))that:(c)). This seems strange as it comes up in some examples I've seen such as [ a b | a + b ] value: obj1 value: obj2.

Smalltalk is very unambiguous

Gavin Harrison: My only problem with smalltalk's syntax is apparent ambiguity. I could never find an answer to this from a compiler writers standpoint.

I know the answer to that one. :-) I've written two (toy) Smalltalk compilers, so I know a compiler writer viewpoint. The syntax is not ambiguous because of the following message precedence rules:

  • unary is highest
  • binary is higher than keyword
  • keyword is lowest

Smalltalk's grammar is traditionally shown as bubble diagrams, so a verbal description of this precedence might appear less often. The grammar is actually very unambiguous, once you know the rules. (A parser only needs one token lookahead. In fact, if I remember correctly that numbers have unambiguous lexical grammar, Smalltalk only needs one character lookahead; I'm not entirely certain here though.)

So in your example, in the absence of parens to change precedence, the keyword message has lowest precedence. If you string together a long set of keywords and other expressions without parens, and without periods and semicolons, then all the keywords join together as part of one long message selector.

then there's the Self language...

which has the rule that the first selector fragment of a keyword message starts with a lowercase, subsequent ones start with an uppercase.

Like this:

a do: this AndDo: that

Which permits one to chain messages together (invoking subsequent messages on the result of the prior invokation) unambiguously without parens:

a do: this AndDo: that AndThenDo: theOther is the same as

a.do:AndDo:AndThenDo (this, that, theOther);

(in a Java-ish pseudosytnax where colons are valid lexemes within identifiers), whereas

a do: this AndDo: that andThenDo: theOther

is the same as

a.do:AndDo (this,that).andThenDo(theOther);

Whether this feature is desirable or not, is left as an exercise for the reader. I think it's kinda cute... on the other hand, given the nastiness involved in casefolding in certain non-European languages (not to mention those lacking case at all), making case syntactically significant strikes me as unwise these days. (This isn't an argument against case sensitivity; just an argument about have the grammar treating tokens differently based on case, other than the identification of keywords).

Yes..

I knew the precedence rules, and I thought of both of these solutions (camel:Cased: messages and "all keywords on a line are one message". Though, in some examples of smalltalk code, I've seen a 2 arg block receiving two value: messages. I wasn't aware that smalltalk's blocks had both "value:" and "value:value:" messages defined for blocks. However, this could be an incorrect example or understanding of it. Either way, thank you for the response :)

block arity

You're welcome — sorry if I presumed you didn't know the precedence. The arity of a block is the number of parameters declared inside the block before the "|", and the arity must match the number of value: keywords in the message to the block.

(In comparison to C: when you call a function of three args, parameters are separated by commas in C, and preceded by value: in Smalltalk when passed to a block. So block parameters are externally somewhat anonymous in that only order matters. The Smalltalk designers could have chosen to make a block take a keyword message of parts composed of the names of parameters used inside. But that would have had the effect of making blocks less duck-typed, in that blocks of the same arity would no longer be interchangeable at call sites.)

Smalltalk never uses parentheses to pass arguments as a tuple, so method args and block args are always introduced by some symbol: either a binary selector or a keyword.

Here's one more way to visually parse Smalltalk syntax: binary operators terminate unary expressions, and keywords terminate both unary and binary expressions. (And periods, semicolons, and close-parens terminate all message types.)

Smalltalk Syntax is EASY

Compared to other languages, there's very little of it. You will have to work past your prejudices if you're used to something else. Anyhow, Smalltalk syntax is superior to C-ish syntaxes as all arguments are named in keyword sending. Which is clearer:

object.put(a,b);
object at: a put: b.

In the former, you have no clue which value is the key.

Anyhow, claiming Ruby's syntax (which I find irritatingly complicated) vs Smalltalks has nothing to do with Smalltalk's lack of adoption and probably precious little with Ruby's succeess.

It was all about price of adoption vs perceived benefit.

No: easy only for beginners

[[Compared to other languages, there's very little of it.]]

So what? Lisp or Forth syntax are even simpler, but this doesn't make them easier to read or write!

[[You will have to work past your prejudices]]
*will*? No I have no such obligation, that's the point.
Let me tell you: in school, I learned Smalltalk but as I didn't like its syntax, so as soon as the lesson ended I forgot Smalltalk, much later when I saw Ruby I was hooked by its syntax, so I learned it.

As for your example, there is a middle ground:
object.put(target: b, source: a)
which I find better than "object at: a put: b."

[[It was all about price of adoption vs perceived benefit.]]
Sure, but learning the syntax is part of the 'price of adoption' it was too high for me for Smalltalk, but not for Ruby.

Given the lack of adoption of Smalltalk, I wasn't the only one thinking this..

knowing

"Given the lack of adoption of Smalltalk, I wasn't the only one thinking this."

Is it that you know there was lack of adoption of Smalltalk, or is it that you don't know there was adoption of Smalltalk?

oatmeal and fingernails

Compared to other languages, there's very little of it.

IMHO one thing that people miss in this debate is that simple syntax doesn't necessarily make for readable code, because code-reading is often a top-down process. One thing I find hard about Lisp is that, because there is so little syntax, it's sometimes difficult to see the code's overall structure. In a language with more keywords and block structure, I can tell how deep the current line is by looking at whitespace, and simply glance up to find the kind of block it's in. In Lisp, I'm forced to use my editor's paren-navigation functions to find an expression's extent, because it may not be visually apparent.

Smalltalk has all of Lisp's simplicity, but without the parens to let me do this. The solution seems to be to only write really small functions, but that's unsatisfying...

PS -- Lest the flames get too hot, let me just say that I'm only talking about human readability here, which is just one factor in choosing a syntax.

Human readability ?

For Lisp you might have a point (in fact in my opinion, you have a point... but that's not the subject here), but for Smalltalk I fail to see how you can claim it lacks structure ??

It seems to me that it is rather more structured than C syntax, I never had any difficulty reading the structure for Smalltalk code (contrary to Lisp).

--
Jedaï

Syntax blocked me.

Anyhow, claiming Ruby's syntax (which I find irritatingly complicated)
> vs Smalltalks has nothing to do with Smalltalk's lack of adoption and
> probably precious little with Ruby's succeess.

Well, it's the major thing that has made Smalltalk too hairy for me to read easily, and as a such kept me from starting to play with the language.

As a such, it necessarily has something to do with adoption - it has made sure I haven't adopt Smalltalk. Maybe I wouldn't anyway - but - the syntax has been a major part of what blocked me. I have over 20 years experience in reading more conventional syntaxes - Smalltalk asks me to throw that training away to be replaced with new training. Inconvenient, and a choice I cannot say beforehand will ever pan out: Paul Graham says he still finds it easier to read maths in infix notation than Lisp, and I fear something similar would hit me for Smalltalk.

Eivind.

JRuby

Although it's probably not quite what Avi had in mind, JRuby is a mixed mode compiler-interpreter written in Java, compiling to JVM bytecode. As the link notes, the JVM is derived from Self.

By the way, is a transcript available anywhere?

Future of Smalltalk programming...

I think Gemstone is the most incredible thing done in Smalltalk ever, and it was worth mentioning it in the presentation. It is interesting to notice that Gemstone also has a file-based scripting interface in addition to the image-based programming environment. However, unlike the other Smalltalks, image-based programming is done remotely, usually from VisualWorks or Squeak. Remote browsing, with a file-based repository such as ObjectStudio's, is the way to do Smalltalk for the future.

I didn't expect to hear it mentioned in the presentation, but I hope that when I release GNU Smalltalk 3.0 (soonish, the release candidate is out at http://smalltalk.gnu.org/ already) some of the issues with Smalltalk that the audience pointed out will be addressed (except that 3.0 won't have Seaside yet).

Like Ruby, GNU Smalltalk supports file-based development with an irb-like shell; it has a decent scripting syntax (no more file-outs); its packaging system is similar to Ruby gems; it uses the image basically as a cache and can bootstrap an image from the kernel's source code in less than a second. However, like other Smalltalks it is "turtles all the way down", and it has a browser written in itself (which can be used for programming, but at the moment is probably more useful for reading code).

some pedantry

Doesn't affect the substance of the talk, but it's a pity he got his facts wrong about Hindi and Urdu.They aren't separate languages that have grown together, but two descendants of the same language(s).

i.e. Urdu doesn't descend from Persian; just like Hindi, it is descended from Sanskrit (plus a mishmash of several other languages). It simply has more persian loan-words and an arabic-based alphabet, but it's essentially the same as hindi in grammar.

[end of nitpick]