Ruby On Nails Scratching a Chalkboard 52
So, as I explore how Ruby works, I’m discovering some bits of ugliness. It’s syntax is increasingly reminding me more of Perl than Smalltalk. A case in point: blocks.
I’d heard so much about Ruby’s Smalltalkishness that I was a bit taken aback when I saw control statements in the language grammar. In Smalltalk, control flow is managed using methods and blocks, and I knew Ruby had blocks (this is one of the things that you hear so much about in Beyond Java), so why did they need these control statements? In Smalltalk, control flow looks like this:
1 + 1 = 2
ifTrue: ['it is true']
ifFalse: ['it is false']Now, I can’t claim that this provides any real productivity boost over Ruby’s approach:
if (1 + 1 == 2) then
'it is true'
else
'it is false'
endBut I was kind of surprised, given Ruby’s ties to Smalltalk, that someone hadn’t hacked it in. So, I went about hacking it in myself. That’s when I found out why.
It turns out that blocks in Ruby have a very high level of syntactic sugariness. Not only do they have their own special literal form (which is a key advantage over say Java’s Inner Classes, or C++ functors without boost::lambda), but they also have their own special status which really makes them non-objects. (I found it amusing to discover that the most non-object entity in Ruby is a block).
Here’s the magic: blocks aren’t passed as normal parameters to functions. They are passed through an implicit variable (showcasing Ruby’s Perlishness here). So, if, for example, I wanted to add something like Smalltalk’s ifTrue: to Ruby, I’d do the following:
class TrueClass
def ifTrue
yield
end
end
class FalseClass
def ifTrue
end
end
(1 + 1 == 2).ifTrue { puts 'Math works' }
(1 + 3 == 2).ifTrue { puts 'Math is broken' }Notice that ifTrue doesn’t appear to take any parameters, and neither does the “yield” method. In reality, the block is an implicit parameter. One Ruby tutorial claimed this is a good thing, because it means that all Ruby methods can take a block as a parameter…. even if they don’t use it. Me, I’m a big fan of explicitness, but I can see that in a scripting world, sometimes these kind of shortcuts are nice to have. What’s bad about this is that not only does it mean that all Ruby methods can take a block as a parameter, it also means all Ruby methods can only take exactly one block as a parameter, and it has to be the last one.
Now, it turns out that Ruby has a wrapper around blocks called Proc, which lets you treat a block like a real object, Of course, it has all the syntactic beauty of Java’s Inner Classes. Here’s how you can do ifTrueifFalse in Ruby:
class TrueClass
def ifTrueIfFalse(trueProc, falseProc)
trueProc.call
end
end
class FalseClass
def ifTrueIfFalse(trueProc, falseProc)
falseProc.call
end
end
(1 + 1 == 2).ifTrueIfFalse(Proc.new { puts 'Math works' },Proc.new {puts 'Math is broken'})But wait! There’s more! Since Proc’s are proper objects, you can query them for meta-information, which is really handy for various dynamic programming tricks. Only… Ruby’s interface is kind of weird. Proc’s have this method “arity” which tells you how many arguments the block takes… sort of. For reasons passing understanding, if a block takes zero arguments, the function returns “-1” intead of “0”, and if it takes 1 argument, it returns “-2” instead of “1”. So, now we’ve established that it can never return 0 or 1, and that you can’t always use the return value as an collection size for your argument list. Here’s where it gets really crazy though: if your function takes a variable argument list with it’s last parameter, arity returns “0 - # of args”. So, quick question for you: if arity returns back -2, does that mean it’s argumetn list is one argument long, or that it takes one argument followed by a variable list of arguments? I’m not sure how Bruce Tate can claim that Ruby doesn’t have some weird anachronisms that get in the way of doing metaprogramming with a straight face.
In fairness, the case where you want to pass a single block as your last argument seems like the common case, and Ruby is a scripting language after all. I’m mostly annoyed because I’ve heard so many people talk about Ruby’s elegance, comparing it favourably with Smalltalk (which admittedly is not entirely without warts). Upon inspection it seems to have warts just like other languages (well, some languages have a few more warts than others). Still, there is hope. Ruby does seem to have some genuinely nice features, and it is open source, so there is always the possibility that some of these idiosyncracies will get cleaned up in the future.
UPDATE: So, someone with some real Ruby experience has clarified for me that nobody actually does “Proc.new” in Ruby. Instead they use Lambda. So, invoking my ifTrueIfFalse method would normally be done like so:
(1 + 1 == 2).ifTrueIfFalse(lambda { 'Math Works' },lambda {'Math Doesn't Work' })Which I have to admit does seem a lot prettier for some reason.
ANOTHER UPDATE: I’ve gotten some great comments to this article, and I thought I should incorporate their content. First, people have suggested that you can break up ifTrueIfFalse in to two calls that are chained together, and then get back some of the elegance. I thought about this when I first looked in to it, but you lose the ability to pick up a return object cleanly.
Antti Tarvainen provided some excellent points. In particular he clarified the difference between a Proc that takes no arguments (arity returns 0) and a Proc that doesn’t define any arguments returns -1. Furthermore, arity has been updated for Ruby 1.9 to what seems like a more sensible behavior. I noticed that even in 1.8
puts lambda {|a|}.arity returns 1, which suggests the Ruby documentation is a wee bit out of date.
I still think it’d be far more sensible to not overload the arity method and instead have numArgs? which gets you the number of required arguments”, hasOptional? which gets you back a boolean as to whether there are optional arguments, and argsDefined? which gets you back a boolean as to whether the Proc has defined arguments at all. Overloading the meaning of the return value just results in more code that needs to check for special cases and cases where you can’t actually know which of two states is correct.
Also, there seems to be confusion about my point in comparing it to Smalltalk’s ifTrue:ifFalse:. Of course one should use Ruby idioms when doing Ruby. The ifTrue:ifFalse: example is just a simple and well understood example of having more than one block in your parameter list. I will say that there is a certain kind of semantic elegance that comes from having all your control flow done through methods and objects. Ruby advocates always say that in Ruby “everything is an object”, but it appears that blocks and control flow expressions are not, and in this regard Ruby doesn’t quite live up to expectations set by Smalltalk and LISP.
Trackbacks
Use the following link to trackback from your own site:
http://xblog.xman.org/trackbacks?article_id=ruby-on-nails-scratching-a-chalkboard&day=12&month=09&year=2006
You better be careful criticizing Ruby or someone will call you a commuterrorist
Dude, I’m a Smalltalk advocate. That’s way tougher. If the Ruby guys try to take me on, they won’t know what hit ‘em. ;-)
Another way to partially, and uglyily, achieve a smidge more Smalltalkiness is by method chaining, i.e.,
The syntax does not look as good as Smalltalk, pretty much no matter how you format it: you can’t do something like:
and we can’t fake it with keyword arguments :/
I prefer both Lisp and Smalltalk over Ruby, but it’s quite fun nonetheless.
Maybe a little closer…
and, Dave Newton, the multi-line method chaining works if you end the lines with the dot or if you use backslash for line continuation.
Still uglier than ST, though.
You can also use the ‘cond ? true : false’ syntax like so:
(1 + 1 == 2) ? lambda{‘Math works’} : lambda(‘Math is borked’}
That looks better than
(1 + 1 == 2).ifTrueIfFalse(lambda { ‘Math Works’ },lambda {‘Math Doesn’t Work’ })
to me but your mileage may vary.
I read the
Proc#aritydocumentation after finishing your article. After that, the workings ofaritystarted to make more sense to me.First of all, a block taking no parameters is different from a block whose parameters have not been declared. The former checks that the number of the parameters is zero, whereas the latter just ignores all parameters.
Secondly, the way
Proc#arityworks differs from Ruby 1.8 to 1.9. The following is the documentation for 1.9:(http://ruby-doc.org/core/classes/Proc.src/M000808.html)
In 1.8:
In 1.9,
arityis defined as the number of parameters that would not be ignored. In 1.8,arityreturns the number of arguments a block accepts.The real strength of Ruby is that it combines powerful features from other languages (OO is Smalltalk like; Lisp: metaprogramming; Perl: string processing, glue scripts) in a simple design and a syntax which is easy to pick up for programmers proficient in mainstream languages (say Java). If I had to phrase in one sentence what sets it apart from other languages, I’d say “Ruby is simplicity done right.”.
I think people who know Smalltalk, Lisp or Haskell (add other language with more theoretic background here if you like) well are probably a bit disappointed when learning Ruby, because Ruby is not as “pure” as their favourite language, nonetheless is Ruby a great tool for many problems.
@Devin: Yeah, I didn’t like the way either of the obvious alternatives looked :( Blech.
I didn’t even think of your block idea (which is kinda funny, since that’s exactly what we’ve been talking about and I solve a lot of problems that way! :) but it’s probably as close as you could get. Good catch!
@Farrel: True, but the larger issue goes beyond single ifTrue:ifFalse: message comprehension; that happens to be a special case where there are two mutually exclusive messages.
Your problem can be solved if you implement iftrue/iffalse on Object instead of TrueClass (everything except nil and false is true in Ruby, after all):
$ irb irb(main):001:0> class Object irb(main):002:1> def if_true() yield; end irb(main):003:1> def if_false() false; end irb(main):004:1> end => nil irb(main):005:0> module False irb(main):006:1> def if_false() yield; end irb(main):007:1> def if_true() false; end irb(main):008:1> end => nil irb(main):009:0> class FalseClass; include False; end => FalseClass irb(main):010:0> class NilClass; include False; end => NilClass irb(main):011:0> # Now your example irb(main):012:0* (1 + 1 == 2).if_true { “It is true” }. irb(main):013:0* if_false { “It is false” } => false irb(main):014:0> simen@nettverket:~$ irb irb(main):001:0> class Object irb(main):002:1> def if_true() yield; end irb(main):003:1> def if_false() self; end irb(main):004:1> end => nil irb(main):005:0> module False irb(main):006:1> def if_false() yield; end irb(main):007:1> def if_true() self; end irb(main):008:1> end => nil irb(main):009:0> [NilClass, FalseClass].each { |klass| klass.send :include, False } => [NilClass, FalseClass] irb(main):010:0> (1 + 1 == 2).if_true { “It’s true” }. irb(main):011:0* if_false { “It’s false” } => “It’s true”
Bah, formatting screwed up.
Anyway, the “blocks are only pseudo-objects” thing in one of the things about ruby that annoys me. I believe the only reason it’s there is for performance (and possibly some heritage from perl wrt pseudo-variables), since the current implementation doesn’t make it into a Proc object unless you prepend it with an ampersand in the argument list (and you can only have one ampersand per method). But then you have to prepend an ampersand to it again to use it with a method that expects a block.
If I’m not wrong, Ruby’s Block are like Smalltalk’s, nobody said “they are the same thing”. So that gives rise to a few points
Ruby does single blocks best, asthetically speaking. As you pretty much pointed out after experimentation. More than one, and it doesn’t look like Smalltalk (or Ruby for that matter).
Don’t try to make Ruby look like Smalltalk. It may give some people a feeling of looking at Smalltalk, and hence pushes them to mould the language into Smalltalk. Its not going to happen. You end up obviously enough with very asthetically displeasing code. Believe me, I’ve tried simulating the same experiment, of Smalltalk like conditional statements, and it didn’t look nice.
Another point with regard to the given example is that, the ifTrue:ifFalse: is really a feature of Smalltalk Method’s syntax (or did they call them Messages?). Its Smalltalk’s way of doing keyword parameters (which I might add is very nice) and method syntax in Ruby is definitely C-like, its not Smalltalk like. So the more you try to make it look like some other language’s syntax, the more weird it can be =D
If you actually believe Smalltalk’s if else syntax is nicer than ruby’s (or just about every other popular language), then I don’t think I’ll be paying attention to what smalltalk fans say anymore. squeak out.
Most of your are missing the point. One of the key focuses in ruby is to provide constructs which are easily readable and understood. ‘if/then/else’ achieves this, which is probably why it was used. Consider another way ‘if’ can be used:
puts ‘hi’ if (1 == 1)
Ruby code is meant to be read like English. Smalltalk’s implementation does not allow for the same flexability or readability.
Farrel, I think you completely missed the point… just spend 5 minutes looking at Squeak’s code :-)
I have no Ruby interpreter handy, but doesn’t this work?
And, if this doesn’t work, would it work if the “self” keywords were replaced by “true” and “false” keywords as appropriate?
(If only I had Ruby on this lab computer, I could check these things!)
@Doug: You’ve missed the point. This isn’t about if/then/else; this is about blocks and syntax. I’m assuming your dismissal of “Smalltalk fans” because of one particular religious war was in jest.
@Ben: Smalltalk’s syntax is actually more flexible, because there barely *is* any. You are also focusing on one particular case, if/then/else, which I am now wishing wasn’t the example given, because it’s throwing people off the original topic.
“Readability” is subjective and also not the point here. Some people find Lisp or Forth unreadable whereas I prefer them because the syntactic model is simpler.
YMMV.
@Simen: I don’t see how that’s ultimately any different, but you’re right that the funky block stuff is a mild Ruby irritant.
“Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people.”
For the “smalltalk is weird!” group, one thing that confuses people looking at Smalltalk is that they’re not really “named parameters”, although that’s how it often works out. They’re method selectors, so in the case like:
aDictionary at: 5 put: “hi mom”
The method selector is at: put:
You can’t arbitrarily reorder the “arguments” unless there is another method for every permutation, in this case, you would have to define (or your implementation would have to provide) a put: at: method. This may be fine until you have ten “arguments” you need to pass into a method, but then, that smells like a class, doesn’t it?
Lisp is a different beast, of course, and named parameters, since they’re, well, named, can be placed in basically any order.
Ben wrote:
First off, my point wasn’t about readability but about how easily one could work with multiple blocks. However, as far as readability goes, you seem to be assuming that Smalltalk has only one way to do boolean logic, even though Ruby has several (as you’ve demonstrated). In fact, Smalltalk doesn’t have any reserved words for control flow, so you can do pretty much whatever you want. Certainly it’s possible to do the equivalent to what you wrote in Ruby with something like this:
or perhaps better:
If anything, Smalltalk’s syntax tends to be more readible, as another poster pointed out, whenever there is more than one parameters, it forces named parameters, so argument order is essentially encoded in to the message.
Ruby’s Perlishness is the reason I just can’t stand it and I use Python instead.
ArtT write:
Both Ruby and Smalltalk have ways of doing named parameters so that order doesn’t matter: they simply use hashes/dictionaries, which is basically what LISP does too (although Smalltalk’s way of doing this isn’t quite as pretty as LISP and Ruby’s syntax, because the Smalltalk idiom is either to using chaining to build an object that represents all the arguments or used the named ordered syntax).
What is different about Smalltalk is that it forces parameters to be named in any case where you have more than one parameter (well, you can cheat with methods like with:with:with:, but that is horrible and there is clearly a strong disincentive to do so). I’m not sure how important that turns out to be in the grand scheme of things, although I find it tends to be more useful in a dynamically typed language because you can’t even catch the cases where the parameters are different types. I suspect the Ruby folks just get around this by passing arguments using a hash for the case where many arguments are required.
Perhaps I haven’t read properly, but why hasn’t anyone pointed out that blocks can be passed explicitly? e.g.
def x(&y) puts y.class end x { 1 + 1 }Try it out.
I wish there was a ‘lambda’ button on the keyboard!
By the way, here’s my cutest solution:
class TrueClass; def =~(a); a[:ifTrue].call; end; end class FalseClass; def =~(a); a[:ifFalse].call; end; end def _(&a); lambda &a; end (1 + 1 == 2) =~ { :ifTrue => _{ puts "True" }, :ifFalse => _{ puts "False" }, }Peter Cooper:
Yes, they can be passed explicitly, but even when you do it explicitly you can only pass one and it has to be the last parameter.
Peter Cooper:
So passing them as a hash isn’t a bad idea (although likely to be even slower), but your definition of “_” is just evil!
Peter Cooper:
And in case you got the wrong idea by my omission =~ seems at least as evil.
The real downside of this technique is that operators like =~ and cute methods like _ may already be overridden to perform cute syntax hacks like those in my code. Still, just wanted to prove you can kinda contort Ruby into doing whatever you want, even if it’s not practical for real world use ;-)
From a terminology perspective Smalltalk has both messages and methods.
When you write:
obj para1: some para2: thing
You are sending a message called para1: para2: to the object. The message dispatcher then matches this with the para1: para2: method on the object that receives the message.
In short the message is at the call end and the method is the code that is executed in response to it.
This message/method distinction is built into all OO languages and constructs. How the message dispatcher works is one of the things that distinguishes OO languages.
Smalltalk’s message dispatcher is always dynamic and class based. I’ve heard that the dispatcher can be upgraded to allow instance methods, but I never got it to work.
Javascript’s dispatcher allows both class and instance methods whilst C++’s also adds in static binding (bypassing any dispatcher, or doing the dipatching at compile time depending on how you think about it).
Kirit:
Javascript has only instance methods, because it is prototype based, which means there are no classes. An object’s prototype is its parent, etc. Self, Slate and Io are examples of prototype based languages.
A bit wooly I know, but I was sort of considering the prototype to be the closest thing to a class that the language has.
I admit to not having thought through too deeply on the difference between prototype languages and other language types, especially about the similarity/differences between the prototypes and classes.
In a prototype based language, every object is both a class and an instance. There are only instance variables, and you make a new object by cloning an existing one. The cloned object is linked to as the prototype, like an instance links to a class.
Also, about the main post: even Lisp, which has virtually no syntax at all, has if/else in its grammar. Why shouldn’t Ruby?
Simen wrote:
Because Smalltalk doesn’t. ;-)
Seriously, I’ve tried to make this clear several times, but I seem to be failing: I’m not suggesting that Ruby needs to do if/else the way Smalltalk does. if/else was selected because it’s a well understood case where two blocks are passed to a function, which is what I am suggesting Ruby should be able to do well. Lambda helps paper over some of the syntactic ugliness, but it’s still not as clean as LISP or Smalltalk.
@Simen: The difference is that if/then/else in Ruby is an additional syntactic construct. In Lisp it’s just another function.
Nobody said Ruby shouldn’t have it. The OP was merely trying to compare a particular subset of claims of Ruby’s Smalltalkiness vs. its implementation, which obviously don’t match.
Personally, I don’t find Ruby to be overly Smalltalky: things were inspired by Smalltalk (things like .each, etc.) This isn’t bad, this just *is*.
Purists are offended by this (and rightfully so) because it isn’t pure. That’s why they’re called purists. This doesn’t make Ruby bad. I am a purist, some of the warts are very irritating, and I still prefer Smalltalk and Lisp. But I still find Ruby a very productive environment, because it combines two modes of programming I’m very familiar with.
KenM quoted Matz as freely admitting it’s a bad ripoff of Smalltalk and Lisp. I actually think it’s a GOOD ripoff of Smalltalk and Lisp, not because it’s “pure”, but because it’s productive and as Matz says, it’s “nicer to ordinary people.”
Perhaps it’s a bridge language to bring people into the fold of Smalltalky, Lispy languages. Or maybe it’s Just Plain Good Enough(tm).
Either way, pure or not, syntactic warts and all, it has shaken things up, and this can only be a Good Thing.
Just because I’m enjoying this thread so much, I thought I’d throw in another pointless, though far more pragmatic, example:
puts case (1 + 1 == 2) when true: "True" when false: "False" endI’m not sure how you’d implement put:at: like that.
Dave: no it’s not. If is a syntactic construct. It just looks like a function because everything in Lisp is a list. Watch, Scheme and Common Lisp:
Christopher: yes, you’re right, the block thing is stupid, and it has bugged the hell out of me before.
Its Iimplementation* is irrelevent; it does not have its own syntax, like if/then/else in Ruby and similar languages.
It does have its own syntax. Here’s the part that describes it in R5RS. The fact that it all looks the same, and that code is data in Lisp, is irrelevant. This isn’t implementation-specific.
The Lisp “if” special form can’t be implemented as a procedure, because Lisp semantics are strict, meaning a value is computed even if there’s no need for it, contrasting with lazy languages such as Haskell. It can be implemented by macros, though.
This contrasts with Smalltalk, where ifTrue:ifFalse is a method, used with standard method calling syntax.
Bottom line, Ruby isn’t Smalltalk, or Lisp, or Perl, and it doesn’t try to be, but that block thing sure is annoying.
That simply isn’t a syntactic construct in the same way if/then/else etc. are, it’s a special form that takes two expressions as arguments. That’s just not how languages with more syntactic noise operate, but whatever. How it’s implemented (a special form, in this case) still isn’t relevent.
If you look at the language grammar for Scheme, say at http://www.htdp.org/2001-01-18/Book/node43.htm (which doesn’t use ‘if’ but that’s not important) see how orthagonal it is? See how the keywords simply occupy the same space as non-keywords? Regardless of implementation the syntax doesn’t change.
Dave Newton: If you look at the language grammar for Scheme, say at http://www.htdp.org/2001-01-18/Book/node43.htm (which doesn’t use ‘if’ but that’s not important) see how orthagonal it is? See how the keywords simply occupy the same space as non-keywords? Regardless of implementation the syntax doesn’t change.
Okay, let’s some this up:
Can we all pretty much agree on that?
This whole discussion reminds me of something that went on for months and years in the C++ circles: “how to build an auto pointer”. I think the final level in elegance was reached after many articles and rounds of critics and suggestions. Hurrah, we managed to create an auto-pointer class.
“Ten different ways to write one line of code that does the same thing in Ruby” is probably even more hilarious than the auto pointer. No wonder programmers are again drooling over a chance to spend their time on endless niftiness and cool programming tricks which approaches cryptography.
You could start secret societies that share their wildest Ruby tricks. The sheer obscurity of all the tricks would truely make such societies a hit.
…just kidding, of course.
I was all excited about learning the secret handshake then you said you were kidding.
snibble
@Christopher: I don’t think anybody ever said there was anything wrong with the different approaches, just that you had expected something else and discovered one of Ruby’s Little Uglies :)
@Mike B:
thanks to our good friend whytheluckystiff, one is never without ruby when there is an internet connection available: http://tryruby.hobix.com/
I admit to not having any Smalltalk or Lisp experience.
Having experienced Logo, Forth, C, C# Python and Ruby, looking at languages like Lisp and Smalltalk, the syntax often looks alien and unapproachable, hence my lack of progress with them.
Ruby caused me to look at Smalltalk and Lisp. Yet despite the overwhelming love the proponents have for them, The value is difficult to comprehend. As one commented above, it is highly likely my experience with procedural languages blinds me to the benefits of Lisp, Smalltalk and other non procedural languages although Ruby is now my favorite which mixes these and other programming paradynes.
So, I have two difficult questions:
1) Why hasn’t Lisp or Smalltalk become as mainstream as Java or C++ if they are so powerful?
2) Why is the syntax so difficult to grasp for the uninitiated yet so beautiful to the practicing?
Elise:
Well, there is long and tortured history behind each of them, but it’s worth noting that both of them were mainstream at various points in time. I think one thing to keep in mind though is that a more powerful language isn’t always an asset.
The beauty comes from the consistency. and simplicity. Honestly, I’ve always been able to explain the syntax of either to someone in a matter of minutes. The catch is that their syntaxes are both quite different from the BCPL family of languages, which seems to intimidate people. They look alien but I assure you the syntax is far more approachable than most languages. LISP’s infix notation is a bit weird for arithmetic, but otherwise is pretty similar to procedural code. Smalltalk’s syntax is different, but it is incredibly simple. You basically only have three different bits of syntax to learn to get started, and there’s maybe five or six syntactic structures in total. Cincom pretty much sums up the key bits of the syntax on one page..
Christopher:
Your simple explanation has prompted me to dig a bit further this time and try some Smalltalk coding. Thank you.
The Cincom primer is great (thanks for the link) and the free VisualWorks environment looks appealing (first impression) compared to the open source Squeak Smalltalk environment I’ve tried in the past. To be fair I haven’t used either in any depth whatsoever. This comment is purely based on asthetics and my past IDE experience.
Which Smalltalk do you use and do you use Smalltalk in any professional capacity?
@Elise:
1) There are lots of reasons; a lot of it boils down to inertia… Algol -> Fortran -> C -> C++ -> Java ->() C# is a pretty logical progression of languages, and that *is the progression in the mainstream. There’s a few others thrown in there (COBOL, Basic); I’m speaking in general terms.
2) Lisp and Smalltalk syntax isn’t difficult to grasp at all; like Christopher said, minutes. Wrapping your head around the languages’ concepts is what takes the effort.
As you’ve discovered, Ruby combines things a bit (with a couple of warts :) and may make entry in to one of its “parents” easier.
I used to use Smalltalk professionally in days gone by (over a decade ago). I was using Visual Smalltalk which I believe has been discountinued. These days I mostly use Squeak (and I agree that it’s UI is quite foreign, there is a project to bind it to wxWindows which I watch with great interest) and Seaside for personal web projects, but I’m experimenting with Cincom (which I’ve used in the past) and Vista Smalltalk.
For getting started I usually recommend people use one of Cincom or Squeak. Squeak’s environment is more foreign, but it does a fantastic job of getting you started. Cincom’s stuff is more standard fare, but it’s a more commerical grade experience (well, except for my pain with Linux).
There are also a number of reasonable books that discuss development in Squeak which help out a lot.
I’ll have to try the Cincom, though; it would probably generate less resistence to management just because of the way it looks.
Dammit! Sorry. Server musta been slow and there’s no indicator to say something is happening; I thought Firefox had locked up.
Algol -> Fortran -> C -> C++ -> Java ->() C# is a pretty logical progression of languages, and that *is the progression in the mainstream.
I don’t think I’d describe Algol as “mainstream” in the same sense as the others in that list. While Algol had a lot of influence in academia and on the design of other languages, the only commercial software development I know of using Algol was on Burroughs/Unisys “Large Systems” (aka B6xxx series) mainframes, and the Algol they used was very non-standard.
I’d say the mainstream predecessor to Fortran was various kinds of assembly language (for particular IBM mainframes, but I know little about that world).