Bits of History, Words of Advice
gbracha.blogspot.com
gbracha.blogspot.com
I think a modern parallel is darklang.com. It might be great, but it faces the same resistance for the same reasons.
You can do some amazing things if you integrate everything into a big monolith, but that also makes it impossible to adopt a technology part-way.
Perhaps Smalltalk was too far ahead of its time at the time it initially appeared. The computing machinery of the age couldn't run it efficiently enough. If they had, it just might have displaced everything else. At the time there really were no IDEs, no good SCM, no review tools, etc. And so it could have made that world in its image, which at the time was frankly superior.
But for the broader point, yes -- Smalltalk does not play well with others. I'm sure it can be made to, but that was not its first instinct.
And, I get a double-clickable app that runs on Windows, MacOS, and Linux. Last I looked there wasn't an open-source way to do this with smalltalk.
This is bad? Everything (besides maybe reviews) is horribly broken for most (modern) dev, so not sure it's a negative to just nuke it from orbit.
Having fewer options is not inherently good.
I'd send them a table flip emoji but im pretty sure they wouldn't get it, they legitimately think they're giving me good helpful advice.
They simply don't understand that if you need to restart something, said something is fucking broken.
Yikes, your fix for your software is just delete it and start over? What is so leaky about the build process.
Aside from that, I don't need typescript, its being forced on me.
I do want typescript, because it has advantages.
A frustratingly broken workflow is far too high of a cost to pay though.
SCM? Hah! The image was path-dependent. I seem to recall getting into a position where the code you filed out of one image couldn't be filed into a new image---you had to get a previous version and then upgrade.
Deployment strategy? Ship 'em the image. Maybe you should disable the editor first, though.
No matter how bad you think "modern" dev is, Smalltalk was worse.
I'm not a Smalltalk fan really (though it's neat) but it was doing "containers" quite intensely long before anybody else.
A Docker image can run an app written in JS, C++, Python, Haskell, brainfuck, whatever.
Smalltalk was not doing containers.
All the time wasted not solving my problem on e.g. linux, filesystems, config files, bash, docker, kubernetes, rest, git, programming languages ...
With either of these tools, it seems quite dependable to clone a git repo, and get it up and running in minutes or even seconds with a couple consistent commands. That is as long as the dependencies are fully rooted within the ecosystem.
Take a look at SLIME+swank for Common Lisp, or Geiser for Scheme, or Cider for Clojure.
A common architectural choice is to have a REPL buffer in Emacs, connected over a socket to the language runtime which hosts the REPL. You edit a text file, sending whatever portion of your program you want to the REPL, where it is evaluated in the runtime, with results printed back to the REPL buffer. There are advanced introspection and documentation workflows supported by being connected to a live REPL.
These protocols easily and transparently cross the network, so you have the ability to troubleshoot a production issue on a (hopefully previously-quarantined) production host exhibiting the issue. You can inspect state, recompile functions on the fly and replay the failure all from the comfort of an editor and REPL that you are familiar with from dev-time.
What you are describing, though, is conceptually easy enough to implement: modern Smalltalks (Squeak, Pharo, and friends) all have robust interfaces to Unix and stdin/stdout. You could easily create a repl. It's also easy to make TCP, HTTP, or WebSocket servers, so you can create interaction that way as well. And of course there is Seaside, which has some tools already for interacting with a Smalltalk image through the browser.
Another approach is Amber Smalltalk, which is a web-based Smalltalk for frontend development (amber-lang.net)
Getting back to giving up your editor. It should be possible to use many editors with the smalltalk of your choice. However, in practice, there are many half finished and abandoned tools for doing so[4], and fighting with that while learning the system is unlikely to be productive.
[1] https://github.com/pharo-vcs/iceberg [2] https://ci.inria.fr/pharo-contribution/job/EnterprisePharoBo... [3] https://www.slideshare.net/umejava/dockerizing-pharo [4] https://dmitrymatveev.co.uk/shampoo/
They work similarly on the surface level, but the tradeoffs are quite far apart. The deployless nature of Dark on the backend is the central big benefit, and it's a distinction that doesn't exist when you are developing local GUI apps. Also, in Dark there isn't a peristent VM image that everything is entangled with, not to mention the lack of entanglement inherent in the FP language.
To me Smalltalk feels too integrated, which is a problem for me. I like a language that's small in it's (open source) core, with lots of (competing) integrations (IDE, testing, profiling) available. It helps me not to feel locked-in to an ecosystem.
If you're willing to accept heavily entrenched ("a lot of development" as in the parent), then languages like Fortran and COBOL are highly successful. They underlie an enormous amount of infrastructure in the world.
Visual Basic is probably the biggest success of a non-Algol-derived general purpose language after the dominance of C as anything other than mostly-legacy.
There are some others (Erlang, some Lisp-family languages [recently Clojure], some ML family languages) but languages with Algol-derived syntax are still far and away dominant.
There's also lots of not-general-purpose languages without Algol syntax (SQL, for instance.)
That changed once C/C++ look over, but until then it wasn't something large proportions of programmers knew and had an affinity for.
Why did Rust move from an ML syntax to a C syntax?
Ruby, though still in the Algol-derived syntax family, is even less C-like than Python.
It is true that mathematics is closer to programming than tailoring is, but you can't escape this issue. So I don't get particularly worked up about it.
(This context is why this matters too; "vector" as a term for this is established, just like the linear algebra term is established.)
(I do like to joke about getting worked up about this though, but I pick on String, which should be StrBuf, instead of vectors.)
But for the sake of internet pedantry, you seem to be saying that calling it vector is acceptable because it's established, not that there are any inherent advantages to this right? Because I would argue that we can and should take the opportunity to turn the page on imprecise terms of art which only exist for historical reasons.
Even looking at Rust, I'm very glad that char|short|int|long has been replaced with i8|i16|i32|i64 even if the former are terms of art which everyone can understand.
Please excuse my WIP CSS, but I wrote a longer bit about this over at https://steveklabnik.com/writing/the-language-strangeness-bu... . I think that, for languages that intend to be adopted broadly, you have to choose carefully where you diverge from existing practice. Sometimes, you have to change, after all, that's how progress even happens in the first place! And sometimes, you're forced to change, because you don't truly have an analogous situation.
(On a side note, the CSS is perfectly fine, and I've been looking for a static alternative to Ghost for blogging, so I might give next.js a try)
Ah so, next is a way to make websites in general; the template linked is a good one for a blog though. I've had pretty positive experiences with next so far; I just re-did my blog in a hurry over the weekend for unrelated reasons, so it's pretty much just the template at the moment.
You can have a vector of integers, a vector of real-numbers, why do you think a vector of strings doesn't make any sense? Strings can be given a well-defined ordering. You can think about strings as a points along a string-line, if you want to.
For example - Java often names packages using co-ordinates (vectors) in an n-dimensional string space. Seems to make sense to me?
And how would you compute the cross product of <"foo", "bar", "baz"> and <"apple", "orange", "banana"> exactly?
How would you compute the cross product of <NaN, NaN, NaN> and <NaN, NaN, NaN>?
Some vectors don't have a useful result for cross product, even if they contain 'numbers' and even if you can get some kind of result out.
Same with dot product of a string. Doesn't make much sense... so probably don't do it.
Vectors don't 'contain' numbers, a vector is a multidimensional value. The fact that a C++ vector is conceptually a container for values more than anything else is a reason why 'vector' is a poor name for this component.
The practical problem is, when you do a lot of work with linear algebra, you would really like to have the term vector to use for its canonical mathematical meaning rather than having it reserved for a data structure which is not suitable for that purpose.
Cross product isn't a well-defined operation. The wedge product[0] would be <a,b,c>~<x,y,z>=<<ay-bx,az-cx,bz-cy>>, assuming I didn't get the signs wrong again. That would require scalar multiplication and subtraction of strings, though, neither of which are generally well-defined.
If you substitute in string multiplication (ie concatentation) and addition of negatives (alternation and reversal, the latter of which is only vaguely justified by anticommutativity of multiplication), you get:
<< /fooorange|elpparab/ ,
/foobanana|elppazab/ ,
/barbanana|egnarozab/ >>
which frankly sounds to me like a pretty good argument that vectors of strings make no sense and shouldn't be supported, but maybe someone working on parsing algebras could come up a more useful interpretation.0: http://en.wikipedia.org/wiki/Wedge_product
Edit: FWIW, wedge product of NaN makes perfect sense: <NaN,NaN,NaN> ~ <NaN,NaN,NaN> = <<NaN,NaN,NaN>>.
If you remove semicolons and use indentation over curlies in C it will look pretty pythonesque.
#($a #a "a" 1 1.0)
There's no way a C programmer can know what that means without looking it up.
It doesn't take too much breadth of knowledge to recognize those all as different kinds of literal syntax, even if you don't know the exact details. #(...) for some sort of collection, probably a list or vector, $a and #a for different kinds of atomic value, even if it's hard to guess whether any one of them represents a symbol, a character literal, a perl-style variable reference, or something else.
If such prosaic syntax is really so unfamiliar-looking nowadays, it really speaks to a major gap in how people are taught about programming. Comparable to if it were common for younger mechanical engineers to not even recognize a slide rule when they see one.
subject.verb(arguments)
Is more intuitive than the example you've given.Of course it's also quite possible to write an equally cryptic line of C code.
Smalltalk is actually quite readable in practice, though the keyword syntax seems to throw off experienced programmers from other languages. It's worth noting that the language was originally tested on children, so it was also designed to be easy to read and learn.
The equivalent of your C code above could be something like:
MyObject doSomethingWith: anArgument:)))
It's not a direct linear descendant of C the way C++, Java, C#, and lots of other relatively recent languages are, but it's still a lot closer to C than Smalltalk is.
The syntax was again "ugly" but some people were so excited about the language that I had to look into it, which is when I learned why the syntax looks the way it does, and how powerful it is because it looks that way.
Needless to say, I felt monumentally stupid, not just for having done myself the disservice of not looking into lisps earlier, but for having the audacity to write things off out of "ewww" feelings. A perfect exhibit of programming being a pop culture and me being a mindless consumer.
Thankfully I learned my lesson, which came in handy when I came across Smalltalk. The syntax is powerful [0], and good luck getting that kind of power out of any conventional syntax language.
[0] among many other aspects.
Clojure actually fixes quite a few of the syntax problems with previous lips, but doesn't go nearly far enough so they still have the same problem.
M-expressions didn't just fail because they were unnecessary; they also failed because they just weren't a very good syntax. They were more cluttered and less readable than S-expressions, while adding no real practical value.
But Clojure has arguably demonstrated that you can evolve on Lisp syntax without going to M-expressions, or even changing S-expressions all that much, just by adding a few new bits of literal syntax and sprinkling some clever macros into the standard library. (A macro invocation may not technically be syntax from the parser's perspective, but it sure feels like syntactic sugar from a user experience perspective.)
And, while I haven't actually tried them at all, I've at least been intrigued by t-expressions. They seem to achieve some nice things like git-friendliness and easier visual scannability without sacrificing on macro-ability.
As for Clojure, TBQH I'm not too convinced that few sigils make all that difference in writing, in plus or in minus. But I am far from my 10k hours in Clojure so YMMV
They're that, but it's also used to describe a specific syntax. IMO, the more general definition is not particularly valuable and should be discarded. Because it's just not useful to paint m-expressions, i-expressions, t-expressions, etc. with the same brush like that. Doing so just muddies the waters. If you want a general-purpose term for alternative lisp syntax, why not "alternative lisp syntax?"
At the same time, after 35 years as a programmer (mostly in C++), it is rare these days that I find myself ever thinking that my inability to get "power out of [...] syntax" is a problem when I'm working.
The problems I feel I face these days, working on a mid-size (700k LOC or so) complex, native, multithreaded, realtime, creative software project, are mostly just caused by the fact that what we need to do is hard, no matter what the language is.
I feel as though attempts to elide those difficulties through syntax really do almost nothing to address the underlying hardness of the problems. One example: it is true that there are quite a few places in the codebase where using lambdas/anonymous local functions would be handy. We wouldn't have to create actual named methods to tidy things up, even though we only use them once. But none of this relates to the actually hard stuff: managing UX and responding to changing and expanding user expectations.
Lack of a Standard. Didn't really bother us. FYI we were using Digitalk Smalltalk. People in those days didn't have the expectation of changing their toolset without incurring problems.
Business Model. At that time people paid for software. The free (as in beer) software distribution model didn't yet exist. The tools were expensive but they were justified by programmer productivity. To that end, the tools made programmers very productive. It's one of the best environments I've ever worked in - and that was over 25 years ago!
Performance. Ah - this is where we started having problems. At that time Smalltalk hadn't yet optimized integer arithmetic and as a result simple numerical operations were slow. The garbage collector was also difficult - when it ran it would essentially hang your machine for several minutes. That would improve over the years but it was bad early on. Performance was the deciding factor in our not using Smalltalk.
Interaction with the outside world. Digitalk took care of this. It was workable, i.e. this isn't where we had problems or concerns.
Deployment. Digitalk was capable of producing a Windows executable file. There were two problems though: 1) it made a guess as to which classes should be included in the executable artifact (you could manually adjust), this made automated testing extremely important because you would need to test a release candidate and 2) it employed it's own windowing system which it would embed in the executable. It never looked like a native Windows application. The marketing folks and product line managers didn't like that aspect of Smalltalk.
Bottom line - poor performance and a poor end-user experience killed Smalltalk for us as it did for many others at the time. You know the saying you only get one chance to make a first impression? That goes for programming languages as well. A LOT of developers gave Smalltalk a go in the early 90's and ran into these issues. Though these issues would later be resolved by then the perception damage had been done and everyone had moved on.
It's interesting that Smalltalk is one of the most influential languages that never caught on.
It used OOP and was leaning heavier on the code-side than Smalltalk, which had this in-place modification of a already running system.
I think Java went a step back so people would understand it better.
* OOP in a C-like syntax without the complexity and traps of C++, this made it attractive as a teaching language and ensured a steady supply of Java developers
* Cross-plattform-ness, reasonable performance, easy multitasking, and the Servlet API made it the ideal successor to Perl as the default option for web development, leading to ubiquitous industry adoption.
However, Java did solve one really annoying problem that's hard to properly appreciate if you didn't leave any of your own blood behind in the 1990s: Cross-platform development. There were so many operating systems and architectures back then, and none of them had really risen to prominence as a general-purpose option, so most shops were working with a pretty decent variety of different platforms. At one point I worked at a desk that had three different computers with different processor architectures and operating systems (and therefore basically no software in common) sitting on the same desk, and all three were needed for some purpose or other.
Into that environment comes a new language/platform that offers write-once-run-anywhere with decent (if not great) performance, and one of the first standard libraries that might be recognized as reasonably mature by modern standards.
The force drags people to it, and stops it splintering into twisty maze of implementations all alike.
In companies where custom, in-house software development was required, NeXT, NeXTSTEP, and Objective-C did quite well.
The whole macOS thing happened about 10 years after the first successes of Objective-C, when it was well on the path to obscurity due to the failure of NeXT's hardware, and then operating system businesses.
But this also kinda proves your point ... it was NeXTSTEP that made Objective-C succeed (both the first time, and then again with macOS/iOS).
It was a very nice system compared to its contemporaries. MacOS 10.1/Cocoa was a lot more fun than anything Microsoft offered.
You can have an awesome language with lousy interaction, and it's dead in the water.
Conversely, you can have a mediocre language with a great ecosystem, and it takes over the world.
In spirit at least, it seems a resounding success.
I miss Smalltalk. I miss it's clean syntax. Were there times when keyword syntax got odd, yes. But less so than list base call syntax (and even weirder with the hybrid list(keyword) keyword messages.
Was everything's done via messages all the way down always the bees knees. There were some edge cases (zip?) were it was difficult to figure out where the behavior really should be bound. But the trade off was simplicity and consistency. None of this why is len() a function and upper() a method nonsense.
I miss the simple syntax and pervasive use of Smalltalk closures.
I miss the tooling. The RefactoringBrowser was one of the most amazing code environments out there. I found code faster. I authored code faster. I changed code faster.
What have I appreciated as I've wandered through the wreckage of modern in use systems?
Namespaces. There were some Smalltalk experiments here, but they were late and varied. My favorite was probably that of Smalltalk/X. I mostly like pythons namespaces: "we should do more of those". Not a fan of pythons shadowing rules though and have never decided whether it's namespaces and shadowing are codependent or independent.
I kind of like typing. I remember I was skeptical of Strongtalk typing at first, but I've come to appreciate that style of annotation. Where typing always seems to break down for me is containers. I am just not a fan of generics. They are to typing what preprocessers end up becoming, a sort of "deep state Illuminati" of the program. Gilad hinted at a proposed solution to this a while back, but I never saw a follow up.
And of course cheep tooling. I don't mind paying for things. But Smalltalk business model was about platform entrapment. There was no incremental. No choice. You had to choose the whole party up front.
Most of its adherents developed on Apple's early Macintosh line. One of the core tenants of the Mac was intuitive usability. The Mac developer's 'Bible' was the Inside Macintosh series that featured Object Pascal (Think Pascal was a realy good IDE for it's time) and the MacApp library and resources that made it fairly easy to produce software that adhered to Apple's then state-of-the-art UX guidelines.
Smalltalk at that crucial point in time was of in it's own (academic) world, with its own windows and menus that didn't feel at all like the rest of the Mac's software. While this would soon be possible, it was too late and did not offer enough of an advantage to get the Macintosh developer community to turn away from Object Pascal. That would only be achieved by years of C/C++ programmers pushing for that language's adoption across all platforms.
In reality I think if we do an honest accounting of the situation we can see that these have been the more pragmatic engineering solutions for their times, and so that's where the $$ was. I worked in Java for years, but didn't particularly like it, but it is, I think, what the marketplace needed and could handle at the time.
And I think JS/ECMAScript etc. is a reasonable practical solution for the imperfect world that evolved out of Internet/browser tech.
Unlike the author I don't think Sun's fortunes would have been any different if Self/Strongtalk or some other Smalltalk-world inspired/derived tech had been pushed hard. The market didn't need or want it.
IBM did a similar pivot with their VisualAge line, and they did it for pragmatic reasons.
Finally, let's look at the bigger picture: in the end, what we have with the browser + modern JS on V8/SpiderMonkey etc. is a dynamic object oriented programming language that allows for dynamic manipulation of its environment, is accessible to any user, can be edited and inspected live, can present interactive media to users, and has a large community of authors.
Is this really that far off from what Alan Kay and Dan Ingalls originally wanted? Purists will gag, but I think as much as I hate front end dev in JS that there's actually a lot here that is Smalltalk inspired.
EDIT: I spent much of the 90s and early 2000s cringing at what was evolving. I was really into PL research and really liked the Self-inspired world of prototype OO languages. I really dug LambdaMOO and spent time writing my own shared-world multi-author persistent-world object oriented virtual machine type systems. But there's no way any of that would pay the bills. I still avoid JS work really, but I can see the niche that this filled. It's imperfect ... but that's the world. I'm grateful to V8 & friends for making it suck a lot less. And that work in V8 is a direct descendant of some of the really neat pioneering stuff in the 80s&90s.
There's a good response the original article here: http://www.wirfs-brock.com/allen/posts/914
I don't really have much love for the combination of dynamic types and object orientation in general, but could someone explain what they got from smalltalk that they don't currently have via Ruby, Python, or other currently popular languages of similar discipline? I've seen lots of explanations as to why it failed...but why do people still talk about it like they miss it?
* BlockClosures. Reified and used ubiquitously. Did I mention reified? Since the language had no control flow builtins/keywords, it was all done in the library. And since Closures were fully first class objects that you could explore, understand, and extend, you could write control flow to your hearts content.
* Simplicity. You didn't have to have a PHD in parsing to deal with the AST for Smalltalk. Building your own AST walker was a mid level exercise. I once saw a comparison between the Ruby AST and the Smalltalk AST. The Ruby one was like 10 times more complex to deal with all of the edge cases. I added a goto implementation for a lark in an afternoon. I wouldn't even know where to start to add goto to Python. An absurd example of course, but it highlights that you didn't feel like Dan Ingalls and the other inventors of Smalltalk controlled your destiny. They wanted you to go places with it.
I think that SmallTalk's contribution to ObjC was nice. It was weird to encounter, at first, but I got used to it.
He has a point about the people charging for it. The same thing happened to XSLT.
XSLT 1.5 is the free version; supported by many languages and libraries.
XSLT 2.0, however, is where the action is at, and that is only supported by Saxon, a paid library.
I'm not sure if that has changed, as I haven't messed with that Pandora's Box in a number of years.
That was well underway when Java was released. And you could hear the air go out of the Smalltalk tires. Java was another OO language, it was designed for “applets” that would run in the browser, and it was created by Sun Microsystems, who built the most popular computers of the day. Nearly everyone who was interested in Smalltalk turned to Java and never looked back.
"...Interaction with the outside world."
This. So. Much. This.
I was a (junior) member of the team that made (part of) the prototype for the OS/2 Workplace shell, in (IIRC) Digitalk Smalltalk. Doing anything outside the Smalltalk image was incredibly painful.
Want to share your work with the team? File it out (and make sure you get all of it) and give the file to the Keeper of the Golden Image, who will file it in to the image. Then pass the image around.
Want to send the prototype to someone who didn't have a license for a (rather useless) support library from the trainers who taught the team Smalltalk? File our code out, file it into a virgin image, run through the test suite to make sure you had everything, reimplementing anything that used that library. Shouldn't take you more than a couple of days.
Did I mention this was a prototype of a GUI? Make those FFI calls using the really sketchy api. When I started, there was a bug that would randomly cause the prototype to crash. No one could ever figure out what caused it, beyond the FFI interface. At some point, it escaped the prototype and would cause the image to crash without running the prototype.
Sure, Strongtalk and Newspeak may have improved some or all of everything, but by that point the bridge had been burned. Their one opportunity had been wasted. I never saw or heard of either in the wild.
"The Smalltalk image provided a much better Docker than Docker."
And then there's that kind of thing.
I am worried that rubyists are gonna end up talking about what happened so ruby shrank for decades too. :(
Even in Reader Mode there’s spurious line breaks.