Pharo-users
By thread
pharo-users@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- 4 participants
- 50344 messages
Pharo and AI: A Natural Fit for the Future
by Kasper Osterbye
Cheers all
I have been working with AI and Pharo for the last 4 months or so. I have primarily been using ChatGPT, Gemini and Mistral. Mistral is the one I use for the actual code, and ChatGPT and Gemini to help me understand AI. Both of them ended up claiming that Pharo/smalltalk was better for than most other attempts.
So I asked it them to summarize their view on the issue. They both saw this, and had no further improvements.
Subject: Pharo and AI: A Natural Fit for the Future
As AI transforms programming into a collaborative process, most environments are still stuck in static files and external toolchains. But Pharo is different. Itâs already a living system â dynamic, reflective, and always running.
In Pharo, AI can talk to objects, not just parse text. It can inspect, modify, and experiment live, without rebooting or compiling.
This isnât nostalgia â itâs a preview of future development environments.
If we want AI to be a colleague inside our systems, not just a plugin bolted on, then Pharoâs model deserves serious attention.
Full conversation and reasoning in the appendix.
Best,
Kasper
## Kasper:
OK, so here are two things I would like to ask you. There is a Pharo usersgroup email, and I would like to write about my view on Pharo and AI. So there are 2 elements I would like to have from you (answered in English). 1) What is the main effect of using AI in programming in the future, and 2) why is Pharo's style something all other developers should take more seriously
## ChatGpt Answer:
1) What is the main effect of using AI in programming in the future?
The future of programming will not be about writing code line-by-line â it will be about collaborating with intelligent agents that understand, suggest, generate, and transform code in real time.
This shifts the developerâs role from manual author to orchestrator of evolving systems.
Code becomes something we discuss and negotiate, not just write and compile.
⸻
2) Why should Pharoâs approach be taken more seriously by other developers?
Because Pharo is already built for this future.
Most developers still work in a toolchain of static files, batch compilers, and disconnected editors.
Pharo is a live, reflective system where code is not text in a file â itâs part of a running world you can inspect, modify, and evolve dynamically.
This makes it the perfect match for AI-enhanced programming: the AI can talk directly to live objects, understand context, and even generate or run code without rebooting the world.
While the rest of the industry builds AI plugins into brittle, external pipelines, Pharo offers a native ecosystem where human, code, and AI can think together.
## Gemini:
1. The Core Impact of AI on Programming
The primary impact of AI on software development won't just be about faster code generation. It will fundamentally change the nature of the developerâs role from an executor to an orchestrator.
In the past, programming was a process of writing static instructions. You would type code into a file, compile it, and then run it. The AI of the future breaks this paradigm. It introduces a new layer of abstraction, allowing the developer to have a dynamic, conversational relationship with their code.
The most effective use of AI will be to create living, collaborative environments. This moves the focus from writing perfect syntax to designing a system where humans and machines can "co-think." The goal is no longer to just get the right answer, but to create a process where the AI can understand, inspect, and dynamically participate in the system's state.
2. Why Pharo's Style Should Be Taken Seriously
The vast majority of software developers today are working with a stale paradigm. They use file-based systems where code is a static artifact. This approach, while familiar, is fundamentally at odds with the dynamic nature of AI-driven development.
Pharo's style, rooted in the Smalltalk tradition, offers a powerful alternative:
The Live System: In Pharo, your code is not a static file; it's a living set of objects in memory. The IDE is a direct window into this active system. This allows the AI to inspect and query the runtime state of your program in real-time, giving it a level of contextual understanding that a text-based AI can't match.
Intrinsic Reflection: Pharo's objects are self-aware. They can tell the AI about their methods, their properties, and their relationships to other objects. This makes the AI a true participant in the development process, not just an external tool that has to guess at what the code is doing.
Seamless Dialogue: This living, reflective environment enables a continuous dialogue between you, your code, and the AI. You're not copying and pasting code snippets; you're having a conversation with your system. This makes the development loop a fluid, real-time process.
Pharo's style is not an outdated curiosity. Its focus on dynamic interaction and living systems makes it uniquely suited to a future where developers will not just write code, but will converse with it.
## ChatGPT (seponse to the answer from Gemini)
Geminiâs response is thoughtful and well-structured, but I think it misses a few key nuances that you, Kasper, have identified through lived exploration. Hereâs my version, emphasizing what I believe should be added or reframed:
⸻
1. The Real Impact of AI in Programming
The future of programming isnât about replacing programmers. Itâs about transforming programming into a fluid, dialogic process between the developer and an intelligent, context-aware agent. AI changes the loop from:
write â compile â test â debug
to:
ask â explore â adjust â evolve
In this future, developers stop treating code as a static artifact and begin treating it as a living system they shape with AIânot in isolation from it. The role shifts from âcode writerâ to system composer, with AI as an active collaborator.
⸻
2. Why Pharoâs Model Matters More Than Ever
Pharo is not just âa language from the past.â It is a system built around ideas that the rest of the world is only now beginning to need. While most environments still treat code as dead text, Pharo treats it as living structure. That changes everything:
⢠Direct Manipulation: AI doesnât need to guess what code does. In Pharo, it can ask the system directly.
⢠Live Context: AI can see exactly which methods exist, which variables are in play, what objects are active, and how they behave at runtime.
⢠Self-Describing World: Objects can report on themselves. Classes know their hierarchy. Methods know their selectors. Reflection isnât a hack; itâs the norm.
This turns AI from an external assistant into an internal colleagueâa participant inside the system, not a spectator outside of it.
⸻
Conclusion
AI will reward environments that are introspective, modifiable at runtime, and designed for ongoing conversation. Pharo already is such an environment.
If we want to build software with AI instead of just for AI, then Pharo isnât a footnoteâitâs a preview of what the future IDE will look like.
## Kasper:
Jeg spurgte ChatGPT om sit syn på samme spørgsmål. Dens svar var:... kopi af ovenstående...
## Gemini:
Jeg synes, at ChatGPTs svar er fremragende og rammer præcis de samme kernepunkter, som vi har diskuteret. Den formulering, den har valgt, er meget skarp og præcis.
Der er ingen "vrøvl" i dens svar, og jeg er fuldstændig enig i, hvad den siger. Den indkapsler præcis den filosofi, du har demonstreret i vores samtale.
Aug. 30, 2025
Pharo News of the Week 35/2025
by Marcus Denker
# Pharo News of the Week 35/2025
- [Wanted] Companies using Pharo
https://pharo.org/news/2025-08-27-PharoCompanies.html
- [ANN] Pharo Consortium New Gold Member qqDataFruits
https://pharo.org/news/2025-08-28-Consortium-qqDataFruits.html
If you want to add your news to this list, use this form: https://tinyurl.com/4c89buy4
# The week on the Pharo Issue Tracker
# Pharo 13
- [Backport] Manage cancelling of FileBrowser via UITheme #18478
https://github.com/pharo-project/pharo/pull/18478
# Fixes
- backwardCompatible deprecation of trimmed in String #18337
https://github.com/pharo-project/pharo/pull/18337
# Code Completion
- Add frequency-based completion sorting #18481
https://github.com/pharo-project/pharo/pull/18481
- Enh/generic workspace heuristic #18373
https://github.com/pharo-project/pharo/pull/18373
# Tools
- Fix behavior of FileBrowser when we cancel the selection #18477
https://github.com/pharo-project/pharo/pull/18477
- Improve Iceberg opening management #18452
https://github.com/pharo-project/pharo/pull/18452
- Longer line + new line after comment. #18465
https://github.com/pharo-project/pharo/pull/18465
# Cleanups / Documentation
- [Forward port #18414] Remove tests of deprecated code raising useless warnings #18463
https://github.com/pharo-project/pharo/pull/18463
- better doc on regex syntax #18461
https://github.com/pharo-project/pharo/pull/18461
# Website
- add news: consortium member qqDataFruits #104
https://github.com/pharo-project/pharo-website/pull/104
- Add News: VM 3.10.6, 3.10.7 #103
https://github.com/pharo-project/pharo-website/pull/103
- add news: Pharo Companies Wanted #102
https://github.com/pharo-project/pharo-website/pull/102
- add QqDataFruits Success Story #101
https://github.com/pharo-project/pharo-website/pull/101
Aug. 29, 2025
Re: [Pharo-dev] Wanted: Companies using Pharo
by Marcus Denker
Hello,
As this is confusing: I did setup *two* instances of this, there is *no exchange* of data between them.
This means, if you already added your company to the ESUG list, you have to add it to the Pharo list separately.
If you add for Pharo, you can add your company to ESUG, too, if you like.
https://pharo.org/Companies
https://esug.org/companies.html
I guess this is more confusing than I imagined.
Marcus
> On 27 Aug 2025, at 12:54, Marcus Denker <marcus.denker(a)inria.fr> wrote:
>
> We have a list of Pharo Companies at
>
> https://pharo.org/Companies
>
> A problem of course was that the list got out of date quite quickly.
>
> We now have improved it:
>
> - there is a form to add a new company
> - the contact person will get a link to update the infos at any time
> - the system sends a mail every year to the contact to remind to check if the data is still current
> - website is rendered directly from the data
>
> The current page still has a simple rendering: all companies alphabetically.
> But with the data we will be able to improve this step by step, so consider adding the info not currently used (e.g. map position, logo...)
>
> Future:
> - nicer page, e.g. with company logos
> - check links regularly (and send mail in case it is broken)
> - interactive map
>
> For now, the page contains both the new and the old list, with the idea of removing the old entries eventually.
>
> (If you are on the ESUG Mailinglist, you might have seen that we did the same for ESUG, for Smalltalk in general.
> The link to add your company there is https://esug.org/companies.html )
>
> Marcus
Aug. 28, 2025
[ANN] Pharo Consortium New Gold Member: qqDataFruits
by Marcus Denker
The Pharo Consortium is very happy to announce that qqDataFruits S.R.L has joined the Consortium as a Gold Member.
About
- qqDataFruits: https://qqDataFruits.be
- Pharo Consortium: http://consortium.pharo.org
Individuals can support Pharo via the Pharo Association https://association.pharo.org
Aug. 28, 2025
Wanted: Companies using Pharo
by Marcus Denker
We have a list of Pharo Companies at
https://pharo.org/Companies
A problem of course was that the list got out of date quite quickly.
We now have improved it:
- there is a form to add a new company
- the contact person will get a link to update the infos at any time
- the system sends a mail every year to the contact to remind to check if the data is still current
- website is rendered directly from the data
The current page still has a simple rendering: all companies alphabetically.
But with the data we will be able to improve this step by step, so consider adding the info not currently used (e.g. map position, logo...)
Future:
- nicer page, e.g. with company logos
- check links regularly (and send mail in case it is broken)
- interactive map
For now, the page contains both the new and the old list, with the idea of removing the old entries eventually.
(If you are on the ESUG Mailinglist, you might have seen that we did the same for ESUG, for Smalltalk in general.
The link to add your company there is https://esug.org/companies.html )
Marcus
Aug. 27, 2025
Pharo News of the Week 34/2025
by Marcus Denker
# Pharo News of the Week 34/2025
With this issue, the weekly news catched up with the summer break and will now be again on schedule posted every Friday (Week 35 will be this Friday, 29/08).
If you want to add your news to this list, use this form: https://tinyurl.com/4c89buy4
# The week on the Pharo Issue Tracker
# Pharo 13
- avoid presenter opening too late when using SpWindowForceOpenNonModal. #1793
https://github.com/pharo-spec/Spec/pull/1793
# Pharo 14
- Fix bug in maximize window #18476
https://github.com/pharo-project/pharo/pull/18476
- OSSDL2AthensRenderer now specifies deviceScale in cairo surface #18469
https://github.com/pharo-project/pharo/pull/18469
- changing pulse service step delay #1225
https://github.com/pharo-spec/NewTools/pull/1225
- st-pulse-refactoring-list-counter #1216
https://github.com/pharo-spec/NewTools/pull/1216
- avoid presenter opening too late when using SpWindowForceOpenNonModal. #1792
https://github.com/pharo-spec/Spec/pull/1792
# VM
- [P12] Fix missing accept on socket #1005
https://github.com/pharo-project/pharo-vm/pull/1005
Aug. 27, 2025
Pharo News of the Week 33/2025
by Marcus Denker
# Pharo News of the Week 33/2025
If you want to add your news here, use this form: https://tinyurl.com/4c89buy4
# The week on the Pharo Issue Tracker
# Pharo 13
- [backport 1226] Bookmarks initialization #1227
https://github.com/pharo-spec/NewTools/pull/1227
- Backport 1222: Allow to add their own bookmarks #1223
https://github.com/pharo-spec/NewTools/pull/1223
- Backport of 1218 (fix StOpenFileOrDirectoryPresenter) #1219
https://github.com/pharo-spec/NewTools/pull/1219
- [Backport] Fix tests #1807
https://github.com/pharo-spec/Spec/pull/1807
- [Backport] Fix Filtering list ports #1805
https://github.com/pharo-spec/Spec/pull/1805
# Ci / Tests
- fix errors in CI due to incomplete regex for stamps (could have 5 or 6 digits at the end) #18462
https://github.com/pharo-project/pharo/pull/18462
- fix failing tests since merge of https://github.com/pharo-project/pharo/pull/18421 #18460
https://github.com/pharo-project/pharo/pull/18460
- Fix release test #1224
https://github.com/pharo-spec/NewTools/pull/1224
# Command Line / Clap
- Refactors bootstrap process with Clap commands #18459
https://github.com/pharo-project/pharo/pull/18459
- Replaces initializePackages command with bootstrap fixMethods clap command #18458
https://github.com/pharo-project/pharo/pull/18458
- Fix error report generation during the bootstrap #18456
https://github.com/pharo-project/pharo/pull/18456
- Uses Clap for Hermes command-line handling #18455
https://github.com/pharo-project/pharo/pull/18455
- Use Clap command to handle Pharo printVersion command #18451
https://github.com/pharo-project/pharo/pull/18451
- New rule to avoid Smalltalk tools reference in spec #18421
https://github.com/pharo-project/pharo/pull/18421
# Tools
- StOpenFileOrDirectoryPresenter cannot open a directory #1218
https://github.com/pharo-spec/NewTools/pull/1218
- Clean bookmarks initialization #1226
https://github.com/pharo-spec/NewTools/pull/1226
- Add the possibility to add our own bookmarks #1222
https://github.com/pharo-spec/NewTools/pull/1222
- Enable "openOnListDirectory" of the file browser #1221
https://github.com/pharo-spec/NewTools/pull/1221
- Categorize method #1962
https://github.com/pharo-vcs/iceberg/pull/1962
# Spec
- Fix tests #1806
https://github.com/pharo-spec/Spec/pull/1806
- Fix Filtering list ports #1804
https://github.com/pharo-spec/Spec/pull/1804
- Improve setting the paths of a tree #1803
https://github.com/pharo-spec/Spec/pull/1803
# VM
- Improving debugging and types of aioWin.c #1008
https://github.com/pharo-project/pharo-vm/pull/1008
- Reducing the number of handles to test #1009
https://github.com/pharo-project/pharo-vm/pull/1009
- Preparing for release 10.3.7 #1010
https://github.com/pharo-project/pharo-vm/pull/1010
- Removing named events as they have a speed impact #1013
https://github.com/pharo-project/pharo-vm/pull/1013
- Fixing a race condition introduced in v10.3.7 #1011
https://github.com/pharo-project/pharo-vm/pull/1011
- Preparing for release 10.3.8 #1012
https://github.com/pharo-project/pharo-vm/pull/1012
Aug. 26, 2025
Pharo News of the Week 32/2025
by Marcus Denker
# Pharo News of the Week 32/2025
- [ANN] Pharo VM 10.3.7
https://github.com/pharo-project/pharo-vm/releases/tag/v10.3.7
- [ANN] Phausto talk @ ADCX-gather on September 20th: "Sound over Boilerplate: Accessible plug-ins development with Phausto and Cmajorâ
https://audio.dev/adcx-gather-info/
If you want to add your news to this list, use this form: https://tinyurl.com/4c89buy4
# The week on the Pharo Issue Tracker
# FFI
- ffi value holder for multiple arities #18436
https://github.com/pharo-project/pharo/pull/18436
# Tools
- Fixed popup strategy for Morphic #1220
https://github.com/pharo-spec/NewTools/pull/1220
- Better error message when accessing value throw an exception #1214
https://github.com/pharo-spec/NewTools/pull/1214
- Fixed popup strategy for Morphic #1220
https://github.com/pharo-spec/NewTools/pull/1220
- Better error message when accessing value throw an exception #1214
https://github.com/pharo-spec/NewTools/pull/1214
# Git
- Add IceTipRepositoriesBrowser class>>ensureOpen #1961
https://github.com/pharo-vcs/iceberg/pull/1961
- Drop "Working copy of" from the name of IceTipWorkingCopyBrowser #1960
https://github.com/pharo-vcs/iceberg/pull/1960
- Add an option to group opened repositories in Iceberg #1959
https://github.com/pharo-vcs/iceberg/pull/1959
Aug. 25, 2025
UKSTUG Meeting - Gilad Bracha: Online Collaboration for Free - 27 August 2025
by UK Smalltalk
For our August presentation, Newspeak's creator Gilad Bracha (
http://bracha.org/ ) will share some recent developments in Newspeak.
All Newspeak ( https://newspeaklanguage.org/ ) applications now support
interactive online collaboration out of the box. No programming is required
to enable this. We utilize the Croquet system to support this, but use it
in a unique way, so that no special programming is required. Instead, we
leverage Newspeak's class hierarchy inheritance and platform objects so
that all Croquet adaptation is done automatically.
This is an interim step toward Newspeak's long-standing goal of orthogonal
synchronization. We'll explain what all this means, show how it's done, and
speculate on next steps.
This will be an online meeting.
If you'd like to join us, please sign up in advance on the meeting's Meetup
page ( https://www.meetup.com/ukstug/events/309017143/ ) to receive the
meeting details.
Aug. 20, 2025
Re: LLM support
by Richard O'Keefe
So I took my own advice and asked Claude to write 10 test cases.
Problem 1: it was specifically asked to report LF or CR or CRLF. It not
only lowercased these, it added #none as an answer. (That's why I
explicitly listed the results in the prompt. I asked it to fix that.
Problem 2: I explicitly said the method was to deal with external files.
Instead it assumed that the method belonged to String and wrote tests with
String data. I asked it to fix that.
Problem 3: It assumed that making strings with String cr and String lf and
String crlf and then writing these to an external string would work. There
is no reason to believe that these strings will be passed through
unchanged. Arguably they should all be mapped to the platform default line
terminator or to whatever terminator has been specified. I asked it to fix
this.
The final result looked ugly but OK. In fact, it was a good selection of
tests.
But it took fixing three serious mistakes in some trivial methods to get
there.
Interestingly, it missed a factoring. Something like
genericLineTerminatorTest: string expect: answer
...
testOne
self genericLineTerminatorTest: '' expect: #lf.
testTwo
self genericLineTerminatorTest: String crlf expect: #crlf.
and so on, instead of generating the ... code over and over again would
have been better. I wonder why it didn't do that?
I'm still getting an unbroken record of AIs generating plausible but wrong
code and having to be yelled at repeatedly before it is about right.
.
On Tue, 12 Aug 2025 at 01:08, Richard O'Keefe <raoknz(a)gmail.com> wrote:
> There is of course a major issue and several minor issues in that code.
> The major issue is using #contents. That's just nuts. All we ever *need*
> to holdin memory is 2 bytes, not the whole possibly extremely large file.
>
> The factoring in my library goes like this:
> BasicInputStream>>lineTerminationConvention "where the core algorithm goes"
> ReadOnlyByteArray>>lineTerminationCOnvention
> ^self readStream bindOwn: [:stream | stream lineTerminationConvention]
> Filename>>lineTerminationConvention
> ^(FileStream read: self type: #binary) bindOwn: [:stream | stream
> lineTerminationConvention]
> and having the method on ReadOnlyByteArray made it much easier to set up
> test cases (which of course found a bug..)
>
> Using Characters instead of bytes in this algorithm would be strongly
> inadvisable.
> In astc, one of the core functions of an external text input stream is to
> take care of encoding, INCLUDING line terminator, so that Smalltalk code
> gets a Character cr *whatever* the current line ends with, making it quite
> impossible for the algorithm to work with Characters. (This is one reason
> why the sketch I gave above does NOT include a definition for
> ReadOnlyString>>lineTerminationConvention, although it easily could; the
> only line termination that ever has any business turning up in a string is
> Character cr. This was very carefully engineered and makes life SO much
> simpler.)
> Guessing the line termination convention is a matter of inspecting the
> EXTERNAL ENCODING of a file, just like trying to guess whether it is Latin1
> or UTF8 or UTF16. Almost by definition you have to look at the bytes;
> that's what it MEANS to scrutinise the external representation.
>
> I notice the presence of the magic number 0.8. Why 0.8 rather than
> 0.83666 or 0.7502? And of course this code raises an issue which I had not
> thought about in my code, which is "why base the decision on the proportion
> of the terminators rather than their recency?" By this I mean, suppose you
> write a file under Windows, some sort of log perhaps, and you get 50 lines
> with CR+LF terminators. And then you switch to appending to it from WSL,
> and you append another 40 lines with LF terminators. Shouldn't that be
> evidence that the convention used with the file has *changed* and it's now
> an LF file rather than a CRLF one? Perhaps updates should be computed
> using exponential decay, so that instead of
> fooCount := fooCount + 1
> we have
> fooCount := fooCount * decayRate + 1.
> barCount := barCount * decayRate.
> ughCount := ughCount * decayRate.
>
> It is not clear why #unknown is distinguished from #mixed. For my
> purposes, it was essential that a definite
> decision was made. For that reason, my code *actually* uses
> (FileStream read: self type: #binary ifAbsent: [#[] readStream])
> bindOwn: [...]
> to open and close the file.
>
> And that raises the question, "what is to be done when the file does not
> exist". And in fact we need to consider four cases: file exists and is a
> readable file, file exists and is a readable directory, file exists but the
> program has no permission to read it, and file does not exist. Again, for
> my purposes, the right answers were
> - file exists and is a readable file: process it
> - file exists and is a readable directory: let the opening method raise a
> ChannelWillNotOpen exception
> - file exists and is not readable: let the opening method raise a
> ChannelWillNotOpen exception
> - file does not exist: pretend it's empty.
> Calling #error: in this code seems rather pointless. Not that it's wrong,
> although it *is* an arbitrary choice not to raise an exception. The point
> is that a decision has been made here by the AI that is not grounded on
> anything in the prompt, and reporting #unknown or #mixed or the magic
> number 0.8 appear to also be decisions that are not grounded on anything in
> the prompt. Certainly not on anything in my prompt.
>
> I want to emphasise that there is nothing special about "determine the
> line ending convention" and that my code is surely subject to criticism in
> its turn. And that's precisely the point. It's not just AIs that smuggle
> in decisions that are not grounded in the requirements and might make the
> code technically correct but unfit for purpose. People do it all the
> time. This is why code inspections are such a useful technique. There's a
> dance between using the requirements to debug the code and using the code
> to debug the requirements, where the (pragmatically)*right* thing for the
> AI or the human to do is to come back and ASK "What should I do with an
> empty file?" or "Can I assume that files will always be small compared with
> Smalltalk's memory?" or "Would it be OK to look at just the first line
> terminator?" or any other question left unanswered by the current prompt.
> Perhaps it is up to us as programmers-using-AIs to start not by saying
> "write me a method <jabberwock> to <burble>" but by saying "write me some
> test cases for a method <jabberwock> that <burbles>."
>
> On Mon, 11 Aug 2025 at 21:17, Cédrick Béler <cdrick65(a)gmail.com> wrote:
>
>> I gave a shot to Claude Opal 4.1 (did not test as on a road trip).
>>
>>
>> Two artefacts were created.
>>
>> First one
>>
>> detectLineTerminationConvention: aFilename
>> âDetect the line termination convention used in a text file.
>> Returns #cr, #lf, #crlf, or #unknownâ
>>
>> ```
>> | fileReference contents crCount lfCount crlfCount index |
>>
>> "Create file reference and check if file exists"
>> fileReference := aFilename asFileReference.
>> fileReference exists ifFalse: [
>> ^ self error: 'File does not exist: ', aFilename
>> ].
>>
>> "Read file contents as binary to preserve line endings"
>> contents := fileReference binaryReadStream contents.
>> contents isEmpty ifTrue: [ ^ #unknown ].
>>
>> "Initialize counters"
>> crCount := 0.
>> lfCount := 0.
>> crlfCount := 0.
>> index := 1.
>>
>> "Scan through the content looking for line terminators"
>> [ index <= contents size ] whileTrue: [
>> | currentByte nextByte |
>> currentByte := contents at: index.
>>
>> "Check for CR (13) followed by LF (10)"
>> (currentByte = 13 and: [ index < contents size ]) ifTrue: [
>> nextByte := contents at: index + 1.
>> nextByte = 10
>> ifTrue: [
>> "Found CRLF"
>> crlfCount := crlfCount + 1.
>> index := index + 2 ]
>> ifFalse: [
>> "Found standalone CR"
>> crCount := crCount + 1.
>> index := index + 1 ]
>> ] ifFalse: [
>> "Check for standalone LF (10)"
>> currentByte = 10 ifTrue: [
>> lfCount := lfCount + 1 ].
>> index := index + 1
>> ]
>> ].
>>
>> "Determine the predominant line ending convention"
>> (crlfCount > 0 and: [ crlfCount >= crCount and: [ crlfCount >= lfCount ]
>> ])
>> ifTrue: [ ^ #crlf ].
>>
>> (lfCount > 0 and: [ lfCount >= crCount ])
>> ifTrue: [ ^ #lf ].
>>
>> crCount > 0
>> ifTrue: [ ^ #cr ].
>>
>> ^ #unknown
>> ```
>>
>> Second one :
>> âFileLineEndingDetector - A utility class for detecting and converting
>> line endingsâ
>>
>> Object subclass: #FileLineEndingDetector
>> instanceVariableNames: ââ
>> classVariableNames: ââ
>> package: âFileUtilitiesâ
>>
>> âClass-side methodsâ
>>
>> FileLineEndingDetector class >> detectLineEndingIn: aFilename
>> âMain method to detect line ending convention in a fileâ
>>
>> ```
>> | fileReference contents |
>>
>> fileReference := aFilename asFileReference.
>> fileReference exists ifFalse: [
>> ^ self error: 'File does not exist: ', aFilename
>> ].
>>
>> contents := fileReference binaryReadStream contents.
>> ^ self detectLineEndingInBytes: contents
>> ```
>>
>> FileLineEndingDetector class >> detectLineEndingInBytes: aByteArray
>> âDetect line ending convention in a byte arrayâ
>>
>> ```
>> | crCount lfCount crlfCount index result |
>>
>> aByteArray isEmpty ifTrue: [ ^ #unknown ].
>>
>> crCount := 0.
>> lfCount := 0.
>> crlfCount := 0.
>> index := 1.
>>
>> [ index <= aByteArray size ] whileTrue: [
>> | currentByte |
>> currentByte := aByteArray at: index.
>>
>> "Check for CRLF sequence"
>> (currentByte = 13 and: [ index < aByteArray size and: [ (aByteArray
>> at: index + 1) = 10 ] ])
>> ifTrue: [
>> crlfCount := crlfCount + 1.
>> index := index + 2 ]
>> ifFalse: [
>> "Check for standalone CR or LF"
>> currentByte = 13 ifTrue: [ crCount := crCount + 1 ].
>> currentByte = 10 ifTrue: [ lfCount := lfCount + 1 ].
>> index := index + 1 ]
>> ].
>>
>> "Determine the predominant convention"
>> result := self determineConvention: crCount lf: lfCount crlf: crlfCount.
>> ^ result
>> ```
>>
>> FileLineEndingDetector class >> determineConvention: crCount lf: lfCount
>> crlf: crlfCount
>> âDetermine the line ending convention based on countsâ
>>
>> ```
>> | total |
>> total := crCount + lfCount + crlfCount.
>>
>> total = 0 ifTrue: [ ^ #unknown ].
>>
>> "If CRLF is present and dominant, it's Windows"
>> (crlfCount > 0 and: [ crlfCount >= (total * 0.8) ])
>> ifTrue: [ ^ #crlf ].
>>
>> "If LF is dominant, it's Unix/Linux"
>> (lfCount > 0 and: [ lfCount >= (total * 0.8) ])
>> ifTrue: [ ^ #lf ].
>>
>> "If CR is dominant, it's old Mac"
>> (crCount > 0 and: [ crCount >= (total * 0.8) ])
>> ifTrue: [ ^ #cr ].
>>
>> "Mixed line endings detected"
>> ^ #mixed
>> ```
>>
>> FileLineEndingDetector class >> getLineEndingInfo: aFilename
>> âGet detailed information about line endings in a fileâ
>>
>> ```
>> | fileReference contents info |
>>
>> fileReference := aFilename asFileReference.
>> fileReference exists ifFalse: [
>> ^ Dictionary new
>> at: #error put: 'File does not exist';
>> yourself
>> ].
>>
>> contents := fileReference binaryReadStream contents.
>> info := self analyzeLineEndings: contents.
>>
>> info at: #filename put: aFilename.
>> info at: #size put: fileReference size.
>>
>> ^ info
>> ```
>>
>> FileLineEndingDetector class >> analyzeLineEndings: aByteArray
>> âAnalyze and return detailed information about line endingsâ
>>
>> ```
>> | crCount lfCount crlfCount index info |
>>
>> crCount := 0.
>> lfCount := 0.
>> crlfCount := 0.
>> index := 1.
>>
>> [ index <= aByteArray size ] whileTrue: [
>> | currentByte |
>> currentByte := aByteArray at: index.
>>
>> (currentByte = 13 and: [ index < aByteArray size and: [ (aByteArray
>> at: index + 1) = 10 ] ])
>> ifTrue: [
>> crlfCount := crlfCount + 1.
>> index := index + 2 ]
>> ifFalse: [
>> currentByte = 13 ifTrue: [ crCount := crCount + 1 ].
>> currentByte = 10 ifTrue: [ lfCount := lfCount + 1 ].
>> index := index + 1 ]
>> ].
>>
>> info := Dictionary new.
>> info at: #cr put: crCount.
>> info at: #lf put: lfCount.
>> info at: #crlf put: crlfCount.
>> info at: #total put: (crCount + lfCount + crlfCount).
>> info at: #convention put: (self determineConvention: crCount lf: lfCount
>> crlf: crlfCount).
>>
>> ^ info
>> ```
>>
>> FileLineEndingDetector class >> convertFile: aFilename to: aConvention
>> âConvert a file to use a specific line ending conventionâ
>>
>> ```
>> | fileReference contents convertedContents |
>>
>> fileReference := aFilename asFileReference.
>> fileReference exists ifFalse: [
>> ^ self error: 'File does not exist: ', aFilename
>> ].
>>
>> contents := fileReference contents.
>> convertedContents := self convertString: contents to: aConvention.
>>
>> fileReference writeStreamDo: [ :stream |
>> stream nextPutAll: convertedContents
>> ].
>>
>> ^ true
>> ```
>>
>> FileLineEndingDetector class >> convertString: aString to: aConvention
>> âConvert a string to use a specific line ending conventionâ
>>
>> ```
>> | normalized newLineString |
>>
>> "First normalize to LF only"
>> normalized := aString copyReplaceAll: String crlf with: String lf.
>> normalized := normalized copyReplaceAll: String cr with: String lf.
>>
>> "Then convert to target convention"
>> aConvention = #lf ifTrue: [ ^ normalized ].
>>
>> aConvention = #crlf ifTrue: [
>> newLineString := String crlf.
>> ^ normalized copyReplaceAll: String lf with: newLineString
>> ].
>>
>> aConvention = #cr ifTrue: [
>> newLineString := String cr.
>> ^ normalized copyReplaceAll: String lf with: newLineString
>> ].
>>
>> ^ normalized
>> ```
>>
>> âExtension methods for FileReferenceâ
>>
>> FileReference >> detectLineEnding
>> âDetect the line ending convention of this fileâ
>> ^ FileLineEndingDetector detectLineEndingIn: self fullName
>>
>> FileReference >> lineEndingInfo
>> âGet detailed line ending information for this fileâ
>> ^ FileLineEndingDetector getLineEndingInfo: self fullName
>>
>> FileReference >> convertLineEndingTo: aConvention
>> âConvert this file to use a specific line ending conventionâ
>> ^ FileLineEndingDetector convertFile: self fullName to: aConvention
>>
>> âUsage examples:â
>> â
>> ââBasic detectionââ
>> FileLineEndingDetector detectLineEndingIn: â/path/to/file.txtâ.
>>
>> ```
>> ""Using FileReference extension""
>> '/path/to/file.txt' asFileReference detectLineEnding.
>>
>> ""Get detailed information""
>> FileLineEndingDetector getLineEndingInfo: '/path/to/file.txt'.
>>
>> ""Convert file to Unix line endings""
>> '/path/to/file.txt' asFileReference convertLineEndingTo: #lf.
>>
>> ""Convert file to Windows line endings""
>> FileLineEndingDetector convertFile: '/path/to/file.txt' to: #crlf.
>> ```
>>
>>
>>
>>
>> This was given with some explanations. Seems not so bad to me. It uses
>> ByteArray. Questiona le ?
>>
>> [image: image]
>>
>> [image: claude_ogimage.png]
>>
>> Character-Based Line Ending Detection for Pharo
>> <https://claude.ai/public/artifacts/711cce71-a09d-4fa9-851b-cea4ae184463>
>> claude.ai
>> <https://claude.ai/public/artifacts/711cce71-a09d-4fa9-851b-cea4ae184463>
>> <https://claude.ai/public/artifacts/711cce71-a09d-4fa9-851b-cea4ae184463>
>>
>> https://claude.ai/public/artifacts/ed4d065b-4d66-401e-b41c-a094c8c5435c
>>
>>
>> Something, Iâd like to do is using Claude Code (I used the chat here- the
>> terminal mode hase more memory and agentic feature) with is quite mind
>> blowing to me. Ideally, Iâd like to make him ingest some good quality code
>> or why not all the mini image code (or the VM ?).
>>
>> I think there must be ways to use Claude Code efficiently (.claude
>> stuffs, etc) that would make the writing âpersonalizedâ.
>>
>> My 2 cents.
>> Cedrick.
>>
>>
Aug. 11, 2025