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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.