The Mystery of Moose

Someone here mentioned a thing called “Glamorous Toolkit”. I downloaded it and started playing with it, and quickly became baffled as to just what it was, what it was for, and what all the odd layers of… things… in it were for. It was obviously written in Pharo, which is some kind of modern Smalltalk, but… why all the other stuff? What is a Mondrian and why would I want one? Why are all the examples (in a Smalltalk project) about parsing Java source code? If it’s a Toolkit - and one assumes it’s not the same kind of toolkit as Gtk, ie, it’s not a set of GUI components - what makes it Glamorous? It appears to be partially a rewrite of the entire Pharo GUI, so it is some kind of GUI toolkit or has one, and it presumably has aspirations of being a Smalltalk or a replacement for one, but it’s also… so much other things. Java-flavoured things.

I eventually figured out (and not from reading the Glamorous Toolkit documentation) that GT is itself just one tiny sentence in a decades-long conversation called “Moose”. For those of us who haven’t been anywhere near the room full of people talking about “Moose”, GT probably isn’t the place to start. It’s certainly not the place for me to start.

I found out that Moose, whatever it is, is associated with one thing called “Feenk” (which is probably a startup?) and another thing called “The Moose Book”. Which appears to be documentation - the entire missing manual that wasn’t included with Glamorous Toolkit.

So I’m reading The Moose Book to try to get a sense of what, and more importantly why, Moose is, and why it’s so huge and sprawling and full of strangely named things about Java.

In the “Moose in a nutshell” chapter very near the start, I found what appears to be a mission statement.

http://themoosebook.org/book/index.html#h2mooseoverview

Moose is a generic platform for engineers that want to understand data in general, and software systems in particular. Foremost, Moose is designed for programmers, not for clickers. To get the most out of it, you have to program it. First, that means that you have to program in Pharo. Second, you have to learn the inner workings of Moose to understand how to use it.

This is actually less difficult than it sounds. Pharo is a beautiful language, and if you do not know it already, you will not be sorry for learning it. And Moose is rather small having less than 2000 classes and less than 150k lines of code.

Okay yes that’s a very nice explanation. I will try to learn Pharo and not be sorry. It is high time I learned me some kind of a Smalltalk. The language spent many decades being dead or mostly dead (eToys did its very best to make me hate Squeak) and now appears to be less dead. I’m very happy that Smalltalk’s not dead. BUT.

2000 classes and 150,000 lines of code is “small”?

Look, I grew up on 8k PETs. I’ve been looking recently at Uxn code, where files can be tens of bytes long. I’ve been playing with data files that yes might be several megabytes in size, but the Javascript I’m using to analyze them are on the order of 10 to 100 lines long. I’ve read that the Lisp 1.5 metacircular evaluator is about 30 lines of code (though I suspect that’s cheating). What draws me to Smalltalk in the first place is the minimalism: the Xerox Alto ran in 128K of RAM.

This artifact (is this a typical artifact for 2020s Smalltalk programmers?) definitely comes from a civilization somewhere in JCR Licklider’s Intergalactic Computer Network which does not define “small” on the same scale that I do!

Edit: Another quote, sorry. Just to show the Licklider mutual incomprehension of galactic species doing first contact problem:

Let’s look at an example. Suppose you want to look for all classes that are not being directly called by JUnit test.

model allModelClasses select: [:each | 
	each clientTypes noneSatisfy: #isJUnit4TestCase ]

Having a highly expressive API brings makes querying inexpensive

It does! Especially having lambdas is great for queries. But I’m pretty sure I could write that exact API in Javascript almost literally character-for-character with no loss of expressivity - and instant comprehension (of the grammar, at least) from millions of working programmers.

model.allModelClasses.select(each => each.clientTypes.noneSatisfy(“isJUnit4TestCase”))

I’m not saying I want to be using Javascript forever, I don’t, but it’s installed everywhere and everyone already knows it. I don’t yet see the argument for why the language has to be Smalltalk to do this kind of malleable data analysis. (As opposed to, say, Javascript running in a Computational Notebook kind of environment.) Perhaps I’ll find out as I go.

Edit2: Another example, to see how Smalltalk would translate to Javascript:

b := RTCircularTreeMapBuilder new.
b shape
  borderColor: Color lightGray;
  if: [ :d | 
    d files anySatisfy: [ :f |
      f basename = 'build.xml' ] ]   color: [ Color red ].
b leafWeight: [:f | f size sqrt ];
  explore: self
  nesting: #directories
  leaves: #directories.
b 

b = new RTCircularTreeMapBuilder;
b.shape.borderColor(Color.lightGray);
b.shape.if(d => d.files.anySatisfy(f => f.basename == ‘build.xml’)).color(Color.red);
b.leafWeight(f => f.size.sqrt())
b.explore(self);
b.nesting(“directories”);
b.leaves(“directories”);
return b

Ok there’s a few quirks, yes. Smalltalk can run zero-argument methods instead of doing object lookups (like sqrt) which is very nice, and semicolon maybe reduces repetition a little. I’m doing a bit of a hack to make a split keyword like if:color: translate to JS grammar. Atoms/symbols/keywords or whatever the hash things are called might be better than strings, but they’re still basically stringlike (and they aren’t as visually clean as Lisp symbols).

But I think we can do at least maybe 80% of Smalltalk in modern Javascript ES6 fluent syntax. I’m guessing the big wins come a little less from the syntax and more from just having a runtime object namespace that’s backed by disk storage and not having to constantly wrestle with a filesystem or database to get things done with your big models once you’ve imported them.

2 Likes

There is no concept though in Javascript of a “model” that contains all your source code.

After having spent some time with it (but not as much as @khinsen), I think of GToolkit as a Smalltalk with extensive facilities for creating debug inspectors.

Mondrian is image-aware version control.

You’re right about the scale disparity!

In a live programming environment, isn’t debugging the same as inspecting a live object?

I see it more as code isn’t just lines of text, but it has multiple views, one of it being the result of the execution itself.

Denotational design can also be easily implemented here.

1 Like

Mondrian is a DSL for defining graphs. A bit like graphviz, but embedded in Smalltalk.

Because it’s meant to be a code analysis tool that is not limited to analyzing Smalltalk code.

Well, names…

Right, that’s the core. A completely new GUI, based on a graphics stack that ensure unconstrained composability of graphics elements.

It’s just Pharo Smalltalk.

I have only vague notions of what Moose is, I have never used it, and probably never will. But I use GT every day, for very different things. What I care about most is the composable graphics toolkit and the extendable notebook. BTW, GT comes with rather extensive documentation inside (“Glamorous Toolkit Book”), which is also available online.

feenk is a Swiss software consultancy. They did Moose in the past, and now they develop GT. I guess they have been around for too long already to be a startup, but I am not an expert on startups.

Well, I agree. The people at feenk are not at all into minimalism. I suppose “small” is meant relative to typical business software packages or IDEs or whatever.

You should then probably look into Cuis, the minimalist branch of the Smalltalk-80 descendants.

Obviously it doesn’t have to. It’s just that the authors of Moose and related stuff knew and liked Smalltalk. And that the Smalltalk community has been pretty good at code analysis and refactoring tools for decades.

I can offer a gues on “why not JS”: you don’t get the live development experience that Smalltalk offers. And that is something addictive.

There are Smalltalkers who switched to JS for the benefit of ubiquity. A famous one is Ward Cunningham, inventor of the Wiki. People are different.

1 Like

Oh sorry, I confused Mondrian with Monticello.

As far as I understand, there isn’t such a concept of a model in Smalltalk either. The “model” at the heart of Moose (which does seem cool) into which source code can be parsed is just a bunch of ordinary Smalltalk objects which represent an entity-relationship diagram. We could parse source files and create Javascript objects to represent a model in just the same way. Probably many Javascript data-visualization projects do exactly this.

What Smalltalk has and Javascript (in most implementations) doesn’t have is an image that persists your Javascript objects seamlessly to disk, on your local machine. The Javascript culture (as opposed to the core JS language itself) really, really, really loves working with web servers to store code and Cloud databases to store data and really hates giving the local user any control over their code and data. Which is very sad, because we could have had a Pharo-like experience but with Javascript years ago, but… well, Google and Facebook just aren’t interested in funding anything that runs on a local computer.

Yep, it was reading though the GT documentation inside GT that made me aware it was full of Moose stuff that felt like it was from an entirely previous universe, but that the documentation didn’t want to talk about Moose at all. That’s why reading the Moose Book was a revelation to me: “oh, so THAT’S where this has come from, this is the source of all this extra complexity. There is a reason to it, or there once was.”

GT is certainly interesting to use and I can see potential in it, although I keep bouncing off the complexity of the source code because of the feeling - right or wrong - that I have to understand every part of it in order to be able to begin to use it.

GT with its Lepiter notebook is a very different UI experience from a conventional Smalltalk “browser” interface. I kind of like it! But there are some odd parts that seem like they were jury rigged from unrelated pieces lying around, and don’t yet feel cleanly integrated. Like Lepiter with its multiple text files and databases: isn’t Smalltalk strictly object-based and the objects all live in an image, so why is my notebook in text files that are stored outside the image? And why is there a database as well that’s not in the image and also not in the text files? Ok I like that I can (probably) extract the raw Markdown text in a my-Smalltalk-image-has-melted-down emergency, but should I be worried that that’s a disaster that happens often enough that it’s been planned for? How many different incompatible-format files do I have to juggle here to back up my notes?

For someone not used to Pharo at all, it’s often a struggle to work out what parts of GT are Smalltalk, what parts are specifically Pharo innovations on top of Smalltalk (eg pragmas) which won’t port to any other dialect, what parts are or were Moose (many of the visualizers, all of the parsers), what parts are specifically new to GT (Lepiter, I guess, plus the new UI widgets?) It’s like an archeological dig, and that’s before I even get started trying to use it.

I’m always nervous about putting my personal data, which I need to be available and to be able to port between systems, into a high complex system that I don’t understand. It feels like that’s maybe a one-way trip for my data.

If I write and maintain a notebook in GT, and I want to give it to someone else, how many hours to weeks of training are they going to need just to get up to speed with the interface and how it works?

Why is GT using Rust for its graphics library? That really baffles me. Smalltalk bills itself as a highly customizable system, yet Pharo (which already has a GUI) isn’t good enough to write a slightly customized GUI in? Aren’t the people writing Moose and GT literally also writing Pharo? If they need some super-low-level hardware capability for graphics which isn’t yet in Pharo, can’t they just add that into the Pharo kernel that they’re maintaining? Why add GUI components written in a completely separate compiled language onto a dynamic language? If you put the “programming philosophy” of Rust vs Smalltalk on a line, each would be at the opposite end. One’s C++ mashed up with Haskell, extremely strictly typed and compile-heavy, the other’s very late-binding dynamic. Surely that’s not going to end well at all?

I’m inspired by the feel of GT but I’m daunted by the size of it and the feeling that there’s no underlying organizing principle but a bunch of separate projects each with very different rules.

It’s just that the authors of Moose and related stuff knew and liked Smalltalk. And that the Smalltalk community has been pretty good at code analysis and refactoring tools for decades.

Ah! That last part makes a lot of sense to me. The “code analysis and refactoring” community would be exactly the part that is alien to me. It all sounds Extremely Enterprisey, and despite being a Windows and Linux sysadmin for decades, enterprise code refactoring is nothing I’ve ever been involved in. (I learned UML once and was very, very glad to never have to use it ever again.) I’m guessing IBM kind of created that situation by making VisualAge Smalltalk be so expensive and pitching it alongside UML, Rational Rose and other similar tools. The language and techniques all rubbed off on each other.

So Smalltalk, which started out as an experiment in education and being “something so simple a child could use it”, ended up getting pushed to almost the exact opposite (extreme enterprise complexity) because of the community where it found adoption. And that would explain why in that community 2000 classes is considered “small”.

The weird thing is I could draw a diamond diagram with “PARC and MIT AI Lab” at the top, “Macintosh and Zork” on the left, “Smalltalk enterprise code refactoring and the Design Patterns movement” at the right", and then at the bottom… “me, trying to find a good language for writing an adventure game in the 2000s and falling into the Portland Pattern Repository Wiki as a consequence”.

AI “modelling” branched hard two ways: one to 8-bit gaming and 16-bit GUIs, the other to massive enterprise models… and I’d like those two paths to converge again for personal malleable desktops.

For what it’s worth, seeing unnecessary path-dependent notations/“universes” in a system bothers me just as much as it does you, @natecull.

1 Like

For what it’s worth, seeing unnecessary path-dependent notations/“universes” in a system bothers me just as much as it does you, @natecull.

Yep! But when I understand what communities a particular notation came from, it starts to make a little more sense. I mean, it surprises me that there are still people out there for whom UML is a functional, useful communication tool that improves their lives! But I guess there are, and for them it’s useful.

(Which is a terrifying thought: there must be programming/design notations even worse than UML for it to have survived this long!)

The other thing that strikes me is, here’s Smalltalk having its happy second life from the 1990s on as a big systems analysis tool, all full of meta-meta-meta-modeling, esoteric stuff very similar to the “Artificial Intelligence” context that it was being pitched in back at PARC in the 1970s…

… but when I actually look at this very meta “AI”-ish code… what I find is the exact same code idioms as used in humble little Javascript to just paint widgets on a screen, looked down on and laughed at by everyone. It’s nothing special, just “Create a new object, imperatively and destructively run methods on it to set properties, pass it to another object”. Destructive, imperative, serial “do this then that” calls all the way. 1970s style coding.

What I’m saying is, we could be doing meta-meta-meta enterprisey systems analysis in Javascript on a web browser if we just had some way of loading and saving runtime objects. And to some extent we are, since we can run entire emulated DOS boxes in web pages.

Also, probably the features of Javascript that are most looked down on by “high computer science” types as being regrettable mistakes, are the exact same features that make Smalltalk work for the high software engineering meta-meta stuff. Mainly the very loose typing, and the runtime reflectivity.

Pharo does tend towards the “enterprisey” end of things as opposed to Cuis which tends towards the minimal.

Also, Alan Kay once lamented that programmers took Smalltalk and threw away the end user programmable stuff in favour of making it more professional programmer friendly.

I’ve actually been looking into Smalltalk 76 & 78 recently. It’s a neat little system though unfortunately only runs in a browser based VM atm.

2 Likes

Thanks (and to khinsen too) for pointing me to Cuis! I hadn’t heard of it before. I’ll give it a go and see if it’s easier to explore.

I also didn’t realise that Squeak, Pharo, Cuis and Newspeak all run on the same virtual machine! That seems like good news. https://opensmalltalk.org/

It all depends what you call “Smalltalk”. The language is very small, the class library is enormous, but varies widely between dialects. The idea of a model for source code is quite old and widespread in many Smalltalk implementations, because it is the basis for refactoring tools. In Pharo, there is a component called Ring that models code. Moose can be seen as “Ring on steroids”.

I doubt that any single person understands everything in GT. Nor even in standard Pharo, although maybe Stéphane Ducasse does.

My understanding is that this choice was motivated by future plans for collaborative editing. It is a constant source of friction though. I’d also prefer to keep my (small) notebook databases in the image.

There isn’t. The ‘database’ is a directory with JSON files.

There’s just one format, the JSON files I just mentioned. It’s pretty easy to parse and decode.

With today’s standard Smalltalk workflows, that never happens. Source code and notes are kept in Git repositories. Images are usually short-lived. I use mine for a few days at most.

There’s only GT on top of Pharo. All classes whose names start with Gt or Le are GT, everything else is Pharo or other packages that GT depends on (such as Moose). You can easily find the Git repositories from which each class has been loaded, so keeping things apart is possible, even easy, but rarely necessary.

Pharo is not called Smalltalk because it doesn’t want to be constrained by ANSI Smalltalk. In practice, it’s ANSI Smalltalk plus extensions.

Me too. All my personal data is stored in files, in formats that I can work with (which includes Lepiter JSON).

That’s a good question, which I cannot answer. I doubt anyone so has has learned GT just for the notebook feature.

  1. Speed. 2) Reuse.

The foundation is Skia, a Rust graphics library written by Mozilla for use in Firefox. But that’s only the low-level stuff. I have never looked at it. All GUI elements are written in Pharo, it’s the rendering code that uses Rust.

The Pharo base system already uses external C libraries. Skia is just one more, and Rust rather than C. You can draw a line around the VM and the C/Rust libraries and call that “the kernel”.

It’s not that bad, but Smalltalk culture does not encourage unifying principles beyond OO.

Me neither. But I have come to appreciate the Pharo refactoring tools. I wish I had the same for other languages.

Yes! Except for Cuis.

1 Like

That was my feeling as well in the not-so-distant past. Now I see this as an inevitable symptom of systems that have grown over a long time. And that means systems that have survived, so they can’t be all bad. Today I only examine if the different subsystems in a system I want/need to work with are manageable.

My daily-driver system includes: Unix (via Linux), Emacs, Common Lisp, Pharo/GT, and still a bit of Python. More than I’d like to have to deal with, but manageable.

1 Like

Now I see this as an inevitable symptom of systems that have grown over a long time.

I have some sympathy for this view, having been through a microcosm of it in my experience with LÖVE. Programs written for this game engine depend on handlers like:

  • love.draw
  • love.keypressed
  • love.mousepressed
  • …etc.

In just a year or so, I ended up creating several layers above these. For example, above love.draw:

  • App.draw
  • on.draw
  • car.draw

In my defense, I have a crisp reason why each such abstraction layer is needed:

  • love.draw: interacts with the game engine
  • App.draw: mocked in automated tests
  • on.draw: supports live editing.
  • car.draw: supports mobile editing.

Keeping the layers separate decouples concerns. Code in on.draw can be live edited, but not code in App.draw (which calls on.draw). Code in love.draw can’t be unit tested, except the part that’s in the call to App.draw. And so on.

So it seems fine to add layers – as long as you can explain them easily. (I have no idea how I’m doing by this score, but I try.)

My daily-driver system includes: Unix (via Linux), Emacs, Common Lisp, Pharo/GT, and still a bit of Python.

User code needs zero justification! That you add yourself so the consequences are very direct. But it would suck if using any Python required Common Lisp, etc.

4 Likes

As in: installing Python requires gcc, and installing gcc requires Python. That’s today’s reality!

3 Likes

It seems that Clang can be built without Python though. (Python is only used for its test suite)

Maybe. There are definitely C compilers that do not depend on Python, e.g. TinyCC, so the dependency cycle is just a matter of implementations.

I believe the Bootstrappable Project has a way to build most of Linux starting with a ~400 byte binary. Bootstrapping gcc from nothing is quite a lot of work it seems :sweat_smile:

1 Like

The most compact bootstrap binary I am aware of is 357 bytes:

And yes, that was a lot of work. But Guix uses this scheme to bootstrap a complete Linux distribution indeed.

1 Like

Yep, that’s the one. I couldn’t remember the exact size. :sweat_smile:

1 Like