51 comments

[ 1.1 ms ] story [ 98.7 ms ] thread
One of the things to appreciate with Pharo Smalltalk is a code snippet isn't a code snippet.

Pharo is not a filesystem/.txt coding environment.

It's a VM runtime with every single element is indexed by the class/traits hierarchy. And then the same code draws the GUI.

OP didn't just write a code snippet.

They wrote a method, tested it in an already launched dynamic runtime.

And deployed it into a desktop app in front of you.

Forget Jenkins, Docker-Compose or Make, their deploy tool was copy/paste.

It's truly a pity that desktop based applications are not popular in the current age, and phones are locked down.

Smalltalk remains truly unparalleled at producing local apps. 30 years after its heyday, SwiftUI is still a shadow of what Smalltalk can do.

From 2016 to 2018 I worked on a complex case management application that was implemented in Smalltalk. It ran on Visual Smalltalk Enterprise (last updated in 1999! But the app was first put into production in 1996...) which is really quite crufty compared to Pharo, but the development experience still blew me away. The Smalltalk way of working takes some getting used to, but once I got into the swing of it, it was the the smoothest development process I've had: you log into the app and do your stuff. Poke some bugs, try to reproduce them, maybe find some completely unrelated error, and whenever you update the code you just save the methods and pick right back up from where you left off.
It's gonna be part of a benchmark for how long until "engineers" realize they're stupid.
Engineers are still just humans which means they're susceptible to marketing same as any other human. Much of the evolution of popular programming languages is just marketing, most obviously in the case of Javascript.
Partly true, partly not true. It's somehow sad to see educated people falling for these tricks. But actually my issue is not about people being diverted by market dynamics.. i can empathize with that. It's the non recognition, non interest when presented with these artefacts. No curiosity, no reading grid to analyze systems or ideas.. shallow reflex criticism .. super odd to me.
Keep in mind that there are some very good reasons the Smalltalk ecosystem wasn't adopted.

#1 it's a burden of knowledge to shift from the Unix filesystem to the Smalltalk runtime. There... are no files.

#2, quite honestly Pharo Smalltalk has only gotten good in the last 3-4 years. And even then, it has 1-2 really noticeable bugs and what I'd argue are extremely subpar default keybindings, due to it being such a small community.

For 30+ years, the only really decent run-times were paid ones you bought for $1k per developer in 1980s dollars. No FOSS.

IMO the programming language ecosystem we have today was heavily cemented in the 2005-2010 period. These days the JVM/Python/Javascript/C ecosystems are huge juggernauts.

They're not about the programming languages themselves. They're about the massive integration with their underlying compilers, and massive library of tools available.

#3, it's a dynamic language for obvious reasons. It's hugely beneficial for applications development, but it's still a slow dynamic language for backend work.

And #4. The elephant in the room:

End users are divided between Windows, MacOS/BSD, and locked down phone platforms, nobody makes native applications.

Everything is a webapp, because an HTML page is truly cross platform.

I don't think engineers are wrong to congregate towards webapps. SwiftUI is still extremely amazing after all, but it only produces native MacOS apps. Which is rubbish.

But it's important to know your tools, deeply, and understand the context behind the application development industry.

Mostly agree with these points, but I don't think I understand this one:

> End users are divided between Windows, MacOS/BSD, and locked down phone platforms, nobody makes native applications.

This is probably gonna end up being a dumb question, but isn't this point a pro for Smalltalk (or at least Pharo - I forget how far upstream the VM comes from) because each application runs in a VM, which should be platform-agnostic?

Smalltalk doesn't run on iPhone for one thing.

Also, there is still a nonzero amount of asset porting.

Even if the code is portable, making the buttons for MacOS involves changing the art and everything. Apple only allows rounded corners etc. Plus supporting a new keyboard etc.

Essentially nobody gave a damn and just went for websites.

Smalltalk (Squeak and Pharo, perhaps Cuis as well) does run on the iPhone. At least at some time in the past there were a few apps in the Apple store which had been written in Squeak. The restriction was that it had to be impossible to break out of the app into the underlying Smalltalk. And the raw Smalltalk itself was not allowed in the store, but if you were a registered developer you could get it and load it into a small number of iPhones/iPads.
> There... are no files.

My guess is you mean something like — usually, Smalltalk software is written in a Smalltalk IDE (editor, code browser, incremental compiler, debugger, cache), instead of being written by editing plain text files with a text editor?

Of course, if you really wanted, you could edit a plain text file with a text editor, compile and run. I wrote fact.st with GNU nano.

    $ cat fact.st
    Stdio stdout 
        nextPutAll: 100 factorial printString; 
        nextPut: Character lf.!
    SmalltalkImage current snapshot: false andQuit: true!

    $ bin/pharo --headless Pharo10-SNAPSHOT-64bit-502addc.image fact.st
    93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
First time I saw the find by example feature I thought "maybe it tries all applicable methods" but then immediately dismissed the idea because it could execute methods with side-effects. Does Pharo somehow knows about safe/unsafe methods ?
I don't think it really does. If I remember correctly, there's a bit of white/blacklisting going on under there.
Smalltalk code is full of these kinds of unprincipled solutions which work better than they should.

You can get away with a lot of saying "just trust me" when everything is exposed for immediate exploration of whether invariants are in fact preserved.

I also noticed that the reimplementation uses `receiver deepCopy` for each message send to preserve the original object, so that side effects would not affect the receiver.
The original method finder in squeak has a blacklist of methods not to try, but otherwise works just as you imagine. There's some very cool recent work on isolating effects at a low level that should obviate such grody hacks! Then the system really can freely and safely try all applicable methods. See thread up and down from here https://twitter.com/leastfixedpoint/status/15123917563183923...
Pharo recruitment plug: yesplan.be (Belgium) is hiring European Pharo software engineers. If you have little Pharo knowledge that’s fine too, in my (personal) experience, as I am now working with it for 3 months.

More on topic: there are many ways in which Pharo can find things that is not possible (or applicable) in other languages.

For example, there are 4 mouse clicks you can make in your image:

- left click

- right click: it shows a context menu

And then there are two clicks that I would need my laptop for to (re)figure out. One shows a “halo” around a window. The “halo” gives all kinds of options. The other one shows a context menu that allows you to figure out what objects are running with regards to the pixel you clicked on!

Because of the last click, it’s easy-ish to extend your IDE.

The last two clicks are some combination of CMD + Option + CTRL + click

What is your pay for someone who could write this ten years ago in Amber Smalltalk but had since worked with Python and typescript?

https://m.youtube.com/watch?v=uUOlzr4XdcY

Asking for a friend…

Feel free to email me to have a more in-depth conversation. My email is in my profile.
Interesting, from: https://yesplan.be/en/vacancy/full-stack-software-engineer

> Our backend uses Pharo Smalltalk, Seaside and GemStone/S

How is your experience with GemStone/S?

For people that don’t know, GemStone is a smalltalk descendant that has an object-oriented database behind it.

I don’t know much about GemStone specifics yet, I am about to though.

My skillset before this was mostly in React and Node.

I used Gemstone/J for a number of years. This is the version of Gemstone DB for Java applications, same capabilities as the Smalltalk version. If you are familiar with Object Databases you will find it very easy and capable.

Before using Gemstone/J with a Java application, I worked in Smalltalk for a number of years building an application backed by a different object database product, so I was already familiar with the advantages and pitfalls of using an OO DB. If you are familiar with using an OO DB, Gemstone is an easy transition.

would you consider part time, remote?
I do remote-ish [1] for 4 days per week. I doubt they will do less days or more remote.

[1] I am at the office about every 6 weeks for 2 to 3 days.

We have been working for years now on a smalltalk like IDE and a language (which is as language not like smalltalk at all, but as runtime it is). When we went down the rabbithole of prior work (like smalltalk, lisp, etc), it is painful to notice how far we actually have come but how little we actually use / have available to us in mainstream dev. We hope to show how it should be later this year!
It's kind of depressing, honestly. Smalltalk is amazing future technology from the 1980s, and here we are in 2022 with our fancy IDEs still dropping off our (metaphorical) punch cards for batch processing.
Yep... Fairly bizar that a smalltalk env on an old computer is faster for iteration than the modern react/typescript stack. Better errors, easier to debug etc. All because the tooling was from the future. React peeps think hot reload is something special. It was normal and it was faster and more robust than it is now.
I think there's an inherent conflict between languages creating programs like clay to be molded by the developer and the user, interactively (repl, smalltalk), vs. languages creating programs with optimal machine code with no extraneous computations, and/or maximal low-level control (sometimes even at the cost of making it harder to alter code, like manual data structures or hand-rolled assembly or vectorization). I wouldn't call Smalltalk technology from the future, but rather optimizing for a different ideal (though I've never used Smalltalk to experience the magic firsthand (and/or smoke and mirrors, ctrl+f "white/blacklisting")). Smalltalk (like Java) is bound to a GC, and GC wreaks havoc with using finalizers for manual memory management cleanup, since finalizers can be called while a variable is still in scope unless you use GC.KeepAlive() or friends.

On the other hand, optimized C++ is notoriously hard to debug, and debug C++ is slow (especially when using "zero overhead" abstractions that are only zero-overhead in release builds). There's cool work at reversible debugging, binary-patching, etc. (low-overhead tracepoints, Linux kernel Kprobes which failed to hook some functions I think were actually called, CONFIG_DYNAMIC_FTRACE, most recently https://justine.lol/ftrace/, though both CONFIG_DYNAMIC_FTRACE and ftrace depend on injecting nops into code which can later be replaced by tracing code).

JavaScript excels at neither performance nor dynamism, though I think it's still a lot more dynamic than C++ (userscripts can tamper with page contents and scripting) and faster than Python (through herculean effort of the V8 developers funded by Google ad revenue to make web apps and advertising faster). And C++/assembly, by its nature of allowing complete control over the machine, is difficult to sandbox beyond running code in an isolated process or VM (or compiling to WASM then to x86?), as opposed to JS/WASM being (theoretically) memory-safe and sandboxable by taking away APIs interfacing to the outside world.

We are trying to do something novel on this intersection you speak of. I hope we figure it out far enough. But yes, you are right in sketching the current situation; I firmly believe we could’ve been a lot further than we are and I intend to prove it.
While this is a deep topic regarding the philosophical break between the two paradigms and one which I spend a lot of time on, the ideal to me seems to be a system which has the immersive nature of a smalltalk-like environment while having the finalized image run at near “chip speeds”. JIT was added to smalltalk to solve this problem and so I wonder if it’s more about balancing the two modes.
There is also just the simple issue of how many people are working on these systems. Right now there is an Opensmalltalk VM change in the words -- SISTA -- that has the potential for a 3x speedup of those systems. But it's largely the work of one or two people and it's unfunded. They are working on it in their limited free time.

Additionally, there is a specific kind of dominant "computing culture" that we live in. Show a new language to mainstream developers and they will want to know how to do a "hello world" and which text editor / command line program to run in order to use it, as if these are the only ways to interact with a machine in any meaningful way. Anything outside of this seems like it's "not real programming".

> the philosophical break between the two paradigms and one which I spend a lot of time on [...] I wonder if it’s more about balancing the two modes.

I don't see the break? "Clay" tooling exists for "industrial" code, but as secret sauce, and jig kludgery, and various other "making this more broadly available is not in/of our interest". "Clay"'s rejection of "industrial" has seemed more resource-starved exploit-not-explore group-think. Smalltalk/forth/etc audacious-scope rewrite-the-world efforts have seemed more "remake the world" than "to force us to remake ourselves". Try imaging a forth implementation effort that said "ok, we have bootstrap... so now the next obvious steps are supporting PICs and multiple dispatch and template jit, WAM and BEAM vms, linking Z3 solver, DHM type inference, ...". So perhaps rather than an inherent break between modes, and balancing to be done, there's a lack of available power, and of interests/resources aligned with ramping it.

But then, I'd like a programming environment which provides an powerful environment for making engineering tradeoffs, rather than ones which hardwire in very dramatic ones. I expect such an environment, when it finally exists, won't be hard to recognize. As, for example, basic reimplementation of existing modern languages, with their big test suites, libraries, community repos, specs sometimes transliteratable directly into code, code-as-documentation and highly-investment-in optimization, is a natural forcing-factor exercise for such an environment. So when you see a small team spewing new language implementations... maybe we've at long last hit phase transition. And if one can't easily manage that, in bulk, even with all that leverage... then it's not a very powerful environment, is it?

I think that saying it's an inherent conflict is overstating it. I think it's a bit more like there are these two axes, a performance axis and a malleability axis, and they aren't completely orthogonal, but they also aren't diametrically opposed.

Granted, if you ignore one axis and optimize the heck out of the other one, you're unlikely to end up in an optimal region of the ignored axis. But there are optimization paths that move in good directions on both axes at once, until you reach some limit where you sort of move around on some boundary arc by trading off one against the other.

Apple's Dylan project was conceived with the explicit purpose of developing a language and runtime that would satisfy the highly-interactive-programming enthusiasts (that is, the Smalltalkers and Lispers) in Apple's ATG and other researchy groups, while also producing built artifacts that were fast and interop-friendly and compact enough that they wouldn't all have to be rewritten from scratch in C, Pascal, or assembly before the product groups would agree to ship them.

The Dylan team did a pretty good job. I was one of their internal customers, working on an experimental handheld OS written mostly in Dylan.

The Dylan team gave us a modified version of Macintosh Common Lisp, called Leibniz, with Dylan support. Leibniz was just MCL, but with a Dylan compiler, object system, and runtime built into it. The Dylan compiler cross-compiled to the handheld's hardware. Our dev machines were Macs, either with daughterboards stuck into nubus slots, or with actual handheld hardware ribbon-cabled to the nubus.

Leibniz had a second version of everything in the MCL environment: there were the normal Lisp listener windows, but also Dylan listener windows. There were normal Lisp editor windows and Dylan editor windows. And so on.

Code compiled and evaluated in the Lisp windows ran on the Mac hardware. Code compiled and evaluated in the Dylan windows ran on the handheld hardware.

Our built software ran on the same handheld hardware as the C++ OS. It performed well--well enough to make some of the C++ team curious sometimes about how we did certain things.

The relevant point is that you can make a highly-interactive and malleable language and development environment that also delivers fast, compact artifacts. I don't think there's an irresolvable tension between those two goals.

On the other hand, optimizing toward both goals is more work than optimizing one at the expense of the other. If you elevate one goal above the other, the elevated goal will benefit and the other will suffer. Optimizing both means paying attention to both all the time, and that sometimes means that you will disqualify certain options. Optimizing both shrinks the workable solution space, so you have to look harder and sometimes solve problems in less easy ways than you would if you were thinking only about the one goal.

On top of that, the features that make an environment a great, malleable, highly-interactive environment are extra. You still have to do all the same kind of work that you need if you don't care about making a highly-interactive environment--lexers, parsers, compilers, optimizers, linkers, editors, indexers, and so on, and so forth--but on top of that, you have to design and build all of the features that make an environment highly interactive--a repl that has visibility into everything in the runtime as it runs, error handling that can spin up an interactive session in the dynamic context of a signaled error, runtime facilities that detect and keep track of every dependency that changes dynamically and knows what to do about it, inspectors that know how to expose and edit every element of state in the whole system, and so on.

That's really the obstacle, I think: a really malleable environment is just a lot more work. That, and to build one you need builders who know what they are and how to build them.

See also, recently posted 2013 article on GNU openstep/étoile project and unification of C, objective-c and smalltalk runtimes:

"Smalltalk in a C world (2013)" https://news.ycombinator.com/item?id=31462735

Not entirely sure about the status of the project, but there appear to have been a few updates in github more recently than the news section of the website.

https://github.com/etoile/

The problem is that developers have been brainwashed to dislike what Smalltalk has to offer. If you tell them to use a Smalltalk-like system they will complain to no end about the lack of file-centric infrastructure, while what Smalltalk has to offer is decades ahead of what they can do with other systems.
Any recommendations on where to get started to understand the idea behind it, where it’s used and how to approach typical problems?
In a much less interactive manner, the Unison language seems like it revolves around some stuff found in Smalltalk
market dynamics wiped lisp in the 80s, then smalltalk in the 90s

such is life, it's gonna popup again in php10 or typescript5 for sure

How is version control usually handled in these kinds of systems?
<= Pharo 8: Monticello

>= Pharo 9: Git (through something called Iceberg)

When I did Smalltalk in a corporate team environment we used a tool called Team/V. Code is stored in a shared repository. Everyone starts with the same clean image, loaded with the tools and options chosen for the project.

From your clean running image, you open the Repository Browser window. You load app code from the repository, make changes etc., and commit back to the shared repository.

There were many options for organizing “packages” and creating lists of packages and version numbers for a “build”. Also different options for ownership of code, locking code from changes, difference reports, etc.

Open source tools I have not used.

The problem is, what's the single best use case for Smalltalk?

Web apps are too dominant, and the fact is much of backend engineering is mildly unsuitable for a dynamic language runtime due to raw performance.

I think that's the issue. No golden use case like Ruby on Rails.

If Apple supported Smalltalk for native iOS apps things would be fine. But pigs would fly first.

> We have been working for years now on a smalltalk like IDE and a language

I’d be curious to know more about this!

Does anyone know how to go to a specific implementation of a message for an object?

For example can I take "#(1 2 3) min." and go directly to the definition of min? It seems I can only look at _all_ implementations, not just the implementation for that object

Use the debugger to step through, and you will see the implementation that is about to be executed?

The debugger code itself could give clues on how to do it.

Because it starts out in English and does not say so right away, I think it is a good idea to point out that the article is a google-translate, and seeing it in English I get a different idea in places than when reading the Portuguese.

For example, I had never before considered how this feature could help people navigate a foreign language so literally.