Re: AI-generated contributions (was: Re: PragmasHelp.md)
gettimothy via Squeak-dev <[email protected]>
| Newsgroups | gmane.comp.lang.smalltalk.squeak.general |
|---|---|
| Message-ID | <[email protected]> |
Hi Eliot... thank you for the thoughtful reply. Much appreciated... Some thoughts... 1. "If you feel that learning about the system by yourself is cumbersome or ineffective, maybe ask yourself why it is. If the code is too hard to read, maybe propose a refactoring. If you don't have the right tools for the job, let's start a discussion about how a better tool should look and feel like." I am working on just that..REPL, ESP, E macs, ...I have a "putter-time" project where I am learning Emacs Lisp so that we can converse with the image via Emacs, its *ephemeral buffers*, and the underlying transport method...Currently in an .org file, I can execute code via a bit of (AI generated) Lisp.I expect that I can recreate the Graphical UI Idiom in Emacs.. Why? Because its fun and it may prove useful towards expanding the franchise. I am sure system administrators with a bunch of headless squeaks running, would appreciate the tooling. 1,a I am already thinking about making an X Desktop out of headless Squeak where the Desktop IS a Croquet Island...this is far down the road, but, with AI, now achievable. 1.b. I have the same feeling about Squeak that I did about Linux back in the 90's...it is something fundamentally important and the change in "ontology" required to use the language (much as SQL is its own way of thinking) is a must-have, but it takes time to "get it" ...the AST in Tweak, which a tree of objects is a beautiful bit of software is a case in point....the question becomes, "why aren't people using it?" and the answer, heard on this board over the years is "A lack of documentation" 2. Remember the open-source "Publish early, Publish often" mantra ? that is why I publish alpha/proof of concept projects...Perhaps a category on SqueakSource for pushing these thought experiments? Maybe a new tag "AI SLOP" checkbox. The GitBrowser help is published (it is generated from the hpi-swa github README.md and, while I struggled through using it once, I now have a baseline to extend the HelpTopic.... 3. I will be improving the Pragmas and GitBrowser help...but on my own time at my own pace. I am just abiding by the Publish Early , Publish Often mantra. 4. Way down the road is me trying to learn what an LLM is by creating one from the ground up by building one in Squeak Smalltalk where the "universe" of "training?" is the image itself...(my terminology is almost certainly wrong) and sqAI answers are immediately testable and debug-able in-image.. (related a Markhov chain in squeak? why not,,,Eugene Onegin is just sitting there...) 5. Finally, I am having fun. I work a mundane-day-job and coding is how I retain a semblance of an intellectual life. I respect this community and i do not want to cause friction or step on people's toes cordially, t From: Eliot Miranda <[email protected]> To: <[email protected]> Date: Wed, 27 May 2026 12:13:28 -0400 Subject: [squeak-dev] Re: AI-generated contributions (was: Re: PragmasHelp.md) Well said Christoph!! +100 _,,,^..^,,,_ (phone) On May 26, 2026, at 6:04 PM, Thiede, Christoph via Squeak-dev < mailto:[email protected] > wrote: Hi Timothy, all, > the LLM that shall not be named > There are glaring errors in every statement. > yes...AI is often idiotic... I think the resentment against LLMs is not just a dogmatic aversion of the community against hearing about new tools. Instead, as you can see, LLMs are quite likely to hallucinate at this point in time, especially about niche topics such as Squeak/Smalltalk. Would it be too much to ask to at least try out all AI-generated code snippets yourself before sharing them in public? One should only post such content if one can stand behind it and take responsibility for it under one's own name. To me it's highly understandable if people don't want to review AI slop contributions that do not meet this criterion. There's more important work to be done than fixing the errors of a stochastic parrot that will not learn from your corrections. That's a crucial difference from reviewing human contributions, which have the important side effect of training other people on the system and the intentions behind it, as well as bonding with other human beings in the community. As the cost of generating content is sinking, the need for reviewing content is rising. In other words, many AI slop contributions are not worth the bytes in which they are stored. If I want to have some system documentation that I cannot trust, it is easier for me to AI-generate it myself than to look up an existing repository (that suggests truthfulness but fails to deliver that). In my opinion, AI slop contributions are generally little helpful but rather often can feel like a veiled request to other people to do the actual work and do it right. More generally, I do have a problem with AI contributions for Squeak because it raises a fundamental question about why volunteers engage in the community. If we enjoy working with and exploring the system, then why should we delegate precisely that joy to a machine agent that cannot experience that joy? And if we do not enjoy working with the system, then why would we bother at all? I think these questions are especially relevant for a self-describing and modifiable system such as Squeak, which aims to be programmer-centric and fun in the first place. If you feel that learning about the system by yourself is cumbersome or ineffective, maybe ask yourself why it is. If the code is too hard to read, maybe propose a refactoring. If you don't have the right tools for the job, let's start a discussion about how a better tool should look and feel like. That would enable further Squeakers to explore and enjoy the system by themselves rather than diverting them to static, rotting AI artifacts. AI will soon or later replace humans in many professions embedded in economical structures and force them into less interesting tasks. You can already stream AI-generated music or watch AI-generated reels without any human touch more than you will ever need. Let's preserve for ourselves the interesting tasks at least in a setting like Squeak where we have the freedom to do so. Having - reliable - documentation about pragmas in Squeak could indeed be a valuable asset for future Squeakers. But instead of sharing largely unverified AI output with the community, I'd like to invite you to explore the system yourself in a Squeak image and ask two questions: what kind of information are you looking for (e.g., high-level architecture, implementation detaills, programming interfaces)? And how would you imagine this information could be easier to access from within the system itself (e.g., more explaining method names and method categories, better usage examples, more code references within comments)? Do we actually need a separate help document about pragmas, or could the implementation better speak for itself (e.g., by browsing the implementors and senders of interesting methods or playing with do-its in a workspace)? Happy to discuss your thoughts about a future of Squeak/Pragmas that empowers people to understand and extend the system, not locks them into external technologies to manage the chaos. :-) Best, Christoph Von: gettimothy via Squeak-dev < mailto:[email protected] > Gesendet: Montag, 25. Mai 2026 21:59 Uhr An: The general-purpose Squeak developers list < mailto:[email protected] > Cc: gettimothy < mailto:[email protected] > Betreff: [squeak-dev] Re: PragmasHelp.md Hi Eliot... thank you for the reply and thank you for reviewing! the goal is accurate PragmaHelp..and, yes...AI is often idiotic... The PragmasHelp.md is attached... Please edit in place this is important documentation for the Squeak community. cordially... From: Eliot Miranda < mailto:[email protected] > To: < mailto:[email protected] > Date: Mon, 25 May 2026 14:21:52 -0400 Subject: [squeak-dev] Re: PragmasHelp.md It’s half right. There are glaring errors in every statement. I shall review soon. But please, drop at least half the emphasis. You might inspect a method’s pragmas and see how they are represented. Show many inform the compiler (the primitive pragmas, the unwind protect pragmas, and the FFI pragmas) and how many do not (all the others). And since I invented the non-primitive use of pragmas you might talk to me rather than an idiotic AI… Eliot _,,,^..^,,,_ (phone) On May 25, 2026, at 9:30 AM, gettimothy via Squeak-dev < mailto:[email protected] > wrote: Hi folks... I am working with the LLM that shall not be named to develop PragmasHelpTopic...(currently a parser error in DOC import, I will be fixing it) Below is a draft of the PragmasHelp in Markdown format... If you are interested in this topic, have suggestions, rants, etc...please let me know. This was generated by having Claude-Code via gptel/mcp-hub interact directly with the DOC smallalk image where I have XtreamsParsing installed...the summary document was generated by Claude.ai... I find it fascinating and , if correct, you might find it useful for in-image HelpTopic or perhaps the XTreams package would like to include it. cordially, t # Squeak Pragmas — A Help Topic *Part of the DOC project help system. --- ## What Is a Pragma? A pragma is a **compiler annotation** embedded directly in a Smalltalk method using angle-bracket syntax. Pragmas appear at the very top of a method body, before any executable statements: ```smalltalk myMethod <primitive: 'primitiveAt' module: 'CollectionsPlugin'> <signals: #MyException> <preference: 'Show Balloons' category: 'Interface' default: true> ^ self doSomething ``` They are **not executable code**. The compiler reads them, creates `Pragma` objects, and attaches them to the resulting `CompiledMethod`. From that point on they are first-class objects you can query and dispatch on at runtime. The key insight: a pragma is metadata *about* a method — not something the method *does*, but something the method *is* or *belongs to*. --- ## How the Compiler Stores Them When the standard Squeak compiler encounters `< keyword: value ... >` at the start of a method body it produces `Pragma` instances and attaches them to the `CompiledMethod`: ```smalltalk "Read pragmas off any compiled method:" (MyClass >> #myMethod) pragmas "=> Array of Pragma objects" (MyClass >> #myMethod) pragmaAt: #primitive: "=> the pragma or nil" ``` This works uniformly for every pragma keyword — `<primitive:>`, `<preference:>`, `<action:>`, and any custom keyword you invent. The compiler treats them all the same way. Only the *consumer* of the pragma (the VM, a framework, a parser) gives them meaning. --- ## The Pragma Families — Use Cases ### 1. VM Dispatch — `<primitive:>` The oldest and most common pragma. Tells the VM to attempt a C-level primitive before running the Smalltalk method body. If the primitive fails (returns an error code), execution falls through to the Smalltalk fallback below. ```smalltalk at: index <primitive: 'primitiveAt' module: 'CollectionsPlugin'> ^ self basicAt: index ``` ```smalltalk "Also the numeric form — same semantics:" basicAt: index <primitive: 60> self primitiveFailed ``` There are two argument forms: | Form | Example | Notes | |------|---------|-------| | Named primitive | `<primitive: 'primName' module: 'Plugin'>` | Plugin-based, most portable | | Numbered primitive | `<primitive: 60>` | Historical; numbered slot in VM dispatch table | The VM intercepts these at method activation time — no Smalltalk code runs until the primitive returns a failure signal. **Where you find it:** Collections, Streams, Numbers, ByteArray, String — anywhere performance matters. 70+ occurrences in the Tweak C* class family alone. --- ### 2. Contract and Documentation Pragmas These pragmas annotate *what a method promises or warns about*. They are pure metadata — no runtime system acts on them automatically; they are there to be queried. #### `<signals: #ExceptionClass>` Declares the exception class a method may signal. Analogous to Java's `throws` clause. ```smalltalk openFile: aPath <signals: #FileDoesNotExist> ... ``` ```smalltalk "Find all methods in a class that may signal FileDoesNotExist:" FileSystem methodDict select: [:m | m pragmaAt: #signals: ] ``` #### `<bewareOf: 'description'>` A freeform warning to callers — documents surprising side effects, thread-safety concerns, or "this modifies global state" caveats. ```smalltalk resetAllConnections <bewareOf: 'Drops all open sockets. Do not call during active sessions.'> ... ``` --- ### 3. UI Wiring Pragmas (Tweak / Preferences) These pragmas wire methods into UI frameworks at load time. The framework scans the image for methods carrying these pragmas and uses them to build menus, preference panels, and so on — no explicit registration calls needed. #### `<preference: name category: cat default: val>` Registers a method as a user-editable preference. The Tweak Preferences panel discovers all such methods and builds its UI from them automatically. ```smalltalk showBalloonHelp <preference: 'Show Balloon Help' category: 'Interface' default: true> ^ showBalloonHelp ifNil: [true] ``` The pragma carries the display name, the category it belongs to, and the default value. The preference panel needs nothing else. #### `<menuPriority: n>` Controls where a method's entry appears in a dynamically-built menu. Lower numbers appear first. Without this pragma, items appear in selector order. ```smalltalk openInspector <menuPriority: 10> ... openDebugger <menuPriority: 20> ... ``` #### `<timeout: milliseconds>` Declares a time bound on an operation. Consumers (schedulers, watchdog threads) can scan for these and enforce the bound externally. ```smalltalk connectToServer <timeout: 5000> ... ``` --- ### 4. XTreams PEG Parser — `<action:>` and `<action:arguments:>` This is the pragma family most directly relevant to the DOC project. The XTreams PEG parser (by Levente Uzonyi) uses pragmas to bind grammar rule names to Smalltalk methods on a `PEGActor` subclass. The binding is built **once at initialization time** — not on every parse — making dispatch a simple Dictionary lookup. #### How `PEGActor` wires itself up — the real source `PEGActor` has exactly three instance-side methods. The key one is `initialize`, which scans the subclass's compiled methods for `<action:>` and `<action:arguments:>` pragmas and builds a `Dictionary` named `actions` mapping rule names to blocks: ```smalltalk PEGActor>>initialize initialize super initialize. actions := Dictionary new. "Two-argument form: <action: 'RuleName' arguments: #(1 2 ...)>" (Pragma allNamed: #action:arguments: in: self class) do: [ :pragma | | arguments | arguments := pragma arguments. actions at: arguments first put: ( self blockForSelector: pragma selector filterIndices: arguments second) ]. "One-argument form: <action: 'RuleName'>" (Pragma allNamed: #action: in: self class) do: [ :pragma | | selector | selector := pragma selector. actions at: pragma arguments first put: [:object | self perform: selector with: object ] ]. ``` At parse time, `process:object:start:stop:` does nothing but look up the rule name in that dictionary and call the block: ```smalltalk PEGActor>>process:object:start:stop: process: name object: object start: start stop: stop ^ ((actions at: name ifAbsent: nil) ifNil: [ ^object ]) value: object ``` If no action is registered for a rule, the raw match result (`object`) is returned unchanged. This is the entire runtime overhead — one Dictionary lookup per matched rule. #### The two pragma forms, from live image inspection **`<action: 'RuleName'>`** — single-argument form. The actor method receives the complete match result as one argument: ```smalltalk "In PEGMarkdownActor — actual methods from DOC image:" Paragraph: aCollection <action: 'Paragraph'> "aCollection is the raw match result for the Paragraph rule" ... ATXHeading: hashCollection text: aCollection <action: 'ATXHeading'> "With this form the full result collection is passed as one object" ... ``` **`<action: 'RuleName' arguments: #(indices)>`** — multi-argument form. The indices array selects *which elements* of the match result to extract and pass as separate arguments. Index 1 = first sub-match, index 2 = second, etc. Missing positions become `nil`: ```smalltalk HeadingSection: aHelpTopic body: bodyCollection subsections: subCollection <action: 'HeadingSection' arguments: #(1 2 3)> "sub-match 1 → aHelpTopic, sub-match 2 → bodyCollection, sub-match 3 → subCollection" ... ``` `blockForSelector:filterIndices:` handles up to 5 index positions with specialized fast paths (1-arg, 2-arg, … 5-arg blocks) before falling back to a general `perform:withArguments:` form. #### One method, many rules — multiple pragmas on a single method A single Smalltalk method can carry **multiple** `<action:>` pragmas. `PEGActor>>initialize` calls `Pragma allNamed:in:` which returns all of them, and each one gets its own entry in the `actions` Dictionary pointing to the same block. `PEGMarkdownActor` uses this to handle all six ATX heading levels with a single method rather than six separate callbacks: ```smalltalk ATXHeading: hashCollection text: aCollection <action: 'ATXHeading1'> <action: 'ATXHeading2'> <action: 'ATXHeading3'> <action: 'ATXHeading4'> <action: 'ATXHeading5'> <action: 'ATXHeading6'> "hashCollection size gives the heading level (1-6). The same method handles all six grammar rules." ... ``` The grammar defines separate rules `ATXHeading1` through `ATXHeading6` (each matching the right number of `#` characters), but the actor consolidates them into one place. This keeps the semantic code DRY while keeping the grammar rules precise. #### `PEGMarkdownActor` — complete instance-side method list (live image) >From `PEGMarkdownActor methodDict keys asSortedCollection`: | Method | Role | |--------|------| | `ATXHeading:text:` | `<action:arguments:>` callback — `# Heading` syntax | | `SetextHeading1:` | `<action:>` callback — underline `===` heading | | `SetextHeading2:` | `<action:>` callback — underline `---` heading | | `Paragraph:` | `<action:>` callback — plain paragraph | | `HeadingSection:body:subsections:` | `<action:arguments:>` callback — assembles HelpTopic tree | | `MD:` | `<action:>` callback — top-level rule, returns final collection | | `flattenInto:topic:` | Helper — flattens mixed content into a HelpTopic | | `initialize` | Overrides `PEGActor>>initialize` to set up caches | | `transcription` / `transcription:` | Debug flag — when true, fires trace output | | `*cache` accessors | `helptopiccache`, `paragraphcache`, `pagenamecache`, etc. | Class-side methods: `parser`, `process:`, `cleanMarkdownInline:`. #### The entry point — `PEGMarkdownActor class>>process:` ```smalltalk process: input ^ self parser parse: 'MD' stream: input actor: self new ``` `parser` builds a `PEGParser` from `Doc grammarMD` (10,841 characters of PEG grammar). `parse:stream:actor:` runs the `MD` top-level rule against the input stream, routing every successful rule match through the actor's `process:object:start:stop:` dispatch. #### Live parse result — `# Hello World\n\nA paragraph here.\n` ``` OrderedCollection( HelpTopic title: 'Hello World' key: 'hello-world' ← auto-generated slug priority: 1 ← heading level contents: 'A paragraph here.' subtopics: OrderedCollection() ) ``` With nested headings the tree deepens: H2 sections become subtopics of their H1 parent, H3 sections become subtopics of H2, and so on. The root `OrderedCollection` always contains only top-level H1 topics. ``` [H1] Hello World [H2] Section Two [H3] Subsection ``` #### The full parsing pipeline in DOC ``` Doc grammarMD (PEG grammar string — class-side on Doc) ↓ PEGMarkdownActor class>>parser ↓ PEGParser (compiles grammar, drives the match engine) ↓ PEGParser>>parse:stream:actor: ↓ PEGActor>>process:object:start:stop: (one Dictionary lookup per rule match) ↓ PEGMarkdownActor callbacks (action: pragmas wired at initialize time) ↓ HelpTopic tree (nested in-image Squeak help objects) ↓ SeasideDoc / HelpBrowser / .texi → .info ``` The same `<action:>` mechanism powers all DOC actor subclasses — the Org-mode actor, the Markdown actor, and eventually the Wikitext actor. Only the grammar string and the callback methods change; the dispatch machinery in `PEGActor` is shared. --- ### 5. Structural / Slot Pragmas Present in later Tweak packages (not yet loaded in the current DOC image). These operate at class-definition time rather than method time: | Pragma | Purpose | |--------|---------| | `<field: #name type: #Type>` | Declares a typed instance variable | | `<slot: ...>` | Slot declaration variant | Unlike the method-level pragmas above, these describe the *shape* of an object. They require special handling at class instantiation time, outside the normal method compilation pipeline. Design work deferred to Tweak-Costume / Tweak-Basic loading stages. --- ## Querying Pragmas at Runtime Because pragmas are first-class objects on `CompiledMethod`, you can search for them programmatically. This is how frameworks like the Preferences panel and the XTreams parser discover their callbacks without any explicit registration: ```smalltalk "All methods in a class that declare exception signals:" MyClass methodDict select: [:m | m pragmaAt: #signals: ] "Find all preference-bearing methods system-wide:" Smalltalk allClasses flatCollect: [:cls | cls methodDict select: [:m | m pragmaAt: #preference: ]] "Find all XTreams action callbacks on PEGMarkdownActor:" PEGMarkdownActor methodDict select: [:m | m pragmaAt: #action: ] "Find all primitive implementations, print class>>selector:" Smalltalk allClasses do: [:cls | cls methodDict do: [:m | (m pragmaAt: #primitive:module:) ifNotNil: [:p | Transcript show: cls name , '>>' , m selector; cr]]] "Inspect a pragma object directly:" | p | p := (PEGMarkdownActor >> #Paragraph:) pragmaAt: #action:. p keyword. "=> #action:" p arguments. "=> #('Paragraph')" ``` --- ## The Compiler Pipeline — Where Pragmas Live ``` Source text (method text as String) ↓ Compiler parser (Scanner → Parser → MethodNode) ↓ recognizes <keyword: ...> at method head Pragma objects (attached to MethodNode) ↓ Encoder (EncoderForSistaV1) ↓ CompiledMethod (Pragma objects stored in literals array) ↓ Runtime query: (CompiledMethod >> pragmas) (CompiledMethod >> pragmaAt: keyword) ``` The pragma is stored in the literals array of the compiled method, alongside the actual literal constants the method uses. This is why `pragmas` is fast — it is a direct array lookup, not a parse of source text. --- ## Writing Your Own Pragma-Driven Framework The pattern is always the same: 1. Choose a keyword (e.g. `<myFramework: 'name'>`). 2. Define a method on `CompiledMethod` or use `pragmaAt:` to query for it. 3. At startup or load time, scan the classes you care about and collect all methods carrying your pragma. 4. Build your data structure (menu, registry, dispatch table) from the results. ```smalltalk "Skeleton of a pragma-driven registry:" MyRegistry class >> initialize registry := Dictionary new. Smalltalk allClasses do: [:cls | cls methodDict do: [:m | (m pragmaAt: #myFramework:) ifNotNil: [:p | registry at: (p argumentAt: 1) put: m]]] ``` This is exactly how `<preference:>`, `<menuPriority:>`, and `<action:>` all work. --- ## Further Reading - `Pragma` class — browse its class comment in the image - `CompiledMethod >> pragmas`, `CompiledMethod >> pragmaAt:` - `PEGActor` and `PEGMarkdownActor` — live examples in the DOC image (package `Doc-Xtreams-Parsing`) - Squeak mailing list: Eliot Miranda on CCompiler as Facade (May 2026) - *TimmyAndClaudeLearnSqueak* — chapters SqueakCompilerPipeline and TweakCompilerAndFunctionality - XTreams Parsing wiki: https://code.google.com/archive/p/xtreams/wikis/Parsing.wiki --- *First draft — DOC project, May 2026.* *Source: Squeak_Pragmas_Summary.md + live image analysis.* Squeak-dev mailing list -- mailto:[email protected] To unsubscribe send an email to mailto:[email protected] Squeak-dev mailing list -- mailto:[email protected] To unsubscribe send an email to mailto:[email protected] Squeak-dev mailing list -- mailto:[email protected] To unsubscribe send an email to mailto:[email protected] Squeak-dev mailing list -- mailto:[email protected] To unsubscribe send an email to mailto:[email protected] Squeak-dev mailing list -- [email protected] To unsubscribe send an email to [email protected]