• Hello MLAers! We've re-enabled auto-approval for accounts. If you are still waiting on account approval, please check this thread for more information.

Using a AI service to assist with classic mac programming

John_A

6502
Don´t know if this have been up for discussion. Would be interesting to load the whole Inside Macintosh series of books into something like Googles NotebookLM (or if there is something better around). Then ask questions to find the best solutions on various programming related topics. Anyone tried something similar?
 
Using AI for programming non-mainstream platforms will probably be no help at all, maybe even discourage you…
 
If you have the book in PDF you can create a project in Claude.ai and upload the book. If the PDF is too large to fit in context, Claude will RAG search the book for answers.

I use this for other things and it works very well.
 
Last edited:
If you have the book in PDF you can create a project in Claude.ai and upload the book. If the PDF is too large to fit in context, Claude will RAG search the book for answers.

I use this for other things and it works very well.

I use this for other things and it works well.
dont suppose you're using it for posting?
 
OP didn't even mention writing code with AI. Just using an AI tool to lookup reference info.
Exactly this.
The revised IM collection consists of 33 large volumes. Mac Garden had them on a CD image at one point, might still be there. But using a AI "librarian" to do the heavy lifting seems better.
 
I've tried a few prompts in the past using ChatGPT and it was providing detailed information from various Inside Macintosh volumes as well as Apple technical notes without any sourcing of content from me.

For example, I had asked a question about how to add custom vars to a parameter block during asynchronous calls, and ChatGPT was able to point out a custom parameter block structure hack that was similar to what some of our forum members (like @cheesestraws) had suggested to me, with code samples (it was a little wrong but close enough to give the reader an idea) and links to technical notes and Inside Macintosh volumes. Usually the links reference the newer editions rather than the original I-VI volumes.

Did you try? Or was it not enough for you?
 
I can echo what jmacz just said and confirm that, to my surprise, ChatGPT was able to correctly answer a lot of my classic Mac programming questions. Part of the key was turning on web search, which apparently allowed it to find and source pdfs of Inside Macintosh. There were a few questions it got wrong, and it did hallucinate a function a few times, but for the most part it's been surprisingly accurate. And it did far better than when I tried a few years ago asking it questions about HyperCard and XCMD programming (for which it just made up complete nonsense every time).

I've found that, with these LLMs, the trick seems to be to treat them like a search engine with a natural language interface. That way I find them very useful, and in fact more useful than actual search engines which by and large seem to suck now compared to 10 years ago. So rather than asking them to write code for me, I'll treat them as a handle way of asking API related questions. Sometimes it can provide useful example code too, much like you might get out of a stackoverflow question. And, of course, the key here is to treat it with the same skepticism.
 
For those of you not wanting to actually test and validate a chatbot to see the results, I've done it for you with @jmacz's example using Copilot so you can come to your own conclusions:

Me: compliant with "Inside Macintosh", how would you add custom vars to a parameter block during asynchronous calls?

Copilot Response
To add custom variables to a parameter block during asynchronous calls in a way that is compliant with Inside Macintosh, you'd typically use the ioRefNum or ioCompletion fields in the parameter block to store or reference your custom data. Here's how this was commonly done in classic Mac OS programming:

🧠 Background: Parameter Blocks and Asynchronous Calls

In the classic Mac OS, many system calls (especially I/O-related ones) used parameter blocks (like ParamBlockRec, IOParam, DrvQEl, etc.) to pass information. For asynchronous calls, the system would call back via the ioCompletion function pointer when the operation completed.

✅ Compliant Way to Add Custom Vars

To safely add custom data:

1. Use a Custom Completion Routine

You can define your own ioCompletion routine that wraps the original one and includes a pointer to your custom data.

2. Embed Custom Data in a Wrapper Structure

Create a structure that includes the parameter block and your custom variables:
typedef struct {
ParamBlockRec pb;
void *myCustomData;
IOCompletionUPP originalCompletion;
} MyPBWrapper;

3. Set ioCompletion to Your Wrapper Function

In your wrapper function, you can access the custom data, then call the original completion routine if needed.
void MyCompletionRoutine(ParmBlkPtr pb) {
MyPBWrapper *wrapper = (MyPBWrapper *)pb;

// Access your custom data
void *data = wrapper->myCustomData;

// Do something with the data...

// Call the original completion routine if it exists
if (wrapper->originalCompletion) {
wrapper->originalCompletion((ParmBlkPtr)&wrapper->pb);
}

// Free the wrapper if dynamically allocated
DisposePtr((Ptr)wrapper);
}

4. Initiate the Async Call

When making the async call:
MyPBWrapper *wrapper = (MyPBWrapper *)NewPtrClear(sizeof(MyPBWrapper));
wrapper->myCustomData = ...; // your custom data
wrapper->originalCompletion = myOriginalCompletion;
wrapper->pb.ioCompletion = NewIOCompletionUPP(MyCompletionRoutine);

// Set up other fields in wrapper->pb...

PBReadAsync((ParmBlkPtr)&wrapper->pb);


🛑 Important Notes​

  • Always ensure memory is properly managed—especially if allocating wrappers dynamically.
  • This approach is compliant with Inside Macintosh because it respects the structure and behavior of the parameter block and ioCompletion mechanism.
  • Avoid modifying undocumented or reserved fields in the parameter block.

Would you like a concrete example using PBReadAsync or PBControlAsync?



Note that it'll be just as confident no matter whether it is correct or not. Usually it's correct, but if it gets something wrong, you'll have to either catch it yourself, or challenge the bot on it a few times. If it doesn't get something usable after 3 tries, best not to keep trying and just ask it a different question, like which page you should look up the information on.
 
I have created a workspace in NotebookLM and uploaded all 33 IM reference books in pdf format as the only source. Doesnt seem that its possile to share a link.
Any ideas on a question? I will upload the unfiltered answer here.

(Edit: wrote this while adestopon asked the copilot.)
 
For those of you not wanting to actually test and validate a chatbot to see the results, I've done it for you with @jmacz's example using Copilot so you can come to your own conclusions:

Me: compliant with "Inside Macintosh", how would you add custom vars to a parameter block during asynchronous calls?

Copilot Response
To add custom variables to a parameter block during asynchronous calls in a way that is compliant with Inside Macintosh, you'd typically use the ioRefNum or ioCompletion fields in the parameter block to store or reference your custom data. Here's how this was commonly done in classic Mac OS programming:

🧠 Background: Parameter Blocks and Asynchronous Calls

In the classic Mac OS, many system calls (especially I/O-related ones) used parameter blocks (like ParamBlockRec, IOParam, DrvQEl, etc.) to pass information. For asynchronous calls, the system would call back via the ioCompletion function pointer when the operation completed.

✅ Compliant Way to Add Custom Vars

To safely add custom data:

1. Use a Custom Completion Routine

You can define your own ioCompletion routine that wraps the original one and includes a pointer to your custom data.

2. Embed Custom Data in a Wrapper Structure

Create a structure that includes the parameter block and your custom variables:
typedef struct {
ParamBlockRec pb;
void *myCustomData;
IOCompletionUPP originalCompletion;
} MyPBWrapper;

3. Set ioCompletion to Your Wrapper Function

In your wrapper function, you can access the custom data, then call the original completion routine if needed.
void MyCompletionRoutine(ParmBlkPtr pb) {
MyPBWrapper *wrapper = (MyPBWrapper *)pb;

// Access your custom data
void *data = wrapper->myCustomData;

// Do something with the data...

// Call the original completion routine if it exists
if (wrapper->originalCompletion) {
wrapper->originalCompletion((ParmBlkPtr)&wrapper->pb);
}

// Free the wrapper if dynamically allocated
DisposePtr((Ptr)wrapper);
}

4. Initiate the Async Call

When making the async call:
MyPBWrapper *wrapper = (MyPBWrapper *)NewPtrClear(sizeof(MyPBWrapper));
wrapper->myCustomData = ...; // your custom data
wrapper->originalCompletion = myOriginalCompletion;
wrapper->pb.ioCompletion = NewIOCompletionUPP(MyCompletionRoutine);

// Set up other fields in wrapper->pb...

PBReadAsync((ParmBlkPtr)&wrapper->pb);


🛑 Important Notes​

  • Always ensure memory is properly managed—especially if allocating wrappers dynamically.
  • This approach is compliant with Inside Macintosh because it respects the structure and behavior of the parameter block and ioCompletion mechanism.
  • Avoid modifying undocumented or reserved fields in the parameter block.

Would you like a concrete example using PBReadAsync or PBControlAsync?



Note that it'll be just as confident no matter whether it is correct or not. Usually it's correct, but if it gets something wrong, you'll have to either catch it yourself, or challenge the bot on it a few times. If it doesn't get something usable after 3 tries, best not to keep trying and just ask it a different question, like which page you should look up the information on.
Often but not always, Claude does a better job of qualifying things and being clear about it's lack of confidence in the answer. To be clear I've also had Claude give me plenty of confidently wrong answers, but this is a good example of it telling me it doesn't know.

Here is what I get when I give Claude the exact same prompt:

<Prompt>: compliant with "Inside Macintosh", how would you add custom vars to a parameter block during asynchronous calls? <Claude> I need to search for specific information about "Inside Macintosh" parameter blocks and asynchronous calls, as this relates to classic Mac OS programming practices that I want to ensure I get exactly right. Inside Macintosh parameter block asynchronous calls custom variables 10 results Let me search more specifically for classic Mac OS programming and parameter blocks: "Inside Macintosh" parameter block asynchronous completion routine 3 results Let me try to find more specific information about classic Mac OS parameter blocks and custom variables: classic Mac OS parameter block completion routine custom fields asynchronous 10 results I need to search more specifically for classic Mac OS Toolbox programming techniques: "Inside Macintosh" "parameter block" userdata refcon custom variables 0 results Based on my research, I need to be honest that I don't have complete certainty about the specific "Inside Macintosh" compliant method for adding custom variables to parameter blocks during asynchronous calls. The search results show information about modern Objective-C blocks and completion handlers, but not the classic Mac OS Toolbox parameter block structures that "Inside Macintosh" documents. From what I understand about classic Mac OS programming patterns, parameter blocks typically had specific, predefined structures for different managers (File Manager, Device Manager, etc.), and the standard approach for custom data during asynchronous operations was usually: [LIST=1] [*]Using the refCon (reference constant) field that many parameter blocks included - this was specifically designed to hold a pointer to your custom data [*]Creating a separate data structure that you'd allocate and point to from the refCon field [*]In your completion routine, casting the refCon back to your custom data structure [/LIST] However, I don't want to give you incorrect specifics about the exact field names or structures without being certain about the "Inside Macintosh" documentation. Would you be able to clarify which specific manager or type of parameter block you're working with? That would help me give you a more precise answer about the compliant approach for that particular case.
 
Pretty cool stuff here. I've thought about using AI to generate this type of classic Mac code. But I haven't made the leap yet, partly because it's sort of fun to learn this stuff and build it myself. But at some point I'll probably make the leap and give this a shot.
 
I also have found Claude to be more interesting.

These shared answers are not exactly the same as what I saw a while back but clearly provide a hint or general direction which is helpful. The point was many of these already have access to Inside Macintosh and tech notes.
 
The past few years I've been working (off and on) porting an open source System 7 application to System 6.

Originally I was doing it all by hand, but now I'm using LLMs to help me solve bugs. I've found Gemini to give the most accurate answers to coding issues, but ChatGPT o4-high and o3 work most (95%?) of the time. I haven't yet tried adding the project to an agent like Claude Code.

I have a lot of PDFs from vintageapple.org uploaded to NotebookLM which can be helpful for finding references. A recent example is how to get a document to open in an application that is already running (you need to have a menu item for "Open" which the system uses to puppet the interaction).

Overall I've found it to be much more helpful than I would have guessed before trying it. Prompts like "give me c89 code for a macintosh that limits its apis to System 6" work surprisingly well.
 
Back
Top