[Pharo-users] Re: Getting started with the easy projects

2024-05-17 Thread Richard O'Keefe
Life has been getting in the way.  Thanks for the
"Managing your code" chapter.  I've got that now.

On Fri, 17 May 2024 at 00:00, stephane ducasse 
wrote:

> Hi richard
>
> I wanted to tell you that there is also a chapter about how to contribute
> in the Managing your code
> [image: preview.png]
>
> 2020-05-12-ManageCode
> <https://books.pharo.org/booklet-ManageCode/pdf/2020-05-12-ManageCode.pdf>
> PDF Document · 2,1 MB
> <https://books.pharo.org/booklet-ManageCode/pdf/2020-05-12-ManageCode.pdf>
> <https://books.pharo.org/booklet-ManageCode/pdf/2020-05-12-ManageCode.pdf>
>
>
> S
>
>
> On 4 May 2024, at 09:10, stephane ducasse 
> wrote:
>
> Hi richard
>
> I can write something once you have a look at the video and let me know
> what you would like to know.
>
> S
>
> On 3 May 2024, at 14:27, Sebastian Jordan Montano <
> sebastian.jor...@inria.fr> wrote:
>
> You have the guide how to contribute to a fix in Pharo:
> https://github.com/pharo-project/pharo/wiki/Contribute-a-fix-to-Pharo
>
> Sebastian
>
> - Mail original -
>
> De: "Richard O'Keefe" 
> À: "Any question about pharo is welcome" 
> Envoyé: Vendredi 3 Mai 2024 12:28:16
> Objet: [Pharo-users] Re: Getting started with the easy projects
>
>
> What I was really asking was about the very basic mechanics of it.
> "Where are the instructions about how to sign up"
> meant "do I have to register somewhere and if so where and how?"
> "Where are the instructions about what to do"
> meant "suppose I have registered and have the latest Pharo open
> on my laptop; how do I connect to the repository, how do I submit
> a change for review?"  I have been playing with Pharo since version 1
> but I've never actually connected to a repository.
>
> I think a "Complete Idiot's Guide to Getting Started with Distributed
> Development in Phraro" probably already exists somewhere, I just
> don't know where to look for it.
>
> On Sat, 27 Apr 2024 at 21:05, stephane ducasse
>  wrote:
>
>
> Hi richard
>
> https://github.com/orgs/pharo-project/projects/8
> lists some easy projects.  I'd like to make a contribution.
>
>
> Cool.
> The first thing I suggest is to take the stupidiest issue like adding a
> comment
> in a method
> or fixing a badly written comment and make a PR.
> I like to do this trivial things because there are easy to give a positive
> slant
> on my energy.
>
> Where are the instructions on how to sign up and what
> to do?  Fair warning, I'll probably need a bit of hand-holding…
>
>
> For the contributions feel free to pick what you like
>
> - Some easy things are: better comments, improving test coverage
> - Now I’m pretty sure that we can get collection improvements
> - This one could interest you: underscores in numeric literals
> https://github.com/pharo-project/pheps/pull/18/files
> We had long design discussions and I think that the result is good but we
> never
> got the time to implement it.
>
> S
>
>
>
>
> Stéphane Ducasse
> http://stephane.ducasse.free.fr
> 06 30 93 66 73
>
> "If you knew today was your last day on earth, what would you do
> differently?
> ESPECIALLY if, by doing something different, today might not be your
> last
> day on earth.” Calvin & Hobbes
>
>
>
>
>
> Stéphane Ducasse
> http://stephane.ducasse.free.fr
> 06 30 93 66 73
>
> "If you knew today was your last day on earth, what would you do
> differently? ESPECIALLY if, by doing something different, today
> might not be your last day on earth.” Calvin & Hobbes
>
>
>
>
>
>
> Stéphane Ducasse
> http://stephane.ducasse.free.fr
> 06 30 93 66 73
>
> "If you knew today was your last day on earth, what would you do
> differently? ESPECIALLY if, by doing something different, today
> might not be your last day on earth.” Calvin & Hobbes
>
>
>
>
>
>


[Pharo-users] Re: Getting started with the easy projects

2024-05-03 Thread Richard O'Keefe
What I was really asking was about the very basic mechanics of it.
"Where are the instructions about how to sign up"
meant "do I have to register somewhere and if so where and how?"
"Where are the instructions about what to do"
meant "suppose I have registered and have the latest Pharo open
on my laptop; how do I connect to the repository, how do I submit
a change for review?"  I have been playing with Pharo since version 1
but I've never actually connected to a repository.

I think a "Complete Idiot's Guide to Getting Started with Distributed
Development in Phraro" probably already exists somewhere, I just
don't know where to look for it.

On Sat, 27 Apr 2024 at 21:05, stephane ducasse
 wrote:
>
> Hi richard
>
> https://github.com/orgs/pharo-project/projects/8
> lists some easy projects.  I'd like to make a contribution.
>
>
> Cool.
> The first thing I suggest is to take the stupidiest issue like adding a 
> comment in a method
> or fixing a badly written comment and make a PR.
> I like to do this trivial things because there are easy to give a positive 
> slant on my energy.
>
> Where are the instructions on how to sign up and what
> to do?  Fair warning, I'll probably need a bit of hand-holding…
>
>
> For the contributions feel free to pick what you like
>
> - Some easy things are: better comments, improving test coverage
> - Now I’m pretty sure that we can get collection improvements
> - This one could interest you: underscores in numeric literals
> https://github.com/pharo-project/pheps/pull/18/files
> We had long design discussions and I think that the result is good but we 
> never got the time to implement it.
>
> S
>
>
>
>
> Stéphane Ducasse
> http://stephane.ducasse.free.fr
> 06 30 93 66 73
>
> "If you knew today was your last day on earth, what would you do differently? 
> ESPECIALLY if, by doing something different, today might not be your last 
> day on earth.” Calvin & Hobbes
>
>
>
>
>


[Pharo-users] Getting started with the easy projects

2024-04-26 Thread Richard O'Keefe
https://github.com/orgs/pharo-project/projects/8
lists some easy projects.  I'd like to make a contribution.
Where are the instructions on how to sign up and what
to do?  Fair warning, I'll probably need a bit of hand-holding...


[Pharo-users] Re: How to log pharo output to stdio safely?

2024-04-19 Thread Richard O'Keefe
In the C world,
 - flush forces data from user-space buffers to OS buffers
 - sync forces data from OS buffers to devices
 - there is no standard documented way to force devices to move data
   from buffers to persistent storage even when the device has such an
  operation and the OS knows how to use it.
Is it the same in Pharo?


On Fri, 19 Apr 2024 at 19:16, Guillermo Polito
 wrote:
>
> Hi Tim,
>
> In general, doing a flush should suffice.
> Generally, the buffer is flushed automatically when full.
> You generally don’t need to flush manually unless you are in a special case 
> (like, you’re about to quit the process and you want to flush the buffer 
> before quitting).
>
> About the comment, would you mind opening an issue with the exact 
> information, I don’t really get the issue from the blob of text :)
>
> G
>
> El 18 abr 2024, a las 5:16 p. m., Tim Mackinnon  escribió:
>
> Just as a comment on this - I tried using #sync as an experiment and I get a 
> primFailed on an Ubuntu docker image - so I think that comment in the image 
> is misleading (or its a bug, or unfinished work)
>
>
>
> On Thu, 18 Apr 2024, at 11:15 AM, Tim Mackinnon wrote:
>
> Hi Stef - I was aware of that class - but a good reminder to re-read it for 
> any extra info, but I don't see anything in particular mentioned about how 
> data is flushed - and I think this is one of those black arts from in the 
> field.
>
> It looks like stdio uses an Stdiostream - and I did note an interesting 
> comment in #flush which mention #sync and
> "When writing, this syncs any written/flushed data still in the kernel file 
> system buffers to disk. This should generally be used after #flush, but on 
> Windows they do the same thing."
>
> I've never heard of #sync before - and I wonder if the trick to getting 
> output without the cr is to do a "flush; sync" operation?
>
> But even then, I am thinking that a server based logging tool is going to 
> need a cr on a log line to know how to interpret it and parse it into syslog 
> format, so perhaps I can't escape moving the a trailing cr policy - and just 
> try to make sure most of my logging adopts that standard (and just accept the 
> odd corruption when other libraries write out crTrace?).
>
> I'm just curious how others handle this kind of stuff in the wild - maybe I 
> should ask on a Seaside list as they are more likely to delve into this (or 
> maybe the Gemstone guys).
>
> Its a world you don't normally pay attention to until you try and run 
> something on a server and want to use the modern tools available in that 
> world.
>
> Tim
>
> On Thu, 18 Apr 2024, at 6:43 AM, stephane ducasse wrote:
>
> just out of my mind and before breakfast :)
>
> did you see Stdio ?
>
> S
>
> On 18 Apr 2024, at 01:31, Tim Mackinnon  wrote:
>
> Hi - I've been messing around with deploying a hobby pharo app to the web.. 
> which has become a lot simpler over the years, although the tech keeps 
> changing and you have to relearn things.
>
> Anyway, I have my image in one of the wonderful BA Docker containers, and it 
> runs well - and the host I'm using will show the logs for you, so you can 
> figure out what is going on... well that is if your logs come out properly 
> (and of course, if it gets really hairy then you can get a VNC session onto 
> the image and figure stuff out)
>
> So logs are handy, and pharo these days has a nice headless mode that 
> redirects the Transcript to stdout - and there are also a few decent logging 
> frameworks as well.
>
> But as most things go to the Transcript, and that goes to stdout - it should 
> be good.
>
> HOWEVER - flushing is the killer, as if things happen and the last thing goes 
> wrong, but the output isn't flushed, then you aren't going to see it.
>
> So my question is how to properly flush? And I'm sure I've read something 
> about this before, but I can't find it.
>
> From memory,  you often need to have a Transcript cr.  to flush your last 
> line.
>
> BUT, most things in the image seem to use  "self crTrace:"  these days, which 
> is a cr to ensure the previous msg is separated from what you want to write, 
> and then you write your line out. However, as there is now cr -  you might 
> not see it.
>
> So I tried changing my stuff to use "self traceCr:" (which is in the image), 
> and that still didn't seem to work - the last failing line wasn't being 
> output. Worse still, its confusing, as many things in the image are using 
> crTrace: and so you get intermingled messages, which are hard to decipher.
>
> So I tried: Transcript cr; show: msg; flush
>
> But that didn't seem to work (which I don't understand)
>
> Eventually I did: Transcript show: msg; cr; flush
>
> And this seems to ensure things do reliably get outputted - but I'm wondering 
> if anyone can shed light on this areas?
>
> Ideally I want to use: Transcript cr'; show: msg; flush
>
> As this plays much better with everything that is in the image - but is there 
> some way to do this? And indeed, 

[Pharo-users] Re: String concatenation performance

2024-03-18 Thread Richard O'Keefe
Let me start by giving some figures from my Smalltalk, on an Intel
core I5-6200U @ 2.3 Ghz CPU laptop with 8GB of memory running Ubuntu
22.04 and gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0.  Smalltalk is
compiled to C then finished with the system C compiler.  Static
whole-program compilation is allowed by the ANSI standard and the
system was originally written to serve as a baseline for Bryce's JIT.
 nsec technique
  249 replaceFrom:to:with:startingAt:*5
  128 withAll:*5
  486 
  492 (,,),(,)
  521 streamContents:
  367 StringWriteStream
  860 StringBuffer>>addAllLast:
  385 StringBuffer>>nextPutAll:

replaceFrom:to:with:startingAt:*5  makes a string the right size then
fills it in using #replaceAll:from:to:startingAt:.
withAll:*5 is String withAll: a withAll: b withAll: c withAll: d
withAll: e (supported up to 6 withAlls.)
This is interesting because the result can be a [ReadOnly](ByteArray
-- UTF8 -- or ShortArray -- UTF16 or String -- UTF32) and each of the
up to 6 operands can independently be these things.  It wasn't
intended as a fast alternative to #, .
 is a,b,c,d,e
(,,),(,) is (a,b,c),(d,e).
streamContents: is what you had
StringWriteStream is basically the same as streamContents: but using a
WriteStream specialised to Strings with some extra primitive support.
There are also StringReadStream and StringReadWriteStream.
StringBuffer is my version of Java's StringBuilder; it's a cross
between a String, an OrderedCollection, and a WriteStream.  It can
change size like an OrderedCollection; it has most of the "writing"
methods (but not the "position" ones) of a WriteStream, and at all
times you can use it as a String without having to copy the contents.
You would expect #addAllLast: and #nextPutAll: to have the same
result, and they do, but they were written a different times and
#nextPutAll: was optimised for the case where the operand is a string
while #addAllLast: wasn't.

What does all that mean in practice?
It means that a benchmark like this is VERY SENSITIVE to the details
of how the library is written.
Even just bracketing the commas differently gives you a different time.

It means that techniques which are more efficient for LARGE volumes of
data may have startup costs
that make them less efficient for SMALL volumes of data, and that this
is a very small benchmark.
The cost of a,b,c,d,e is proportional to |a|*5 + |b|*4 + |c|*3 + |d|*2
+ |e|, while the other techniques
are proportional to |a| + |b| + |c| + |d| + |e|, BUT have overheads of
their own.

Well, that was astc.  What about Pharo?
1,950,528 per second'  
6,509,256 per second' withAll:*5

Here it is.  I've added withAll:*2 to withAll:*6 to ArrayedCollection class.
withAll: c1 withAll: c2 withAll: c3 withAll: c4 withAll: c5
|e1 e2 e3 e4 e5|
e1 := c1 size.
e2 := c2 size + e1.
e3 := c3 size + e2.
e4 := c4 size + e3.
e5 := c5 size + e4.
^(self new: e5)
replaceFrom: 1 to: e1 with: c1 startingAt: 1;
replaceFrom: e1+1 to: e2 with: c2 startingAt: 1;
replaceFrom: e2+1 to: e3 with: c3 startingAt: 1;
replaceFrom: e3+1 to: e4 with: c4 startingAt: 1;
replaceFrom: e4+1 to: e5 with: c5 startingAt: 1;
yourself

What's the lesson here?  Just because A is faster than B doesn't mean
there isn't a fairly obvious C, D, ..., that will beat A.

Now what is the real argument in favour of StringBuilder in Java and
streamContents: in Smalltalk?

s := ''.
1 to: n do: [:i | s := s , 'X'].

makes a string of n Xs but takes O(n**2) time and turns over O(n**2) memory.

s := String streamContents: [:o | 1 to: n do: [:i | o nextPut: $X]

makes a string of n Xs while taking O(n) time and turning over O(n) memory.
n does not have to be very big before this gets to be a HUGE difference.

For what it's worth, the Java compiler turns a+b+c+d+e into code that creates
a StringBuilder, stuffs a ... e into it, and then pulls a string out.
There is no point
in benchmarking a fixed number of concatenations against a StringBuilder in
Java because they're the same thing.  Smalltalk compilers don't do that.

In Java and in Smalltalk you should seldom concatenation strings, but should
send the fragments directly to their final destination.  I've never
quite made up
my mind whether being toString()-centric was Java's biggest blunder or just the
second biggest, but it was a pretty darned big one for sure.  Smalltalk go this
right: #printOn: is the basic notion and #printString the derived and
best avoided
one.

On Sat, 16 Mar 2024 at 08:12, Noury Bouraqadi  wrote:
>
> I thought streamContents: was faster than using a comma binary message...
>
> I was wrong. Pharo is not Java :-)
>
> Noury
>
> "Run in P11"
>
> a := 'a'.
>
> b := 'b'.
>
> c := 'c'.
>
> d := 'd'.
>
> e := 'ee'.
>
> [ a , b , c , d , e ] bench.
>
> "'395.090 per second'"
>
> "'3808242.503 per second'"
>
>
> [
>
> String streamContents: [ :str |
>
> str
>
> << a;
>
> << b;
>
> << c;
>
> << d;
>
> << e ] ] bench

[Pharo-users] Re: Finding references to non existent classes in Pharo

2024-03-10 Thread Richard O'Keefe
I created a method referring to a non-existent "Snark" class.
To my astonishment, "Code Search|References to it" quietly failed to
do anything visible.
It didn't find it, and it didn't say that it couldn't find it.
However, "Code Search|Method source with it" DID find the reference.
Pharo 9 and Pharo 11 both do this, although the on-screen interface is
different.

In Squeak, "References to it" worked fine, BUT when I created the
method I wasn't
offered the option of leaving "Snark" undeclared; the closest was
"Declare global".

Smalltalk/X offered me the option of "Continue" with an undeclared variable,
and then "References to it" worked perfectly.



On Mon, 11 Mar 2024 at 01:43, Tim Mackinnon  wrote:
>
> Hi - I was convinced in earlier Pharo’s, if you had a code reference to a non 
> existent class you could find it by searching for references to its symbol 
> name eg #MyMissingClass allReferences (or find references in the UI). This 
> doesn’t seem to work in Pharo 11?  I loaded a package with a missing class, 
> and when running something it complained about the missing class (it was an 
> announcement), but I couldn't find an easy way to find it in my code to 
> correct it? I ended up creating the fake class to then find references to it 
> (as I then had a class), which seems way over the top?
>
> I haven't had a chance to try this in Pharo 12, but shouldn't what I have 
> done work? Or is there some new way to do this? I asked on Discord users, but 
> didn't get a reply other than it rang a bell.
>
> I know there has been a lot of work in the area of how things are represented 
> and I wonder if something has got broken by mistake?
>
> Tim


[Pharo-users] Re: "Print it" redirection

2024-02-21 Thread Richard O'Keefe
What stops you copy and paste?

Using ANSI Smalltalk, you'd do
   [:stream | stream print: 1000 factorial; cr; close] value:
(FileStream write: 'factorial.txt'.
Pharo has never provided an ANSI-compatible FileStream class, which is
a pain for
trying to write portable code.  In Pharo you have to write
  'factorial.txt' asFileReference writeStreamDo: [:stream | stream
print: 1000 factorial; cr].


In Pharo 9, you'd have to change #write: to #newFileNamed:.
I wanted to check this in Pharo 12, but PharoLauncher has stopped working.

On Tue, 20 Feb 2024 at 20:46, Rene Paul Mages (ramix)  wrote:
>
> Hello Pharo Community,
>
> Output unix-redirection like the following is very useful :
>
> ls -al ./Pharo > Pharo-dir.txt
>
> 
>
> I want to write in a file the "print-it" output of the following Pharo
> message :
>
>  1000 factorial
>
> Please give me a good track.
>
> 
>
>
> --
> All the best
> Rene Paul Mages (ramix) GnuPG key : 0x9840A6F7
> http://sites.google.com/view/les-logiciels-libres/pharo
> http://nosoftwarepatents.wikidot.com/smalltalk
> http://twitter.com/RenePaulMages


[Pharo-users] Re: A little post Why class number is an idiotic quality metric?

2024-02-10 Thread Richard O'Keefe
"First this is a stupid metrics because to have less code or less
classes is super easy just remove features. For example if you want to
have less classes in Pharo just remove the refactoring engine for
example and you will instantaneously less class. "

That's a straw man argument.  When people say that having a lot of
code or a lot of classes is a sign of poor design, they mean "a lot of
code/classes FOR WHAT IT DOES".  It's like me saying "hey, I can
typically rewrite a Java program in Smalltalk and use only about a
quarter as much code".  That carries the impicating "WITHOUT
sacrificing functionality.:"

Second, whether having a lot of classes is an indication of poor
design is an empirical question.  Whatever dogma says, it MIGHT be and
it might NOT be.  We should approach that by empirical software
engineering, looking at repository histories.  Is there a correlation
between class count and code churn or is there not?

For example, one way to get a lot of classes or methods or SLOC or
whatever is to reimplement something that's already in the library.
Doing your own persistence instead of using Fuel, maybe.  Another way
to get excess classes is to do an incomplete analysis and fail to
notice that two things are actually the same thing seen from different
perspectives.

On Sat, 10 Feb 2024 at 22:14, stephane ducasse
 wrote:
>
>
> https://wordpress.com/post/pharoweekly.wordpress.com/4226
>
>
> Stéphane Ducasse
> http://stephane.ducasse.free.fr
> 06 30 93 66 73
>
> "If you knew today was your last day on earth, what would you do differently? 
> ESPECIALLY if, by doing something different, today might not be your last 
> day on earth.” Calvin & Hobbes
>
>
>
>
>


[Pharo-users] Books about Pharo

2024-01-24 Thread Richard O'Keefe
This is a new thread because it's not limited to any specific topic.

If you have questions about Pharo, especially "how do I do  in
Pharo", you can always ask in this mailing list.  You can, if you like
playing Russian Roulette, ask a Large Language Model "AI".

But there is an amazing resource you should really trye.

books.pharo.org

Did you ever wonder where the manual for Pharo was?
That's where.  The site lists a bunch of Pharo books and booklets,
all of which have free PDFs except for two of the books.
In particular, you'll always want the most recent edition of
"Pharo by Example" handy.

These books are really useful.  They are written by people know know
their material thoroughly and do a good job of explaining it.  If you
want to make any serious use of Pharo, or even to have more happiness
than headaches just playing with it, you owe it to yourself to get the
free PDFs  What do we owe the authors?  Well, if you're not trying to
make one pension support four people, you owe them the purchase of
some of the books.  Me, I'm giving them thanks, praise, and a
heartfelt recommendation.

Seriously, these books represent a HUGE amount of work and "you are a
fool to yourself and a burden to others" if you don't take advantage
of this great resource.


[Pharo-users] Re: Iterating over a Dictionary

2024-01-24 Thread Richard O'Keefe
This has not changed since Smalltalk-80.  Running Smalltalk-80 and
looking in the browser, I see
Dictionary>>
do: aBlock
super do: [:assoc | aBlock value: assoc value].

'super' here is Set, a Dictionary being implemented as a Set of
Associations (which was always a bad idea).
Dictionary>>do: has ALWAYS iterated over the elements of a dictionary,
NOT the associatons.

I have Squeak, Pharo, Smalltalk-80, VisuaWorks, VisualAe, Smalltalk/X,
and GNU Smalltalk (plus several others including my own).
They all follow the ANSI standard in this respect.,  The distinction
between #do: and #associationsDo: goes back to Smalltalk-80,
as does #keysDo:.

On Wed, 24 Jan 2024 at 05:33, Joachim Tuchel  wrote:
>
> So there we already have dialect differences …
>
> Am 23.01.2024 um 17:32 schrieb James Foster via Pharo-users 
> :
>
> myDict associationsDo: [: anAssociation | ].
> myDict keysDo: [:aKey | ].
> myDict valuesDo: [:aValue | ].
> myDict do: [:aValue | ]. “An alias for #valuesDo:”
>
> James Foster
>
> On Jan 23, 2024, at 8:27 AM, Joachim Tuchel  wrote:
>
> AI knows little about Smalltalk ;-)
>
> You can use do: with each Association as a parameter or you can use 
> keysAndValuesDo:
>
> myDic do: [:assoc| | key value| key := assoc key. value := assoc value. ...].
>
> myDic keysAndValuesDo: [:key :value| ...]
>
>
> Joachim
>
>
>
> Am 23.01.24 um 17:24 schrieb sergio ruiz:
>
> I need to iterate over a dictionary.
>
> I asked the AI buddy for a little help, and he says:
>
> | myDictionary |
>
> "Create a dictionary"
> myDictionary := Dictionary new.
> myDictionary at: 'one' put: 1.
> myDictionary at: 'two' put: 2.
> myDictionary at: 'three' put: 3.
>
> "Iterate over the dictionary"
> myDictionary do: [ :key :value |
> Transcript show: key , ' -> ', value printString ; nl.
> ].
>
> but when i try this, I get:
>
> ArgumentsCountMismatch: This block accepts 2 arguments, but was called with 1 
> argument.
>
> Is the AI using a different dialect of smalltalk?
>
> how would I go about acting on each pair?
>
> Thanks!
>
> 
> peace,
> sergio
> photographer, journalist, visionary
>
> Public Key: 
> https://pgp.key-server.io/pks/lookup?op=get=0x69B08F58923AB3A2
> #BitMessage BM-NBaswViL21xqgg9STRJjaJaUoyiNe2dV
> @sergio_101@mastodon.social
> https://sergio101.com
> http://www.codeandmusic.com
> http://www.twitter.com/sergio_101
> http://www.facebook.com/sergio101
>
> --
>
> ---
> Objektfabrik Joachim Tuchel  mailto:jtuc...@objektfabrik.de
> Fliederweg 1 http://www.objektfabrik.de
> D-71640 Ludwigsburg  http://joachimtuchel.wordpress.com
> Telefon: +49 7141 56 10 86 0Fax: +49 7141 56 10 86 1
>
>


[Pharo-users] Re: Iterating over a Dictionary

2024-01-24 Thread Richard O'Keefe
Wrong.
If you want to iterate of the associations of a dictionary, you need
#associationsDo:.
#do: passes the *values* to the block, *NOT* the associations.

On Wed, 24 Jan 2024 at 05:28, Joachim Tuchel  wrote:
>
> AI knows little about Smalltalk ;-)
>
> You can use do: with each Association as a parameter or you can use 
> keysAndValuesDo:
>
> myDic do: [:assoc| | key value| key := assoc key. value := assoc value. ...].
>
> myDic keysAndValuesDo: [:key :value| ...]
>
>
> Joachim
>
>
>
> Am 23.01.24 um 17:24 schrieb sergio ruiz:
>
> I need to iterate over a dictionary.
>
> I asked the AI buddy for a little help, and he says:
>
> | myDictionary |
>
> "Create a dictionary"
> myDictionary := Dictionary new.
> myDictionary at: 'one' put: 1.
> myDictionary at: 'two' put: 2.
> myDictionary at: 'three' put: 3.
>
> "Iterate over the dictionary"
> myDictionary do: [ :key :value |
> Transcript show: key , ' -> ', value printString ; nl.
> ].
>
> but when i try this, I get:
>
> ArgumentsCountMismatch: This block accepts 2 arguments, but was called with 1 
> argument.
>
> Is the AI using a different dialect of smalltalk?
>
> how would I go about acting on each pair?
>
> Thanks!
>
> 
> peace,
> sergio
> photographer, journalist, visionary
>
> Public Key: 
> https://pgp.key-server.io/pks/lookup?op=get=0x69B08F58923AB3A2
> #BitMessage BM-NBaswViL21xqgg9STRJjaJaUoyiNe2dV
> @sergio_101@mastodon.social
> https://sergio101.com
> http://www.codeandmusic.com
> http://www.twitter.com/sergio_101
> http://www.facebook.com/sergio101
>
> --
>
> ---
> Objektfabrik Joachim Tuchel  mailto:jtuc...@objektfabrik.de
> Fliederweg 1 http://www.objektfabrik.de
> D-71640 Ludwigsburg  http://joachimtuchel.wordpress.com
> Telefon: +49 7141 56 10 86 0Fax: +49 7141 56 10 86 1
>


[Pharo-users] Re: Iterating over a Dictionary

2024-01-24 Thread Richard O'Keefe
There are many books about Smalltalk.  Stephane Ducasse has made many
of them available as FREE pdfs.
Of course Pharo by Example would be a good start.  The latest edition
of Pharo by Example I have ready to hand is 8.0, 2020, where what you
want is chapter 13, Collections.

aCollection do: [:element | ...]

aKeyedCollection keysAndValuesDo: [:key :element | ...]

dictionaries are keyed and so are sequences.  You can iterate over the
elements of any collection using #do: with a one-argument block.  The
elements will be passed to the block and the keys will NOT.  If you
want the keys, must use #keysAndValuesDo: with a two-argument block.
The keys and corresponding elements will be passed to the block.

You "AI buddy" is a treacherous lying ignorant bastard.  Such is the
start of AI.

1.  Open a browser on Dictionary.
2. Select "enumerating" the the method category panel (top row, third
from left).
3. In the method panel (top row, rightmost) you will see do:
keysAndValuesDo: keysDo: valuesDo:
4. Selecting them one at a time you will see

do: aBlock
  ^self valuesDo: aBlock
keysAndValuesDo: aBlock
  ^self associationsDo: [:assoc |
aBlock value: assoc key value: assoc value]
keysDo: aBlock
  ^self associationsDo:: [:association |
 aBlock value: associatoin key]
valuesDo: aBlock
  tally = 0 ifTrue: [^self].
  1 to: array size do: [:eachIndex |
|eachAssociation|
eachAssociation := array at: eachIndex.
nil == eachAssociation ifFalse: [
  aBlock value: eachAssociation value]].

Now to fully make sense of this, you'd have to understand how a
Dictionary is implemented in Pharo.  (An Array whose elements are
reach either nil or an Association holding a key and a value.  This is
a traditional Smalltalk implementation of dictionaries, but others
except and some are better.)  But you CAN see quite easily from this
code that #do:, #keysDo:, and #valuesDo: pass just one value to their
block argument, while #keysAndValuesDo: passes TWO values.  And this
is typicalk of trying to glean understanding by looking at the system
source code:  it is easy, you won't undersand everything, but you'll
learn *something*.







On Wed, 24 Jan 2024 at 05:24, sergio ruiz  wrote:
>
> I need to iterate over a dictionary.
>
> I asked the AI buddy for a little help, and he says:
>
> | myDictionary |
>
> "Create a dictionary"
> myDictionary := Dictionary new.
> myDictionary at: 'one' put: 1.
> myDictionary at: 'two' put: 2.
> myDictionary at: 'three' put: 3.
>
> "Iterate over the dictionary"
> myDictionary do: [ :key :value |
> Transcript show: key , ' -> ', value printString ; nl.
> ].
>
> but when i try this, I get:
>
> ArgumentsCountMismatch: This block accepts 2 arguments, but was called with 1 
> argument.
>
> Is the AI using a different dialect of smalltalk?
>
> how would I go about acting on each pair?
>
> Thanks!
>
> 
> peace,
> sergio
> photographer, journalist, visionary
>
> Public Key: 
> https://pgp.key-server.io/pks/lookup?op=get=0x69B08F58923AB3A2
> #BitMessage BM-NBaswViL21xqgg9STRJjaJaUoyiNe2dV
> @sergio_101@mastodon.social
> https://sergio101.com
> http://www.codeandmusic.com
> http://www.twitter.com/sergio_101
> http://www.facebook.com/sergio101
>


[Pharo-users] Re: Troubleshooting ByteArray

2024-01-17 Thread Richard O'Keefe
So the method is expecting some kind of string, but it received a
ByteArray, which is NOT any kind of string.
What's in the ByteArray?  Where did it come from?  Why isn't it a string?

On Thu, 18 Jan 2024 at 04:34, sergio ruiz  wrote:
>
> Hi, all.
>
> I am working on creating a PDF with Artefact 
> (https://github.com/pharo-contributions/Artefact) and am having an issue 
> running the first example.
>
> the Example looks like:
>
> PDFDocument new add: (PDFPage new add: (PDFTextElement new text: 'Hello'; 
> from: 10mm@10mm)); exportTo: 'test.pdf' asFileReference writeStream.
>
>
> When running this, I get the error:
>
> Instance of ByteArray did not understand #isByteString
>
> indeed, ByteArray does not have a method called isByteString.
>
> I have tried creating a method that returns either true or false (I tried 
> them both), but I have not successfully built the PDF.
>
> The method calling isByteString looks like:
>
>
> ZnUTF8Encoder
>
> next: count putAll: string startingAt: offset toStream: stream
> "Write count characters from string starting at offset to stream."
> "Overwritten for performance reasons - create a fast path for byte strings"
>
> string isByteString
> ifTrue: [ self next: count putAllByteString: string startingAt: offset 
> toStream: stream ]
> ifFalse: [ super next: count putAll: string startingAt: offset toStream: 
> stream ]
>
> I TOTALLY get this. This is a whole bunch of very specific questions. But my 
> ultimate goal is to take a deep dive into stream processing to figure this 
> out.
>
> Thanks!
>
> 
> peace,
> sergio
> photographer, journalist, visionary
>
> Public Key: 
> https://pgp.key-server.io/pks/lookup?op=get=0x69B08F58923AB3A2
> #BitMessage BM-NBaswViL21xqgg9STRJjaJaUoyiNe2dV
> @sergio_101@mastodon.social
> https://sergio101.com
> http://www.codeandmusic.com
> http://www.twitter.com/sergio_101
> http://www.facebook.com/sergio101
>


[Pharo-users] Re: [ Security ] Accessing private information from Pharo image

2024-01-17 Thread Richard O'Keefe
Back in the days when an entire department would share something like
a VAX and think themselves
lucky, the advance was never to let secrets *rest* in your address
space any longer than you had to.
Bring the secret into memory just the instant before you need it, use
it, then scrub that area of
memory. You might want to put the credentials on a thumb drive which
is plugged in only when needed,
I've generally found it better for environment variables to contain
file names pointing to configuration
files than to have then hold the configuration information directly.

On Wed, 17 Jan 2024 at 22:31, Norbert Hartl  wrote:
>
>
>
> > Am 17.01.2024 um 05:27 schrieb sergio ruiz :
> >
> > Hi, all.
> >
> > One of my projects logs in to Spaces (Digital Ocean’s version of S3). I 
> > need to be able access the credentials, but I don’t want to store them in 
> > the source code, as I will be using Github to store the projects.
> >
> > Is there an accepted way to do this (encryption)?
> >
> > Should I store them on the system as environment variables? is this 
> > efficient?
>
> One of the usualy ways especially on unix systems is to hand credentials in 
> via the process environment. If you execute
>
> OSEnvironment current at: ‚SHELL'
>
> in a playground you should see somthing like ‚/bin/bash‘. So when starting 
> the process you just need to specify the environment variables so that pharo 
> can access it. If you use docker there is a way to specify that easily.
>
> Norbert


[Pharo-users] Re: Smallscript - A Smalltalk-Inspired Scripting Language

2023-12-28 Thread Richard O'Keefe
Does anyone else remember F-Script?  A "Smalltalk-inspired scripting
language" for MacOS X,
providing full interoperation with Objective C and the whole Cocoa
frameworks system.
The last update was 5 years ago, which is a pity, because
1. It was so well integrated with MacOS X (as it was then) that it
needs rebuilding wih each macOS release.
2. It was so well integrated with MacOS X that it was restricted to
MacOS X; there wasn't anything to port to Windows or Unix.
3. It was Smalltalk - *inspired* but not Smalltalk, so there was no
flow of ideas or code between Smalltalk and F-Script.
For example, there never was an SUnit for F-Script.

Does anyone else remember Susie?  (Scripting using a Smalltalk
Interpreter engine.)  I've been meaning to fix the problem with a
64-bit build but wondering who to tell.  It seems as if reviving Susie
or GST ought to pay off more sooner than starting from scratch.

If you want a "class-less" language inspired by Smalltalk with
minimalist syntax, you really MUST look at Self.
I used to use XLisp/Stat a lot, and while I loved it, I can't say that
not having classes struck me as a strength.
Curly braces trace back to BCPL -- which I once set out to write a
compiler for.  They were and are a bad idea.
If you want a scripting language inspired by JavaScript, with braces
and sans classes,
may I suggest JavaScript?  It satisfies 8 out of your criteria
out-of-the-box, and node.js with a vast library of stuff to script
with, including testing frameworks, already exists.  I'm not sure if
it satisfies criterion 6 or not, but then I'm not sure what criterion
6 means or why you would care.

There are programming languages I dislike *as* languages but use for
the sake of the libraries they give me access to,
S, for example, ticks quite a few of your boxes.  As a language, it's
pretty awful.  (In large part *because* it ticks those boxes.)
BUT the packages!  Oh gosh, the *packages* !
All the work I don't have to do!  All the work I *COULDN'T* have done!

So, one approach is to build your new teenage mutant ninja scripting
language on top of something like node.js.  Go nuts with your syntax,
but make the data structures fully JavaScript-compatible so that you
can use existing npm packages from your language.

I wish GNU Smalltalk were still maintained.  One day I must try to
figure out why printing floats crashes.

On Sat, 2 Dec 2023 at 00:11, Craig Johnson  wrote:
>
> for those who are interested.
>
> https://www.codeproject.com/Articles/5373567/Smallscript-A-Smalltalk-Inspired-Scripting-Languag
>


[Pharo-users] Re: The worst programmer

2023-09-05 Thread Richard O'Keefe
>From a similar personal experience, sometimes the team
leader speaks up for you and the manager fires you anyway.

On Tue, 5 Sept 2023 at 22:07, Guillermo Polito 
wrote:

> Haha, yes, it was a fun read, congrats Tim! :D
>
> El 5 sep. 2023, a las 10:03, Noury Bouraqadi 
> escribió:
>
> Glad you pointed it Christian.
> I saw the title on X, and since I know Tim, I thought it was a troll 
>
> Noury
> On Sep 4 2023, at 4:58 pm, Christian Haider 
> wrote:
>
> Today there was a link in the Daily Insider [1] to a really nice blog post
> [2] featuring Tim Mackinnon as the worst programmer.
>
> Congratulations Tim J
>
>
>
> Cheers,
>
> Christian
>
>
>
> [1]
> https://www.codeproject.com/script/Mailouts/View.aspx?mlid=17447&_z=13433946
>
> [2] https://dannorth.net/2023/09/02/the-worst-programmer/
>
>
>
>
>
>
>


[Pharo-users] Re: Picking neighbouring elements

2023-04-24 Thread Richard O'Keefe
There is a much newer version.  I've made some minor corrections today.
I really must put it up on github.
Let me get back to you about that.

On Sat, 22 Apr 2023 at 18:57, Bernhard Pieber  wrote:

> Hi Richard,
>
> I really liked your concise description about what is the point of using
> an object-oriented language. It made my day.
>
> I searched the Web for your Smalltalk library and found this link:
> http://www.cs.otago.ac.nz/staffpriv/ok/astc-1711.tar.gz
>
> Is there a newer version available somewhere?
>
> Cheers,
> Bernhard
>
>
> Am 22.04.2023 um 00:51 schrieb Richard O'Keefe :
>
> I'm sorry, it appears that I failed to explain the question
> well enough.  I thought I'd explained earlier.
>
> successor: target
>   ^(self select: [:each | target < each]) min
>
> is trivial.  What's wrong with it is that it allocates
> an intermediate collection and takes two passes.
> FIXING that is is also trivial.
>
> successor: target
>   ^(self virtualSelect: [:each | target < each]) min
>  ^^^
>
> This does allocate something, but it's just a few words,
> and a single traversal is one.
>
> In other languages/contexts we'd be talking about
> loop fusion/listless transformation/deforestation.
> It is my understanding that using Transducers would
> get me *this* level of improvement.
>
> The problem is that this is still a linear-time
> algorithm.  If you take advantage of the order in
> a SortedCollection or SortedSet,it can take logarithmic
> time.  When SortedSet is implemented as a splay tree
> -- as it is in my library -- iterating over all its
> elements using #successor: is amortised CONSTANT time
> per element.  So we need THREE algorithms:
>  - worst case O(n)  select+min
>  - worst case O(lg n)  binary search
>  - amortised O(1)  splaying
> and we want the algorithm selection to be
>
>A U T O M A T I C.
>
> That's the point of using an object-oriented language.
> I say what I want done and the receiver decides how to
> do it.  Anything where I have to write different
> calling code depending on the structure of the receiver
> doesn't count as a solution.
>
> Now we come to the heart of the problem.
> The binary search algorithm is NOT a special case
> of the linear search algorithm.  It is not made of
> pieces that can be related to the parts of the linear
> search algorithm.
> The splaying algorithm is NOT a special case of the
> linear search algorithm OR the binary search algorithm.
> It is not made of pieces that can be related to their
> parts.
>
> So *IF* I want automatic selection of an appropriate
> algorithm, then I have to rely on inheritance and
> overriding, and in order to do that I have to have
> a named method that *can* be overridden, and at that
> point I'm no longer building a transducer out of
> pluggable pieces.
>
> So that's the point of this exercise.
> How do we get
> (a) composition of transducers out of pluggable parts
> AND
> (b) automatic selection of appropriate algorithms
>
>
> On Fri, 21 Apr 2023 at 20:35, Steffen Märcker  wrote:
>
>> Hi Richard,
>>
>> Now that's much clearer to me:
>> min{y | y in c . y > x} "strict supremum"
>> max{y | y in c . y < x} "strict infimum"
>>
>> For the general case of a sequence (not sorted) of elements we can do
>>
>> strictSupremumOf: x in: sequence
>>
>> ^(sequence transduce filter: [:y | y > x]) "virtual sequence"
>> inject: nil
>> into: [:min :b | min ifNotNil: [:a | a min: b]]
>>
>> I just picked a variant of minimum that answers nil if no element is
>> found. Other variants would work, too.
>> The focus of transducers is on re-use and composition of processing
>> steps. We can break this up into steps if needed:
>>
>> minimum := [:min :b | min ifNotNil: [:a | a min: b]] init: nil.
>> "reduction"
>> upperBounds := Filter predicate: [:y | y > x]. "transducer"
>> strictSup := minimum transduce: upperBounds. "transformed reduction"
>> ^strictSup reduce: sequence
>>
>> We can also use a different notation similar to a data flow:
>>
>> minimum <~ upperBounds <~ sequence
>>
>> Of course, if we know how the sequence is sorted, we should use another
>> algorithm. Assuming an ascending order with no random access, we'd change
>> minimum to stop early:
>>
>> minimum := [:min :b | Stop result: b].
>>
>> Kind regards,
>> Steffen
>>
>>
>> Richard O'Keefe schrieb am Freitag, 21. April 2023 05:33:44 (+02:00):
>>
>> successor of x in c = the smallest element

[Pharo-users] Re: Picking neighbouring elements

2023-04-21 Thread Richard O'Keefe
I'm sorry, it appears that I failed to explain the question
well enough.  I thought I'd explained earlier.

successor: target
  ^(self select: [:each | target < each]) min

is trivial.  What's wrong with it is that it allocates
an intermediate collection and takes two passes.
FIXING that is is also trivial.

successor: target
  ^(self virtualSelect: [:each | target < each]) min
 ^^^

This does allocate something, but it's just a few words,
and a single traversal is one.

In other languages/contexts we'd be talking about
loop fusion/listless transformation/deforestation.
It is my understanding that using Transducers would
get me *this* level of improvement.

The problem is that this is still a linear-time
algorithm.  If you take advantage of the order in
a SortedCollection or SortedSet,it can take logarithmic
time.  When SortedSet is implemented as a splay tree
-- as it is in my library -- iterating over all its
elements using #successor: is amortised CONSTANT time
per element.  So we need THREE algorithms:
 - worst case O(n)  select+min
 - worst case O(lg n)  binary search
 - amortised O(1)  splaying
and we want the algorithm selection to be

   A U T O M A T I C.

That's the point of using an object-oriented language.
I say what I want done and the receiver decides how to
do it.  Anything where I have to write different
calling code depending on the structure of the receiver
doesn't count as a solution.

Now we come to the heart of the problem.
The binary search algorithm is NOT a special case
of the linear search algorithm.  It is not made of
pieces that can be related to the parts of the linear
search algorithm.
The splaying algorithm is NOT a special case of the
linear search algorithm OR the binary search algorithm.
It is not made of pieces that can be related to their
parts.

So *IF* I want automatic selection of an appropriate
algorithm, then I have to rely on inheritance and
overriding, and in order to do that I have to have
a named method that *can* be overridden, and at that
point I'm no longer building a transducer out of
pluggable pieces.

So that's the point of this exercise.
How do we get
(a) composition of transducers out of pluggable parts
AND
(b) automatic selection of appropriate algorithms


On Fri, 21 Apr 2023 at 20:35, Steffen Märcker  wrote:

> Hi Richard,
>
> Now that's much clearer to me:
> min{y | y in c . y > x} "strict supremum"
> max{y | y in c . y < x} "strict infimum"
>
> For the general case of a sequence (not sorted) of elements we can do
>
> strictSupremumOf: x in: sequence
>
> ^(sequence transduce filter: [:y | y > x]) "virtual sequence"
> inject: nil
> into: [:min :b | min ifNotNil: [:a | a min: b]]
>
> I just picked a variant of minimum that answers nil if no element is
> found. Other variants would work, too.
> The focus of transducers is on re-use and composition of processing steps.
> We can break this up into steps if needed:
>
> minimum := [:min :b | min ifNotNil: [:a | a min: b]] init: nil.
> "reduction"
> upperBounds := Filter predicate: [:y | y > x]. "transducer"
> strictSup := minimum transduce: upperBounds. "transformed reduction"
> ^strictSup reduce: sequence
>
> We can also use a different notation similar to a data flow:
>
> minimum <~ upperBounds <~ sequence
>
> Of course, if we know how the sequence is sorted, we should use another
> algorithm. Assuming an ascending order with no random access, we'd change
> minimum to stop early:
>
> minimum := [:min :b | Stop result: b].
>
> Kind regards,
> Steffen
>
>
> Richard O'Keefe schrieb am Freitag, 21. April 2023 05:33:44 (+02:00):
>
> successor of x in c = the smallest element of c that is larger than x
>  min {y | y in c . y > x}
> predecessor of x in c = the largest element of c that is smaller than x
>  max {y | y in c . y < x}
>
> On Thu, 20 Apr 2023 at 21:08, Steffen Märcker  wrote:
>
>> Dear Richard,
>>
>> thanks for that additional piece. I'll put insert- on my list
>> of possible variants. I think we come back to naming after the initial port
>> is done and everyone can play with it. Generally, I made the observation to
>> better be careful with names since it's too easy to alienate other or
>> trigger wrong assumptions.
>>
>> New  topic! (quote below)
>>
>> Honestly, my knowledge of Haskell is rather limited and rusted. Hence, I
>> am having difficulties understanding what exactly these operations with a
>> sequence of elements. Can you give an example or some pseude/smalltalk code
>> from your use-case and library?
>>
>> Kind regards
>>
>>
>> Changing the subject a wee bit, there's an operation family
>> in my library, and I wonder how it 

[Pharo-users] Re: Picking neighbouring elements

2023-04-20 Thread Richard O'Keefe
successor of x in c = the smallest element of c that is larger than x
 min {y | y in c . y > x}
predecessor of x in c = the largest element of c that is smaller than x
 max {y | y in c . y < x}

On Thu, 20 Apr 2023 at 21:08, Steffen Märcker  wrote:

> Dear Richard,
>
> thanks for that additional piece. I'll put insert- on my list
> of possible variants. I think we come back to naming after the initial port
> is done and everyone can play with it. Generally, I made the observation to
> better be careful with names since it's too easy to alienate other or
> trigger wrong assumptions.
>
> New  topic! (quote below)
>
> Honestly, my knowledge of Haskell is rather limited and rusted. Hence, I
> am having difficulties understanding what exactly these operations with a
> sequence of elements. Can you give an example or some pseude/smalltalk code
> from your use-case and library?
>
> Kind regards
>
>
> Changing the subject a wee bit, there's an operation family
> in my library, and I wonder how it would fit into Transducers?
> To avoid bias, here's a specification in Haskell (for lists,
> because I haven't had any luck installing Data.Witherable).
>
> uccessorBy, predecessorBy :: (a -> a -> Ordering) -> a -> [a] -> a
> successor,   predecessor   :: Ord a=> a -> [a] -> a
>
> successor = successorBy compare
>
> successorBy cmp x = minimumBy cmp . filter (\y -> cmp x y == LT)
>
> predecessor = predecessorBy compare
>
> predecessorBy cmp = successorBy (flip cmp)
>
> The reason these operations exist is to pick neighbouring
> elements in SortedCollections and SortedSets.  But they make
> *sense* for any Enumerable.  So there are "generic"
> definitions with orderrides for those two classes.
>
> A filter + a reduce .  Traditionally, a #select:thenFold:ifNone:
> in order to avoid building an intermediate collection.  That much
> I see how to do with transducers.  But you can't get the desired
> override for #successor:[sortBlock:][ifNone:] by overriding
> #select:thenFold:ifNone: in SortedCollection or SortedSet.  So what
> *should* one do?
>
>


[Pharo-users] Re: Collection>>reduce name clash with transducers

2023-04-20 Thread Richard O'Keefe
I've always called the block in #inject:into: the *combining* function.
Perhaps the reason I don't think of it as a "reducing" function is that
setOfSets inject: Set new into: [:acc :each | acc union: each]
has a block that combines its arguments in a way that makes the result
bigger, not smaller.  For what it's worth, Backus used "insert":

*insert-right*  /*f*   where   /*f*:〈*x*〉 =  *x*
   and /*f*:〈*x*1,*x*2,...,*x*n〉  =
*f*:〈*x*1,/*f*:〈*x*2,...,*x*n〉〉
   and /*f*:〈 〉 =  *unit f*

*insert-left*  \*f*   where   \*f*:〈*x*〉 =  *x*
  and \*f*:〈*x*1,*x*2,...,*x*n〉  =
*f*:〈\*f*:〈*x*1,...,*x*n-1〉,*x*n〉
  and \*f*:〈 〉 =  *unit f*
--- https://en.wikipedia.org/wiki/FP_(programming_language)

Every day spent debating the words is another day the software isn't
getting used,
so I'm sorry about prolonging this.  Some names are just too confusing.
Some years ago, I found it useful to add
  {value:}...{optionalValue:}...
to my library for passing arguments that the receiver may
choose to ignore.  (The methods are exactly as direct as
the {value:}... methods, no extra allocations or anything.)
About the same time, Pharo independenty added {cull:}...
but it was years before I noticec, because "cull" to me
means either (a) to slaughter a large proportion of a
population of wild or domestic anmals, or (b) to gather
information from a large number of sources.  (The concept
"reap" is lurking somewhere in the background.)  I don't
know who came up with that name for pass-optional-argument,
but it grates so much I can't bring myself to use it and
just make do without optional parameters in Pharo.  In
fact it was this example that was at the back of my mind.

Changing the subject a wee bit, there's an operation family
in my library, and I wonder how it would fit into Transducers?
To avoid bias, here's a specification in Haskell (for lists,
because I haven't had any luck installing Data.Witherable).

uccessorBy, predecessorBy :: (a -> a -> Ordering) -> a -> [a] -> a
successor,   predecessor   :: Ord a=> a -> [a] -> a

successor = successorBy compare

successorBy cmp x = minimumBy cmp . filter (\y -> cmp x y == LT)

predecessor = predecessorBy compare

predecessorBy cmp = successorBy (flip cmp)

The reason these operations exist is to pick neighbouring
elements in SortedCollections and SortedSets.  But they make
*sense* for any Enumerable.  So there are "generic"
definitions with orderrides for those two classes.

A filter + a reduce .  Traditionally, a #select:thenFold:ifNone:
in order to avoid building an intermediate collection.  That much
I see how to do with transducers.  But you can't get the desired
override for #successor:[sortBlock:][ifNone:] by overriding
#select:thenFold:ifNone: in SortedCollection or SortedSet.  So what
*should* one do?


[Pharo-users] Re: Collection>>reduce name clash with transducers

2023-04-15 Thread Richard O'Keefe
.
> distinct trim.
>
> For some cases it turns out to be useful to have an object that knows how
> to do both:
>
> distinct := col reduce: (#add completing: #trim) init: Set new.
>
> #reduce:init: knows how to deal with both this new objects and ordinary
> blocks. For now I will call both variants a "reducing function". Note,
> completion is completely optional and the implementation is literally
> #inject:into: plus completion if required.
>
>
> 2. What is a reduction? In some cases, it turns out to be useful to pair
> up a reducing function with an (initial) value. You called it a magma and
> often its indeed the neutral element of a mathematical operator, e.g., +
> and 0. But we can use a block that yields the initial value, too. For
> instance:
>
> sum := #+ init: 0.
> result := numbers reduce: sum.
>
> toSet := (#add completing: #trim) initializer: [Set new].
> distinct := col reduce: toSet.
>
> #reduce: is just a shorthand that passes the function and the value to
> #reduce:init: Maybe #reduceMagma: is a reasonable name?
>
>
> 3. The reason I implemented #reduce:init: directly on collections,
> streams, etc. is that these objects know best how to efficiently iterate
> over their elements. And if a data structure knows how to #reduce:init: we
> can use it with all the transducers functions, e.g., for partitioning,
> filtering etc. Other useful methods  could then be added to the behaviour
> with a trait, e.g., #transduce:reduce:init which first apples a transducer
> and then reduces. As traits are not available in plain VW 8.3, I did not
> try this approach, though.
>
>
> 4. Lets take #reduce:Left: as and example and reimplement the method using
> transducers, shall we? The following code works for each
> sequence/collection/stream that supports #transduce:reduce:init:
>
> reduceLeft: aBlock
> | head rest arity |
> head := self transduce: (Take number: 1) reduce: [:r :e | e] init: nil.
> rest := Drop number: 1.
>
> arity := aBlock arity.
> ^arity = 2
> ifTrue: [self transduce: rest reduce: aBlock init: head]
> ifFalse: [
> | size arguments |
> size := arity - 1.
> rest := rest * (Partition length: size) * (Remove predicate: [:part | part
> size < size]).
> arguments := Array new: arity.
> arguments at: 1 put: head.
> self
> transduce: rest
> reduce: ([:args :part |
> args
> replaceFrom: 2 to: arity with: part;
> at: 1 put: (aBlock valueWithArguments: args);
> yourself] completing: [:args | args first])
> init: arguments]
>
> This code is both more general and faster: It does not create an
> intermediate OrderedCollection and it treats the common case of binary
> blocks efficiently. Note the implementation can more compact and optimized
> if it was specialized in certain class. For instance,
> SequenceableCollection allows accessing elements by index which turns the
> first line into a simple "self first".
>
> Thanks for staying with me for this long reply. I hope I did not miss a
> point. I do not insist on the existing names but will appreciate any ideas.
>
> Best, Steffen
>
>
>
>
> Richard O'Keefe schrieb am Freitag, 14. April 2023 09:43:32 (+02:00):
>
> #reduce: aReduction
>Are you saying that aReduction is an object from which
>a dyadic block and an initial value can be derived?
>That's going to confuse the heck out of Dolphin and Pharo
>users (like me, for example).  And in my copy of Pharo,
>#reduce: calls #reduceLeft:, not #foldLeft:.
>The sad thing about #reduceLeft: in Pharo is that in order
>to provide extra generality I have no use for, it fails to
>provide a fast path for the common case of a dyadic block.
>
> reduceLeft: aBlock
>   aBlock argumentCount = 2 ifTrue: [
> |r|
> r := self first.
> self from: 2 to: self last do: [:each |
>   r := aBlock value: r value: each].
> ^r].
> ... everything else as before ...
>
> Adding up a million floats takes half the time using the
> fast path (67 msec vs 137 msec).  Does your #reduce:
> also perform "a completion action"?  If so, it definitely
> should not be named after #inject:into:.
>
>
>
> At any rate, if it does something different, it should have
> a different name, so #reduce: is no good.
>
> #reduce:init:
>   There's a reason why #inject:into: puts the block argument
>   last.  It works better to have "heavy" constituents on the
>   right in an English sentence, and it's easier to indent
>   blocks when they come last.
>
>   Which of the arguments here specifies the 'completion action'?
>   What does the 'completion action' do?  (I can't tell from the name.)
>
> I think the answer 

[Pharo-users] Re: Collection>>reduce name clash with transducers

2023-04-14 Thread Richard O'Keefe
#reduce: aReduction
   Are you saying that aReduction is an object from which
   a dyadic block and an initial value can be derived?
   That's going to confuse the heck out of Dolphin and Pharo
   users (like me, for example).  And in my copy of Pharo,
   #reduce: calls #reduceLeft:, not #foldLeft:.
   The sad thing about #reduceLeft: in Pharo is that in order
   to provide extra generality I have no use for, it fails to
   provide a fast path for the common case of a dyadic block.

reduceLeft: aBlock
  aBlock argumentCount = 2 ifTrue: [
|r|
r := self first.
self from: 2 to: self last do: [:each |
  r := aBlock value: r value: each].
^r].
... everything else as before ...

Adding up a million floats takes half the time using the
fast path (67 msec vs 137 msec).  Does your #reduce:
also perform "a completion action"?  If so, it definitely
should not be named after #inject:into:.



At any rate, if it does something different, it should have
a different name, so #reduce: is no good.

#reduce:init:
  There's a reason why #inject:into: puts the block argument
  last.  It works better to have "heavy" constituents on the
  right in an English sentence, and it's easier to indent
  blocks when they come last.

  Which of the arguments here specifies the 'completion action'?
  What does the 'completion action' do?  (I can't tell from the name.)

I think the answer is clear:
* choose new intention-revealing names that do not clash.

If I have have understood your reduce: aReduction correctly,
a Reduction specifies
 - a binary operation (not necessarily associative)
 - a value which can be passed to that binary operation
which suggests that it represents a magma with identity.
By the way, it is not clear whether
 {x} reduce: <>
answers x or binop value: ident value: x.
It's only when ident is an identity for binop that you
can say 'it doesn't matter'.
I don't suppose you could bring yourself to call
aReduction aMagmaWithIdentity?

Had you considered
  aMagmaWithIdentity reduce: aCollection
where the #reduce: method is now in your class so
can't *technically* clash with anything else?
All you really need from aCollection is #do: so
it could even be a stream.

MagmaWithIdentity
>> identity
>> combine:with:
>> reduce: anEnumerable
 |r|
 r := self identity.
 anEumerable do: [:each | r := self combine: r with: each].
 ^r

MagmaSansIdentity
>> combine:with:
>> reduce: anEnumerable
 |r f|
 f := r := nil.
 anEnumerable do: [:each |
   r := f ifNil: [f := self. each] ifNotNil: [self combine: r with:
each]].
 f ifNil: [anEnumerable error: 'is empty'].
 ^r




On Fri, 14 Apr 2023 at 05:02, Steffen Märcker  wrote:

> The reason I came up with the naming question in the first place is that I
> (finally !) finish my port of Transducers to Pharo. But currently, I am
> running into a name clash. Maybe you have some good ideas how to resolve
> the following situation in a pleasant way.
>
> - #fold: exists in Pharo and is an alias of #reduce:
> - #reduce: exists in Pharo and calls #foldLeft: which also deals with more
> than two block arguments
>
> Both of which are not present in VW. Hence, I used the following messages
> in VW with no name clash:
>
> - #reduce: aReduction "= block + initial value"
> - #reduce:init: is similar to #inject:into: but executes an additional
> completion action
>
> Some obvious ways to avoid a clash in Pharo are:
>
> 1) Make #reduce: distinguish between a reduction and a simple block (e.g.
> by double dispatch)
> 2) Rename the transducers #reduce: to #injectInto: and adapt #inject:into:
> to optionally do the completion
> 3) Find another selector that is not too counter-intuitive
>
> All three approaches have some downsides in my opinion:
> 1) Though straight forward to implement, both flavors behave quite
> different, especially with respect to the number of block arguments. The
> existing one creates a SequenceableCollection and partitions it according
> to the required number of args. Transducers' #reduce: considers binary
> blocks as the binary fold case but ternary blocks as fold with indexed
> elements.
> 2) This is a real extension of #inject:into: but requires to touch
> multiple implementations of that message. Something I consider undesirabe.
> 3) Currently, I cannot think of a good name that is not too far away from
> what we're familiar with.
>
> Do you have some constructive comments and ideas?
>
> Kind regards,
> Steffen
>
>
>
>
> Steffen Märcker schrieb am Donnerstag, 13. April 2023 17:11:15 (+02:00):
>
> :-D I don't know how compress made onto that site. There is not even an
> example in the list of language examples where fold/reduce is named
> compress.
>
>
> Richard O'Keefe schrieb am Donnerstag, 13. Apr

[Pharo-users] Re: Collection>>reduce naming

2023-04-13 Thread Richard O'Keefe
OUCH.  Wikipedia is as reliable as ever, I see.
compress and reduce aren't even close to the same thing.
Since the rank of the result of compression is the same
as the rank of the right operand, and the rank of the
result of reducing is one lower, they are really quite
different.  compress is Fortran's PACK.
https://gcc.gnu.org/onlinedocs/gfortran/PACK.html

On Fri, 14 Apr 2023 at 01:34, Steffen Märcker  wrote:

> Hi Richard and Sebastian!
>
> Interesting read. I obviously was not aware of the variety of meanings for
> fold/reduce. Thanks for pointing this out. Also, in some languages it seems
> the same name is used for both reductions with and without an initial
> value. There's even a list on WP on the matter:
> https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29#In_various_languages
>
> Kind regards,
> Steffen
>
> Richard O'Keefe schrieb am Donnerstag, 13. April 2023 13:16:28 (+02:00):
>
> The standard prelude in Haskell does not define anything
> called "fold".  It defines fold{l,r}{,1} which can be
> applied to any Foldable data (see Data.Foldable).  For
> technical reasons having to do with Haskell's
> non-strict evaluation, foldl' and foldr' also exist.
> But NOT "fold".
>
>
> https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Foldable.html#laws
>
>
> On Thu, 13 Apr 2023 at 21:17, Sebastian Jordan Montano <
> sebastian.jor...@inria.fr> wrote:
>
>> Hello Steffen,
>>
>> Let's take Kotlin documentation (
>> https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce)
>>
>> > The difference between the two functions is that fold() takes an
>> initial value and uses it as the accumulated value on the first step,
>> whereas the first step of reduce() uses the first and the second elements
>> as operation arguments on the first step.
>>
>> Naming is not so consistent in all the programming languages, they mix up
>> the names "reduce" and "fold". For example in Haskell "fold" does not take
>> an initial value, so it is like a "reduce" in Kotlin. In Kotlin, Java,
>> Scala and other oo languages "reduce" does not take an initial value while
>> "fold" does. Pharo align with those languages (except that out fold is
>> called #inject:into:)
>>
>> So for me the Pharo methods #reduce: and #inject:into represent well what
>> they are doing and they are well named.
>>
>> Cheers,
>> Sebastian
>>
>> - Mail original -
>> > De: "Steffen Märcker" 
>> > À: "Any question about pharo is welcome" 
>> > Envoyé: Mercredi 12 Avril 2023 19:03:01
>> > Objet: [Pharo-users] Collection>>reduce naming
>>
>> > Hi!
>> >
>> > I wonder whether there was a specific reason to name this method
>> #reduce:?
>> > I would have expected #fold: as this is the more common term for what it
>> > does. And in fact, even the comment reads "Fold the result of the
>> receiver
>> > into aBlock." Whereas #reduce: is the common term for what we call with
>> > #inject:into: .
>> >
>> > I am asking not to annoy anyone but out of curiosity. It figured this
>> out
>> > only by some weird behaviour after porting some code that (re)defines
>> > #reduce .
>> >
>> > Ciao!
>> > Steffen
>>
>
> --
> Gesendet mit Vivaldi Mail. Laden Sie Vivaldi kostenlos von vivaldi.com
> herunter.
>


[Pharo-users] Re: Collection>>reduce naming

2023-04-13 Thread Richard O'Keefe
The standard prelude in Haskell does not define anything
called "fold".  It defines fold{l,r}{,1} which can be
applied to any Foldable data (see Data.Foldable).  For
technical reasons having to do with Haskell's
non-strict evaluation, foldl' and foldr' also exist.
But NOT "fold".

https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Foldable.html#laws


On Thu, 13 Apr 2023 at 21:17, Sebastian Jordan Montano <
sebastian.jor...@inria.fr> wrote:

> Hello Steffen,
>
> Let's take Kotlin documentation (
> https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce)
>
> > The difference between the two functions is that fold() takes an initial
> value and uses it as the accumulated value on the first step, whereas the
> first step of reduce() uses the first and the second elements as operation
> arguments on the first step.
>
> Naming is not so consistent in all the programming languages, they mix up
> the names "reduce" and "fold". For example in Haskell "fold" does not take
> an initial value, so it is like a "reduce" in Kotlin. In Kotlin, Java,
> Scala and other oo languages "reduce" does not take an initial value while
> "fold" does. Pharo align with those languages (except that out fold is
> called #inject:into:)
>
> So for me the Pharo methods #reduce: and #inject:into represent well what
> they are doing and they are well named.
>
> Cheers,
> Sebastian
>
> - Mail original -
> > De: "Steffen Märcker" 
> > À: "Any question about pharo is welcome" 
> > Envoyé: Mercredi 12 Avril 2023 19:03:01
> > Objet: [Pharo-users] Collection>>reduce naming
>
> > Hi!
> >
> > I wonder whether there was a specific reason to name this method
> #reduce:?
> > I would have expected #fold: as this is the more common term for what it
> > does. And in fact, even the comment reads "Fold the result of the
> receiver
> > into aBlock." Whereas #reduce: is the common term for what we call with
> > #inject:into: .
> >
> > I am asking not to annoy anyone but out of curiosity. It figured this out
> > only by some weird behaviour after porting some code that (re)defines
> > #reduce .
> >
> > Ciao!
> > Steffen
>


[Pharo-users] Re: Collection>>reduce naming

2023-04-13 Thread Richard O'Keefe
Actually, #inject:into: is what is normally called fold or foldl,
and #reduce: is commonly called fold1.  It is very confusing to
call foldl1 #fold:.

To the best of my knowledge, the name 'reduce' comes from APL.
"Z <- LO/R
 has the effect of placing the function LO between adjacent pairs
 of items along the last axis of R and evaluating the resulting
 expression for each subarray.
 If R is the vector A B C the LO-reduction is defined as follows:
 LO/R <-> A LO B LO C"
which for APL means A LO (B LO C), so it's technically foldr1.
-- IBM APL2 Language Reference, 1994, page 209.

The name given to #inject:into: when it was first invented was
LIT, short for List ITeration.

Here's a reference: Functional Programming, Application and
Implementation, Peter Henderson, 1980, page 41:

As another example of a higher-order function consider the following
operation of reduction (the idea and the name are in fact taken from the
programming language APL). We define reduce(x,g,a) where x is a list,
g is a binary function, and a is a constant, so that the list
x = (Xl. . . Xk) is reduced to the value g(X1, g(X2, ... g(Xk,a) ...))

reduce(x,g,a) = if x = NIL then a else
g(car(x),reduce(cdr(x),g,a))


So APL used "reduce" for foldr1, and Henderson, because
most functions don't carry their identity with them,
used it for foldr.

As I recall it, the name "reduce" was dropped because
people wanted to support both foldl and foldr (and did
NOT want to apply it to higher-ranked arrays, so that
'rank reduced by 1' wasn't an aid to memory).  But it
IS a name for the operation that predates Smalltalk
and is still in use (as APL itself is).

If it comes to that, this higher-order function is
called 'reduce' in Swift:
https://developer.apple.com/documentation/swift/array/reduce(_:_:)
and of course the Map-Reduce paradigm is famous, and
guess what 'Reduce' stands for?

An intention-revealing name in Smalltalk would have been
  aCollection injectInto: aBinaryValuable [ifNone: emptyBlock]





On Thu, 13 Apr 2023 at 07:03, Steffen Märcker  wrote:

> Hi!
>
> I wonder whether there was a specific reason to name this method #reduce:?
> I would have expected #fold: as this is the more common term for what it
> does. And in fact, even the comment reads "Fold the result of the receiver
> into aBlock." Whereas #reduce: is the common term for what we call with
> #inject:into: .
>
> I am asking not to annoy anyone but out of curiosity. It figured this out
> only by some weird behaviour after porting some code that (re)defines
> #reduce .
>
> Ciao!
> Steffen
>


[Pharo-users] Re: Comparison of blocks

2023-04-13 Thread Richard O'Keefe
There is no agreement between Smalltalk systems about how to
compare block contexts for equality.  In Smalltalk-80 (and I
have two versions of Smalltalk-80 to compare), block equality
is identity.  The same in VisualAge Smalltalk 8.6.3.  The
same in GNU Smalltalk.  The same in Smalltalk/X-JV.
Squeak has a similar definition to  VW.
My reading of the ANSI standard is that it is carefully vague about this.

Equality of functions has been troublesome for decades.
Haskell: bans it.
Standard ML: bans it.
Some other ML-family languages: it's a run-time error.
Lisp family: varies.  Interlisp says nothing.  Scheme gives lower and upper
bounds.

Imagine a Smalltalk that recognises [] blocks and
allocates one static closure per .  Then
[true] == [true] hence [true] = [true] even when the two
s were in different methods.  The Squeak
and VW definitions would regard them as unequal.  (This is
on my TODO list, principally for [] [true] [false] and [0].)
For the special case of [], you don't *have* to imagine it.
If I'm reading VAST correctly, it treats "empty blocks"
specially.

If you *rely* on the definition of #= for block contexts/closures
you are almost certainly doing something dangerous.  You are
certainly doing something that is not portable.

On Thu, 13 Apr 2023 at 18:55, Steffen Märcker  wrote:

> Hi!
>
> In VisualWorks, blocks can be compared with each other. In Pharo the
> comparison just checks for Identity. Is this on purpose? For reference,
> that's how BlockClosure>>= is implemented in VW:
>
>
> = aBlockClosure
> ^aBlockClosure class = self class and:
>  [method = aBlockClosure method and:
>   [outerContext = aBlockClosure outerContext and:
>[copiedValues = aBlockClosure copiedValues]]]
>
> Kind regards,
> Steffen
>


[Pharo-users] Re: [vwnc] Block evaluation with n+1 arguments

2023-04-12 Thread Richard O'Keefe
You say

- The source object returns multiple values as a tuple (for good reasons).
- The block processes theses values but needs another argument (at the
first place).


On the first point, we have to take your word for it.
It's not clear why you could not pass an n+1-element array to
the source method and have it fill in elements after the first
rather than having it allocate a new array.  If you are concerned
about object allocation in a tight loop this would be a good
place to start.

argArray := Array new: block argumentCount.
...
   source compute: i into: argArray.
   argArray at: 1 put: i.
   block valueWithArguments: argArray.

If for some reason it is utterly impossible to modify
'source compute: i' in this way, we can *still* use the
technique of allocating an array once for the whole loop.

argArray := Array new: block argumentCount.
...
   argArray at: 1 put: i;
 replaceFrom: 2 to: argArray size with: (source compute: i).
   block valueWithArguments: argArray.

This seems like the smallest possible change to your code.
You still have the overhead of copying from one array to another
-- which is why I prefer modifying #compute: -- but you do not
have the overhead of allocating an array per iteration.

On the second point, right there you have the assumption that is
limiting your vision.

You are viewing the problem as "pass an extra first argument to
the block" when you *should* frame it as "ensure that the block
knows the value of i SOMEHOW".  Presumably these blocks are
generated by code written by you.

So let's start with
Someclass
  methods for: 'generating blocks'
blockFor: aSituation
  ^[:x0 :x1 ... :xn | ]

block := Someclass blockFor: theSourceSituation.
(1 to: 1000) do: [:i | | args |
  args := source compute: i.
  block valueWithArguments: {i} , args

So now we change it to

Someclass
  methods for: 'generating blocks'
blockFor: aSituation sharing: stateObject
  ^[:x1 ... :xn | |x0|
  x0 := stateObject contents.
  .]

ref := Ref with: 0.
block := Someclass blockFor: theSourceSituation sharing: ref.
1 to: 1000 do: [:i | |args|
  ref contents: i.
  args := source compute: i.
  block valueWithArguments: args].

Ref is an actual class in my library modelled on the Pop-2 and SML
types of the same name.  It's not important.  What *is* important is
that information can be supplied to a block through a shared object
as well as through a parameter.

I am a little bit twitchy about the 'coincidence' of the size of
#compute:'s result and the argument count of the block.  Why not
pass the block to #compute: so that there never is any array in
the first place?

compute: index
   ... ^{e1. ... en} ...

=>
compute: index thenDo: aBlock
   ... ^aBlock value: e1 ... value: en ...

ref := Ref with: 0.
block := Someclass blockFor: theSourceSituation sharing: ref.
1 to: 1000 do: [:i | |args|
  ref contents: i.
  source compute: i thenDo: block].

Now there are even fewer arrays being allocated and no use of
#valueWithArguments: in any guise.

The problem is NOT, as some commentators apparently think, that
you are using a block.  The problem is that having thought of
one way to wire things up -- not an unreasonable way, in fact --
you concentrated on making *that* way faster instead of looking
for other ways to do it.

We have several idioms here:
  Reuse Object (convert an allocation per iteration to an allocation
  per loop by reinitialising a object instead of allocating a new one)
  Communicate Through Shared Microstate (communicate information between
  a method and a block or object through a 'microstate' object created
  by the method and passed when the block or object is created)
  Multiple Values by Callback (instead of 'returning' multiple values in
  a data structure, pass a block to receive those values as parameters).



On Wed, 12 Apr 2023 at 04:44, Steffen Märcker  wrote:

> Hi!
>
> First, thanks for your engaging answers Richard, Stephane and the others!
>
> The objective is to avoid unnecessary object creation in a tight loop that
> interfaces between a value source and a block that processes the values.
> - The source object returns multiple values as a tuple (for good reasons).
> - The block processes theses values but needs another argument (at the
> first place).
> We do not know the number of values at compile time but know that they
> match the arity of the block. Something like this (though more involved in
> practice):
>
> (1 to: 1000) do: [:i | | args |
> args := source compute: i.
> block valueWithArguments: {i} , args ]
>
> Since prepending the tuple with the first argument and then sending
> #valueWithArguments: creates an intermediate Array, I wonder whether we can
> avoid (some of) that overhead in the loop without changing this structure.
> Note, "{i}, args" is only for illustration and creates an additional third
> array as 

[Pharo-users] Re: [vwnc] Block evaluation with n+1 arguments

2023-04-10 Thread Richard O'Keefe
>From the slides:
  "What is the difference between a block and a simple object understanding
#value?"
The slides give the wrong answer.  The right answer is that
 - a block can see the variables of the blocks, method, and object
containing it
   which allows ENCAPSULATION of long term and short term state
 - an object cannot see those variables, forcing long term and short term
state
   to be dispersed to other objects, harming encapsulation.

The slides also say
  " imagine passing a block around and want to accumulate information
◦  you can't!"
which is of course not really so.  Consider
  |b s|
  b := [:state :argument | state nextPut: argument].
  s := Summary new.
  #(3 1 4 1 5 9) do: (b bindFirst: s).
  s printOn: Transcript. Transcript cr.
That's actual working code and the output is
Summary(count: 6 min: 1 max: 9 mean: 3.833 sd:
2.994439290863428 skew: 1.044066600910494)
Far from "you can't", it's dead simple.
My library includes
#bindFirst:[bindSecond:[bindThird:]] #bindSecond:[bindThird:] #bindThird:
for binding any subset of the first three arguments of a block.
So far that's been enough.

The slides further say
"Adding behavior (i.e., offering another message) is impossible"
which is sort of true but misleading: you cannot add additional behaviour
to *an individual block*, but you CAN add additional behaviour to the class
it is an instance of.  Which is how come I have #value:valueWithArguments:
#bindFirst: and its relatives, and a host of other combinators.  It really
really
helps that I have a separate class for each block arity.  For example, I
have
about 20 non-ANSI methods on TriadicBlock but about 50 on DyadicBlock.
The additional 30 on DyadicBlock would make no sense for TriadicBlock,
and smushing everything up into a single Block class would not work well.

That whole set of slides reads like a hymn of praise to Java nested classes,
which can do things blocks can't but on the other hand can't do things that
blocks can.

The issue we are discussing in this thread, of course, is not blocks as
such.
It isn't even blocks with many arguments.  In
  aBlock value: firstArgument valueWithArguments: restArguments
we have been given no reason to suppose that restArguments is long.

I still have a couple of stickers that Brian Marick gave me, reading

   AN EXAMPLE WOULD BE GOOD ABOUT NOW.

I'd still like to know what the original poster wanted to DO with

  value: firstArgument value: restArguments
^self valueWithArguments: {firstArgument} , restArguments




On Tue, 11 Apr 2023 at 04:25, Richard Sargent  wrote:

> Excellent write up, Stephane!
>
> I will add that over the years, there have been many times (countless!)
> when developing/debugging involved a complex block and that turned out to
> be significant nuisance.
>
> I can elaborate on the details, but once a block gets passed around,
> revising it on the fly breaks debug and continue.
>
> Having a block comprise a single message send allows one to revise that
> method as and when needed.
>
>
>
>
>
> *From:* vwnc-requ...@lists.cs.illinois.edu <
> vwnc-requ...@lists.cs.illinois.edu> *On Behalf Of *
> stephane.duca...@free.fr
> *Sent:* April 10, 2023 07:03
> *To:* Any question about pharo is welcome 
> *Cc:* v...@lists.cs.illinois.edu
> *Subject:* Re: [vwnc] [Pharo-users] Block evaluation with n+1 arguments
>
>
>
> BTW to me when a block needs too many arguments it feels like that an
> object has to be born :)
>
> With an object I can just sent or not a given extra argument.
>
>
>
> Now I do not know enough your specific context but what I learned is that
> complex blocks are difficult to follow, manipulate…
>
> so I keep block as simple as possible and else I create little objects.
>
>
>
>
>
> This is a little lectures from a super cool forthcoming mooc
>
>
>
>
> https://rmod-files.lille.inria.fr/DesignCoffeeClub/ForLearningLab/7-Lang-04-BlocksVsObjects.pdf
> 
>
>
>
>
>
>
>
> On 6 Apr 2023, at 15:28, Steffen Märcker  wrote:
>
>
>
> Hi!
>
> I want to evaluate a block an argument 'arg1' and additional n arguments
> given in an array 'args'. The following code does the trick:
>
>   block valueWithArguments: (Array with: arg1) , args.
>
> Is there a way to do this without the overhead of creating a new Array?
> (How) Can I add additional #value:value:[...] methods to BlockClosure that
> evaluate the block with n arguments directly without falling back to
> #valueWithArguments: ? If yes, what's the maximum?
>
> Cheers!
> Steffen
>
>
>


[Pharo-users] Re: Block evaluation with n+1 arguments

2023-04-10 Thread Richard O'Keefe
(1) I have #value:valueWithArguments: in my personal library.
(2) The way to answer your question is to look at #valueWithArguments:,
It normally goes through a primitive.
However, it *does* have backup code that you could adapt.
(3) Without benchmarking, it's not clear whether the cost of not being
able to go through the primitive will exceed the saving of not
making another array.  It might not be the win you expect.
Have you profile your code to find out whether this way of
invoking a block is *worth* speeding up?
(4) aBlock value: {a} , remaining
has the merit of working in other Smalltalks
and the merit of being familiar to other programmers.
(5) Is there no way that you can restructure your code so that you
no longer want to do this?  Point (1) is true, but only because
I've never bothered to throw it away.  In the system where I
wrote it, it *does* save time overall, but in the complete
context, it wasn't worth doing.

On Fri, 7 Apr 2023 at 01:29, Steffen Märcker  wrote:

> Hi!
>
> I want to evaluate a block an argument 'arg1' and additional n arguments
> given in an array 'args'. The following code does the trick:
>
> block valueWithArguments: (Array with: arg1) , args.
>
> Is there a way to do this without the overhead of creating a new Array?
> (How) Can I add additional #value:value:[...] methods to BlockClosure that
> evaluate the block with n arguments directly without falling back to
> #valueWithArguments: ? If yes, what's the maximum?
>
> Cheers!
> Steffen
>


[Pharo-users] Re: A blog on graph algorithms library of Pharo

2023-04-05 Thread Richard O'Keefe
Warmest congratulations to the author(s) of this library.
It's a lot of work, and it's available to the Pharo community.
It doesn't suit my graph-processing needs, but that doesn't
stop me appreciating the contribution.

On Wed, 5 Apr 2023 at 04:29, DK Goutham  wrote:

> Dear Pharo Users,
>
> Here's a blog on *pharo-ai/graph-algorithms* library. This acts as a
> primer for people new to this library and discusses the flow and
> architecture of the library. The motive of this blog is to introduce
> people to the amazing graph library of Pharo and give them enough
> confidence to contribute to this library.
>
> Link:
> https://medium.com/@dkgoutham1806/graph-algorithms-in-pharo-7d12af0be060
>
> Happy reading!
>
> Thank you,
> Goutham
>


[Pharo-users] Re: Wow - Chat GPT understands Smalltalk

2023-03-26 Thread Richard O'Keefe
I tried it on three "dead" languages:
- a bubble-sort in Pop-2
- a system of linear equations solver in IMP-80
- the array concatenation example in SNOBOL 4 from Rosetta Code.
It got the first one right -- despite 'array' access
being written 'subscr(index, array)' -- and the second
one almost right -- mistaking an nxn array for a 2n
array. It got the third one (which I had stripped of comments)
right too.

It's impressive.  And it's impressive because it's clearly
NOT based on analysing a large corpus of code in the language
you give it (because there IS no corpus of Pop-2 and the
available corpus of IMP is both limited and very sparsely
commented.  Not much SNOBOL either.

On Wed, 15 Mar 2023 at 20:07, Tim Mackinnon  wrote:

> Of course everyone is talking about ChatGPT, and I saw a post to
> ExplainCode and didn’t expect it to understand Smalltalk, so was impressed
> that it does! Presumably the Tonel Smalltalk code on GitHub has helped
> along with numerous articles?
>
> Try it out: https://whatdoesthiscodedo.com/
>
> I gave this simple example: (1 to: 100 by: 3) reject: [:i | i isOdd]
>
> And got this (neat eh):
>
> The code above is written in the programming language Smalltalk.
>
> It creates a collection of numbers from 1 to 100, incrementing by 3 at
> each step. This is done using the "to:by:" construct where the starting
> value is 1, the ending value is 100, and the increment is 3.
>
> The resulting collection is then filtered using the "reject:" method,
> which takes a block of code as an argument. In this case, the block checks
> whether each element (denoted by the variable i) is odd by using the
> "isOdd" method. If an element is odd, it will be rejected from the
> collection.
>
> So, the final result is a collection of all even numbers from 1 to 100,
> incrementing by 3 at each step.
> Share this explanation with colleagues: whatdoesthiscodedo.com/g/a0ec56e
>


[Pharo-users] Re: Sacrilegeous question : what are compelling use cases for Pharo

2023-01-25 Thread Richard O'Keefe
To Konrad Hinsen: you HERO.

On Thu, 26 Jan 2023 at 02:40, Konrad Hinsen 
wrote:

> "Richard O'Keefe"  writes:
>
> > Thus I hypothesise that there is room for Smalltalk as a tool for
> > *generating* and configuring HPC code.
>
> Yes. But it will be hard to convince people that Smalltalk is a better
> choice than Python (well established in HPC as you say) for this use
> case.
>
> > My main worry is that when it comes to "bet your whole economy"
> > software and worse still, "bet the entire global economy and human
> > happiness for centuries" software like climate models, it's
> > appropriate to use the very highest quality assurance tools practical,
> > including *serious* verification.  That's not common practice.
>
> Indeed, and that's one of my main worries in computational science as
> well. There is a culture of scientific validation, but not of technical
> verification of artifacts such as code.
>
> My own project in this space (implemented in Pharo) aims at supporting
> *human* verification for the aspects that no automatic tool can possibly
> verify. In technical terms, that's verifying the formal specification
> rather than the implementation of some method. The first step, which I
> have made good progress on, is a specification language for scientific
> models and methods that human readers would be happy to proofread.
> Details:
>
>https://github.com/khinsen/leibniz-pharo/
>https://science-in-the-digital-era.khinsen.net/#Leibniz
>
> Konrad
>


[Pharo-users] Re: Sacrilegeous question : what are compelling use cases for Pharo

2023-01-17 Thread Richard O'Keefe
Much sympathy for your life situation.
Most of the Smalltalk code I personally develop is developed using a
classic text
editor, is batch compiled, and runs headless.  Smalltalk is *STILL* an
amazing language
without the "addictive" IDE.  (In fact the more "conventional" Smalltalk
systems I use
have sufficiently different IDEs that I experience considerable friction
using the IDE.)

I'm on the fringes of the High Performance Computing world.  This is quite
dramatically
different from most programming, and in some interesting ways.  The
dominant languages
are Fortran, C, and C++ with extensions such as OpenMP and OpenACC and of
course "transport"
layers like MPI.  These languages have *serious* optimising compilers
working hard to get
the best out of vectorised instructions, GPUs, even FPGAs, and clusters.
There are also
dialects like SYCL and Cilk.  As an example of the kind of application,
consider the
COVID epidemiological model developed by Neil Ferguson's team in the UK,
which was very
influential in setting UK government policy (lockdowns).  This is about 10
000 SLOC of
C++ with much use of OpenMP for parallelism.  This isn't "bet your
business" software;
this is "bet your whole ECONOMY" software.  It is, in the 1970s sense,
"structured".  It
is, in the peculiarly C++ sense, "object oriented".  And it is very hard
for me to
figure out what is going on (despite having tracked C++ since cfront days).

What does this have to do with Smalltalk?

First, Smalltalk is not an HPC language.  If you want to develop
computationally
demanding code, you might prototype it in Smalltalk, but you are not going
to deploy.

Second, that doesn't necessarily preclude the use of Smalltalk in HPC
environments.
People seriously use Python (despite Python's single-thread slowness),
Matlab, and
R for HPC problems.  What they do is wrap Fortran/C/C++ data structures and
call
Fortran/C/C++ code to manipulate them, basically using Python or Matlab or
whatever
to direct the low level code.

Third, just imagine the fun of debugging code like this.  You don't really
want to
write Fortran (even Fortran'08) or C++ (even C++17) by hand; it's ok as
"portable
parallel assembler".

Fourth, in order to configure and customise software like this, you really
want
a decent interactive modelling language.  (For example, the CovidSim
program uses
data loaded *once* from WorldPop.  I haven't yet found anything in the
distribution
to update this.)

Fifth, there's the whole "Embedded Domain-Specific Language" thing.  There
has been
some impressive work done on generating low level code inside functinoal
programming
languages.

Thus I hypothesise that there is room for Smalltalk as a tool for
*generating* and
configuring HPC code.

My main worry is that when it comes to "bet your whole economy" software and
worse still, "bet the entire global economy and human happiness for
centuries"
software like climate models, it's appropriate to use the very highest
quality
assurance tools practical, including *serious* verification.  That's not
common
practice.  CovidSim has 'assert' statements in just two files.  Generation
via
Smalltalk wouldn't be *worse*.  But could it be *better* ?

What is the state of the art in verification tools
 - written in Smalltalk?
 - available (via FFI or otherwise) *through* Smalltalk?
 - available in any form *for* Smalltalk?

(I should probably be looking at MOOSE but am too stupid to know how to
start.)

On Sun, 15 Jan 2023 at 19:11, mayur...@kathe.in via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Hello,
>
> In response to my email below, I received 5 interesting responses. I thank
> those people for writing-in.
>
> Here is my take on what I've understood and why I am still hesitant to go
> along.
> My comments on those responses are further below, but, at the moment, let
> me explain my situation.
>
> I am a 46 year-old who has been programming computers since the age of 16.
> I used to be a highly sought-after programmer till the year 2000, when due
> to circumstances beyond my control, my life and career got destroyed
> completely.
> In fact, I was so highly valued, that in spite of me being from India, I
> was pursued by Verizon US.
> I am now confined to my home (mostly) and I have very little to do, in the
> past 12 years I have not programmed anything beyond a basic prime-number
> tester and a fibonacci-sequence generator in C.
> I am getting my life back in order and I need some occupation, though, not
> necessarily one from which I would demand financial returns.
> I have been dilly-dallying on a decision, primarily because I am unable to
> take a call on whether to pursue my love for the low-level (x64 assembler +
> Forth) or the extremely high-level (work involving reasoning using symbolic
> inference) using a Smalltalk (either Squeak or Pharo).
>
> The above is not meant to elicit sympathy, but has been tacked-in just to
> give potential advisers an idea about my state.
>
> Onward to my take on the 

[Pharo-users] Re: Sacrilegeous question : what are compelling use cases for Pharo

2023-01-17 Thread Richard O'Keefe
Back when I was a University lecturer, I sometimes amused myself by
rewriting student (or other
staff!) Java code in Smalltalk.  I generally got about a factor of 6
smaller.  Of course, that
was before Java 8, which copied blocks and higher-order collection methods
from Smalltalk.

On Sat, 14 Jan 2023 at 21:01, mayur...@kathe.in via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Hello,
>
> This isn't a mail intended to troll this community.
>
> I am genuinely curious about what would be the type of use cases which
> would be exemplary for Pharo?
>
> Now-a-days, anything one could have accomplished solely with Smalltalk
> (and hence Pharo) can be accomplished with a number of modern programming
> languages and their associated frameworks, e.g. Google's Dart with Flutter,
> Apple Swift with SwiftUI, Microsoft's C# with WinUI.
> And such languages and their associated frameworks are built from the
> ground-up for a particular platform, while Pharo does not have any such
> targets, which usually renders graphical applications built using Pharo to
> "look like" aliens.
>
> What does stand-out regarding Smalltalk (and hence Pharo) is the superior
> developer experience furnished as a result of the true object system
> combined with a full graphical environment.
> In addition to that, Pharo, specifically, provides advanced tools like Git
> integration, etc.
>
> But, are these things all that there are to be considered enough for
> highlighting the full inherent power of Pharo?
>
> Again, apologies if anyone found the subject line as well as the message
> body to be troll-ish. That has not been the intent.
>
> Kind regards,
>
> ~Mayuresh
>


[Pharo-users] Re: IWST proceedings online

2023-01-11 Thread Richard O'Keefe
A tip for anyone who finds it convenient for filing
purposes to have proceedings as single PDFs, use
% pdfunite preface.pdf short*.pdf regular*.pdf iwst2022.pdf
to combine the files of the collection into one.
(pdfunite is part of the poppler-utils package.)
Do not be surprised when pdfunite doesn't like the PDF much;
other pdf tools on Ubuntu are also unhappy but not fatally so.


On Thu, 12 Jan 2023 at 17:32, Richard O'Keefe  wrote:

> Excellent news, for which many thanks.
>
> On Wed, 11 Jan 2023 at 20:18, stephane ducasse 
> wrote:
>
>> Hi guys
>>
>> I’m happy to sahre with you this EXCELLENT news. The proceedings
>> of IWST 22 are now online
>> International Workshop on Smalltalk Technologies 2022
>> <https://ceur-ws.org/Vol-3325/>
>> ceur-ws.org <https://ceur-ws.org/Vol-3325/>
>> [image: favicon.ico] <https://ceur-ws.org/Vol-3325/>
>> <https://ceur-ws.org/Vol-3325/>
>>
>> in a nice collection.
>>
>> I would like to warmly thank all the authors, loic and vincent for their
>> great job.
>>
>> Soon we will send around the call for paper for 2023!
>>
>> S
>>
>


favicon.ico
Description: Binary data


[Pharo-users] Re: IWST proceedings online

2023-01-11 Thread Richard O'Keefe
Excellent news, for which many thanks.

On Wed, 11 Jan 2023 at 20:18, stephane ducasse 
wrote:

> Hi guys
>
> I’m happy to sahre with you this EXCELLENT news. The proceedings
> of IWST 22 are now online
> International Workshop on Smalltalk Technologies 2022
> 
> ceur-ws.org 
> [image: favicon.ico] 
> 
>
> in a nice collection.
>
> I would like to warmly thank all the authors, loic and vincent for their
> great job.
>
> Soon we will send around the call for paper for 2023!
>
> S
>


favicon.ico
Description: Binary data


[Pharo-users] ANSI instance creation methods for RunArray

2022-12-23 Thread Richard O'Keefe
Here's a teeny tiny Christmas present:
ANSI-compatible instance creation methods
for RunArray.
'From Pharo9.0.0 of 11 May 2020 [Build information: Pharo-9.0.0+build.293.sha.d27b9cd0a533a234cd3491ce7db3c2ce7085e3a5 (64 Bit)] on 24 December 2022 at 5:14:53.947536 pm'!

!RunArray methodsFor: 'adding' stamp: 'RichardAnthonyOKeefe 12/24/2022 17:05'!
add: value
	^self addLast: value! !


!RunArray class methodsFor: 'instance creation' stamp: 'RichardAnthonyOKeefe 12/24/2022 17:12'!
with: x1 with: x2 with: x3 with: x4
	"ANSI method for creating collections"
	"RunArray with: #f with: #e with: #e with: #d"
	^(self new) add: x1; add: x2; add: x3; add: x4; yourself! !

!RunArray class methodsFor: 'instance creation' stamp: 'RichardAnthonyOKeefe 12/24/2022 17:13'!
withAll: aCollection
	"ANSI method for creating collections"
	"RunArray withAll: #(f e e d  t h e  a d d e r)"
	^(self new: aCollection size) removeAll; addAll: aCollection; yourself! !

!RunArray class methodsFor: 'instance creation' stamp: 'RichardAnthonyOKeefe 12/24/2022 17:12'!
with: x1
	"ANSI method for creating collections"
	"RunArray with: #f"
	^(self new) add: x1; yourself! !

!RunArray class methodsFor: 'instance creation' stamp: 'RichardAnthonyOKeefe 12/24/2022 17:12'!
with: x1 with: x2
	"ANSI method for creating collections"
	"RunArray with: #f with: #e"
	^(self new) add: x1; add: x2; yourself! !

!RunArray class methodsFor: 'instance creation' stamp: 'RichardAnthonyOKeefe 12/24/2022 17:12'!
with: x1 with: x2 with: x3
	"ANSI method for creating collections"
	"RunArray with: #f with: #e with: #e"
	^(self new) add: x1; add: x2; add: x3; yourself! !



[Pharo-users] Re: mapping CamelCase to

2022-11-06 Thread Richard O'Keefe
But there IS a #cutCamelCase method in Pharo.
It comes from Roassal2.
Here it is, copied from Pharo 9.0.0:

cutCamelCase
"Breaks apart words written in camel case.

It's not simply using piecesCutWhere: because we want
to also deal with abbreviations and thus we need to
decide based on three characters, not just on two:
('FOOBar') piecesCutWhereCamelCase asArray = #('FOO' 'Bar').
('FOOBar12AndSomething') piecesCutWhereCamelCase asArray = #('FOO' 'Bar'
'12' 'And' 'Something')
"

| start previous current next pieces |
self isEmpty ifTrue: [^self].
start := 1.
pieces := OrderedCollection new.
3 to: self size do: [ :index |
previous := self at: index - 2.
current := self at: index - 1.
next := self at: index.
((previous isLowercase and: [current isUppercase]) or: [
(previous isUppercase and: [current isUppercase and: [next isLowercase ]])
or: [
(previous isDigit not and: [current isDigit]) or: [
previous isDigit and: [current isDigit not]
]]]) ifTrue: [
pieces add: (self copyFrom: start to: index - 2).
start := index - 1].
].
pieces addAll: ((self copyFrom: start to: self size) piecesCutWhere: [:a :b
|
(a isDigit and: [b isDigit not]) or: [a isDigit not and: [b isDigit ]]]).
^pieces


On Wed, 26 Oct 2022 at 23:37, Kasper Osterbye 
wrote:

>
> What's wrong with
>
> $- join: (s cutCamelCase collect: [ :each | each asLowercase])
>
>
> There is no method called cutCamelCase in Pharo. If there was, this was
> exactly the right solution to use something existing.
>
> Best,
>
> Kasper
>
>
>


[Pharo-users] Re: mapping CamelCase to

2022-10-26 Thread Richard O'Keefe
The important thing is that there is no NEED to write a
new method to split a Smalltalk identifier into pieces,
because there already *IS* such a method.

Only write a new method if the existing one doesn't actually
work for you.  For example, what do you want to be done with
strings or symbols that contain non-alphanumeric characters,
like #== ?  What do you want done with underscores and digits
in strings like 'INTL_61_123_456'?

On Wed, 26 Oct 2022 at 22:41, Richard O'Keefe  wrote:

> What's wrong with
>
> $- join: (s cutCamelCase collect: [ :each | each asLowercase])
>
> where s is the string you want to transform?
> I'm sure you're aware of the proverb:
>   You have a problem and you decide to solve it with
>   a regular expression.  Now you have TWO problems.
>
> MYWeirdName and MyWeirdName both map to my-weird-name,
> but perhaps you are happy with that.
>
> On Sat, 22 Oct 2022 at 21:57, Siemen Baader 
> wrote:
>
>> Hi,
>>
>> I'm looking for an elegant way to convert class names with optional
>> namespace prefixes to names for custom html elements.
>>
>> MYCustomElement and CustomElement
>>
>> to
>>  and 
>>
>> There must be an elegant way to do it with regex or inject, but I'm
>> embarrassed to say I can't get my head around it. I can get it to match the
>> regex '((:isUppercase:+)*)((:isUppercase::isLowercase:+)*)', (if I recall
>> correctly) but can't get a collection of the individual elements 'MY'
>> 'Custom" 'Element' to lowercase and join.
>>
>> Thanks for any hints!
>>
>> cheers
>> Siemen
>>
>


[Pharo-users] Re: mapping CamelCase to

2022-10-26 Thread Richard O'Keefe
What's wrong with

$- join: (s cutCamelCase collect: [ :each | each asLowercase])

where s is the string you want to transform?
I'm sure you're aware of the proverb:
  You have a problem and you decide to solve it with
  a regular expression.  Now you have TWO problems.

MYWeirdName and MyWeirdName both map to my-weird-name,
but perhaps you are happy with that.

On Sat, 22 Oct 2022 at 21:57, Siemen Baader  wrote:

> Hi,
>
> I'm looking for an elegant way to convert class names with optional
> namespace prefixes to names for custom html elements.
>
> MYCustomElement and CustomElement
>
> to
>  and 
>
> There must be an elegant way to do it with regex or inject, but I'm
> embarrassed to say I can't get my head around it. I can get it to match the
> regex '((:isUppercase:+)*)((:isUppercase::isLowercase:+)*)', (if I recall
> correctly) but can't get a collection of the individual elements 'MY'
> 'Custom" 'Element' to lowercase and join.
>
> Thanks for any hints!
>
> cheers
> Siemen
>


[Pharo-users] Re: A question about #beginsWith: and #endsWith:

2022-04-26 Thread Richard O'Keefe
I discovered that my own code-base was inconsistent due
to sometimes following Pharo and sometimes not.  I've just
spent the last day making it consistent and you would not
BELIEVE how many methods suddenly became simpler.

I finally understood why some of the test cases I had
for XPath were broken.  XPath specifies that the empty
string is a prefix and suffix of every string.

Perhaps better support for XPath may have some
persuasive value.  (Though support for XPath collations
will be a long way off.  There's a LOT of other Unicode
support I need to develop first.)

On Tue, 26 Apr 2022 at 22:12, Steffen Märcker  wrote:

> I can only fully agree to Richard's explanation. Also, not having the
> empty string pre/suf-fixing every string breaks the free monoid that
> describes concatenation of strings and forms the basis of regular
> expressions. In effect, this will lead to subtle inconsistencies. Hence, I
> consider this a bug rather than a feature.
>
> Kind regards,
> Steffen
>
>
>
> Richard O'Keefe schrieb am Samstag, 23. April 2022 02:37:48 (+02:00):
>
> Dan Ingalls is of course a big NAME in the
> world of Smalltalk, but the stated reason
> for changing the behaviour of #beginsWith:
> and #endsWith: makes no sense.
>
>
> We have many ways to define a partial order
> on strings.
> x <= y iff y beginsWith: x
> x <= y iff y endsWith: x
> x <= y iff y includesSubCollection: x
> x <= y iff y includesSubSequence: x
> These things are supposed to obey laws:
> if a beginsWith: b , c
> then a beginsWith: b
> if a endsWith: b , c
> then a endsWith: c
> if a includesSubCollection: b , c
> then a includesSubCollection: b
> and a includesSubCollection: c
> if a includesSubSequence: b , c
> then a includesSubSequence: b
> and a includesSubSequence: c.
>
> We also expect the usual rules of equality
> to hold.  So
> (1) a beginsWith: a
> (2) a = '' , a
> (3) THEREFORE a beginsWith: ''
>
> (1) a endsWith: a
> (2) a = a , ''
> (3) THEREFORE a endsWith: ''
>
> (1) a includesSubCollection: a
> (2) a = '' , a
> (3) THEREFORE a includesSubCollect: ''
>
> Reasoning about strings (as values) gets
> enormously more complicated if the operations
> do not follow simple sensible rules, and
> having '' be the least string under these
> orderings and having '' be a prefix and a
> suffix of any string is essential if the
> rules are going to be simple and coherent.
>
> '' is to strings (and more generally
> empty sequences are to sequences) pretty
> much what 0 is to integers.   Denying that
> 'abc' beginsWith: '' is *structurally*
> just like denying that 0 <= 123.
>
> Now as it happens I *can* see a use for
> versions of #beginsWith: and #endsWith:
> that diverge from the ones we have, but
> *this* is not where they need to diverge.
> a beginsWithGraphemesOf: b
> iff a asGraphemes = b asGraphemes , c asGraphemes
> for some c, where s asGraphemes returns a
> sequence of strings each of which is a maximally
> long grapheme cluster, such that concatenating
> s asGraphemes recovers s.  That is,
> #beginsWithGraphemesOf: and
> #endsWithGraphemesOf: would respect the
> Unicode Text Segmentation boundaries.
> But s beginsWithGraphemesOf: ''
> would still need to be true.
>
> The thing is, in practice you often DON'T
> KNOW whether a potential affix is empty or
> not.  Here are some of my test cases.
>
> testTestData
>   "Ensure that the sample string has no duplicates."
>   [(Set withAll: string) size = stringSize] assert.
>
> testBeginsWith
>   "Test that every prefix of the sample IS a prefix of it."
>   0 to: stringSize do: [:n |
> [string beginsWith: (string copyFrom: 1 to: n)] assert].
>
> testEndsWith
>   "Test that every suffix of the sample IS a suffix of it."
>   0 to: stringSize do: [:n |
> [string endsWith: (string copyFrom: stringSize - n + 1 to:
> stringSize)] assert].
>
> testIndexOfSubCollectionAtBeginning
>   "Test that every prefix of 'abcd' is found at the beginning."
>   0 to: stringSize do: [:n | |s i t|
> s := string copyFrom: 1 to: n.
> i := string indexOfSubCollection: s startingAt: 1.
> [1 = i] assert.
> t := string copyFrom: i to: i - 1 + n.
> [t = s] assert].
>
> testIndexOfSubCollectionAtEnd
>   "Test that every proper suffix of the sample is found at the end."
>   1 to: stringSize do: [:n | |s i t|
> s := string copyFrom: stringSize - n + 1 to: stringSize.
> i := string indexOfSubCollection: s startingAt: 1.
> [stringSize + 1 - n = i] assert.
> t := string cop

[Pharo-users] A question about #beginsWith: and #endsWith:

2022-04-20 Thread Richard O'Keefe
I've just tracked down a nasty little problem
porting some code to Pharo.  As a result, I
have added to the comments in my own versions
of these methods.beginsWith: aSequence
  "Answer true if aSequence is a prefix of the receiver.
   This makes sense for all sequences.
   There is a compatibility issue concerning 'abc' beginsWith: ''
   + VisualWorks, Dolphin, astc, GNU ST (where the method is
 called #startsWith:) and VisualAge (where the method
 is called #wbBeginsWith:)
 agree than EVERY sequence begins with an empty prefix.
   - Squeak and Pharo
 agree that NO sequence begins with an empty sequence.
   # ST/X chooses compatibility with Squeak, heaving a big unhappy
 sigh, and adds #startsWith: to have something sensible to use.
   Now ST/X *thinks* it is compatible with VW, though it isn't, so
   I wonder if this was a bug that VW fixed and Squeak didn't?
   astc goes with the majority here.  This is also compatible with
   Haskell, ML, and with StartsWith in C# and startsWith in Java."
  ^self beginsWith: aSequence ignoringCase: false

endsWith: aSequence
  "Answer true if aSequence is a suffix of the receiver.
   This makes sense for all sequences.
   There is a compatibility issue concerning 'abc' endsWith: ''.
   + VisualWorks, Dolphin, astc, GNU ST, and VisualAge (where
 the method is called #wbEndsWith:)
 agree that EVERY sequence ends with an empty suffix.
   - Squeak and Pharo
 agree that NO sequence ends with an empty suffix.
   # ST/X chooses compatibility with the majority, apparently
 unaware that this makes #beginsWith: and #endsWith: inconsistent.
   astc goes with the majority here.  This is also compatible with
   Haskell, ML, C#, and Java."
  ^self endsWith: aSequence ignoringCase: false

Does anyone have any idea
 - why Squeak and Pharo are the odd ones out?
 - why anyone thought making #beginsWith: and #endsWith:, um, "quirky"
   was a good idea (it's pretty standard in books on the theory of
   strings to define "x is a prefix of y iff there is a z such that
   y = x concatenated with z")

I was about to try to file a bug report for the first time,
then realised that maybe other people don't think this IS a bug.


[Pharo-users] Re: Intended behaviour of flatten and flatCollect:

2022-04-13 Thread Richard O'Keefe
PS: *Neither* #flattened nor #flatCollect: can be blamed on
40 years of history.  #flatten(ed) arrived in Squeak back in
2015, at which time #flatCollect: did not exist.  In fact
there is *still* no #flatCollect: in Squeak, although Squeak
does have #gather:, since 2002.

#flatCollect: was added to Pharo more recently still,
as a new name for the tolerably well established #gather:,
apparently in the belief that it was a better name.
Given #flattened, it is not.  #gather: is not all that
helpful, but #flatCollect: is just wrong.  Even if
#flattened did not exist, the result of #flatCollect:
is generally not in any sense flat.

I repeat: NONE of this can be blamed on Smalltalk history.
#flattened was born crufty in 2015 and #flatCollect: is
a recent addition to Pharo.



On Thu, 14 Apr 2022 at 02:03, Richard O'Keefe  wrote:

> It would help to know which version of Pharo you are using.
> #(1 2 3) flatten
> raises an exception in Pharo 9 because there is no #flatten
> in Array's protocol.
> Collection has
>  #flatCollect:
>-- #gather: was not a terribly helpful name,
>-- but #flatCollect: is horribly misleading.
>  #flatCollect:as:
>-- A misplaced method, should be
>-- Collection class >> withAll: aCollection gather: aBlock
>  #flatCollectAsSet:
>-- a trivial special case of #flatCollect:as:,
>-- not clear why this special case exists.
>  #flattenOn:
>-- aStream nextPutAll: self flattened
>-- but without creating the intermediate data structure
>  #flattened
>-- a curiously twisted "flatten" that does not work
>-- at all for non-collections.
>
> #(1 2 3) flattened => #(1 2 3)
> 1 flattened => BOOM!
>
> By the way, we cannot blame the cruftiness of #flattened on
> 40 years of history.  #flatten/#flattened only entered Squeak
> about 7 years ago and it was BORN crufty.  I mistakenly thought
> Squeak and Pharo agreed on what it meant.  They do not.
> Squeak: puts it on SequenceableCollection and Stream.
> Pharo : puts it on Collection (more general) and not Stream (less so).
> Squeak: treats stream elements like nested collections.
> Pharo : doesn't.
> So my earlier claim bears repeating: of the Smalltalk systems that
> have some kind of flattening, no two agree on what it means.
>
> The one use I have ever had for flattening is to build up a
> large string by accumulating characters, strings, symbols,
> and sequences of the same in a sequence and then flattening
> the tree into a single string, which is something that
> Squeak and Pharo flatly refuse to do.
>
> One improvement I would like to see in Pharo 11 is for these
> methods to be deleted.
>
>


[Pharo-users] Re: Intended behaviour of flatten and flatCollect:

2022-04-13 Thread Richard O'Keefe
It would help to know which version of Pharo you are using.
#(1 2 3) flatten
raises an exception in Pharo 9 because there is no #flatten
in Array's protocol.
Collection has
 #flatCollect:
   -- #gather: was not a terribly helpful name,
   -- but #flatCollect: is horribly misleading.
 #flatCollect:as:
   -- A misplaced method, should be
   -- Collection class >> withAll: aCollection gather: aBlock
 #flatCollectAsSet:
   -- a trivial special case of #flatCollect:as:,
   -- not clear why this special case exists.
 #flattenOn:
   -- aStream nextPutAll: self flattened
   -- but without creating the intermediate data structure
 #flattened
   -- a curiously twisted "flatten" that does not work
   -- at all for non-collections.

#(1 2 3) flattened => #(1 2 3)
1 flattened => BOOM!

By the way, we cannot blame the cruftiness of #flattened on
40 years of history.  #flatten/#flattened only entered Squeak
about 7 years ago and it was BORN crufty.  I mistakenly thought
Squeak and Pharo agreed on what it meant.  They do not.
Squeak: puts it on SequenceableCollection and Stream.
Pharo : puts it on Collection (more general) and not Stream (less so).
Squeak: treats stream elements like nested collections.
Pharo : doesn't.
So my earlier claim bears repeating: of the Smalltalk systems that
have some kind of flattening, no two agree on what it means.

The one use I have ever had for flattening is to build up a
large string by accumulating characters, strings, symbols,
and sequences of the same in a sequence and then flattening
the tree into a single string, which is something that
Squeak and Pharo flatly refuse to do.

One improvement I would like to see in Pharo 11 is for these
methods to be deleted.


[Pharo-users] Re: Intended behaviour of flatten and flatCollect:

2022-04-13 Thread Richard O'Keefe
"Flattening" is problematic in every programming language I know
that has something like it in its library.  It was born
problematic in Lisp and it has continued problematic ever since.
(I am aware of several Smalltalk systems offering it.  With the
exception of Squeak and Pharo, no two of them agree.)
The fundamental problem is that which containers (if any)
should be treated as leaves and which should not is not
something that the language can define.  It is problem-specific.
Your best bet is to figure out what YOU need for YOUR problem
and implement exactly that.

I was about to include some code I wrote while trying to make
sense of "flattening", but no.  There is no substitute for writing
something that works for precisely the objects you want it to work
and for no others.


[Pharo-users] Re: [ANN] Pharo 10 released!

2022-04-05 Thread Richard O'Keefe
Congratulations.
I am very impressed, especially by improvements coming
with a healthy reduction in size.
The Pharo team continue to amaze me.


On Tue, 5 Apr 2022 at 22:41, Esteban Lorenzano  wrote:

> Dear Pharo users and dynamic language lovers:
>
> We have released Pharo version 10  !
>
> Pharo is a pure object-oriented programming language and a powerful
> environment, focused on simplicity and immediate feedback.
>
>
> Pharo 10 was a short iteration where we focused mainly on stability and
> enhancement of the environment :
>
>
>- Massive system cleanup
>-
>   - gained speed
>   - removed dead code
>   - removed old/deprecated frameworks (Glamour, GTTools, Spec1)
>   - All Remaining tools written using the deprecated frameworks have
>been rewritten: Dependency Analyser, Critique Browser, and many other small
>utilities.
>- Modularisation has made a leap, creating correct baselines (project
>descriptions) for many internal systems, making possible the work and
>deployment of minimal images.
>- Removing support for the old Bytecode sets and embedded blocks
>simplified the compiler and language core.
>- As a result, our image size has been reduced by 10% (from 66MB to
>58MB)
>- The VM has also improved in several areas: better async I/O support,
>socket handling, FFI ABI,
>
> Even being a short iteration, we have closed a massive amount of issues:
> around 600 issues and 700 pull requests. A more extended changelog can be
> found at
> https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo100ChangeLogs.md
> .
>
> While the technical improvements are significant, still the most
> impressive fact is that the new code that got in the main Pharo 10 image
> was contributed by more than 80 people.
>
> Pharo is more than code. It is an exciting project involving a great
> community.
>
> We thank all the contributors to this release:
>
> Aaron Bieber, Ackerley Tng, Alban Benmouffek, Alejandra Cossio, Aless
> Hosry, Alexandre Bergel, Aliaksei Syrel, Alistair Grant, Arturo Zambrano,
> Asbathou Biyalou-Sama, Axel Marlard, Bastien Degardins, Ben Coman, Bernardo
> Contreras, Bernhard Pieber, Carlo Teixeira, Carlos Lopez, Carolina
> Hernandez, Christophe Demarey, Clotilde Toullec, Connor Skennerton, Cyril
> Ferlicot, Dave Mason, David Wickes, Denis Kudriashov, Eric Gade, Erik Stel,
> Esteban Lorenzano, Evelyn Cusi Lopez, Ezequiel R. Aguerre, Gabriel Omar
> Cotelli, Geraldine Galindo, Giovanni Corriga, Guille Polito, Himanshu, Jan
> Bliznicenko, Jaromir Matas, Kasper Østerbye, Kausthub Thekke Madathil,
> Konrad Hinsen, Kurt Kilpela, Luz Paz, Marco Rimoldi, Marcus Denker, Martín
> Dias, Massimo Nocentini, Max Leske, Maximilian-ignacio Willembrinck
> Santander, Miguel Campero, Milton Mamani Torres, Nahuel Palumbo, Norbert
> Hartl, Norm Green, Nour Djihan, Noury Bouraqadi, Oleksandr Zaitsev, Pablo
> Sánchez Rodríguez, Pablo Tesone, Pavel Krivanek, Pierre Misse-Chanabier,
> Quentin Ducasse, Raffaello Giulietti, Rakshit, Renaud de Villemeur, Rob
> Sayers, Roland Bernard, Ronie Salgado, Santiago Bragagnolo, Sean DeNigris,
> Sebastian Jordan Montt, Soufyane Labsari, Stephan Eggermont, Steven
> Costiou, Stéphane Ducasse, Sven Van Caekenberghe, Theo Rogliano, Thomas
> Dupriez, Théo Lanord, Torsten Bergmann, Vincent Blondeau.
>
>
> (If you contributed to Pharo 10 development in any way and we missed your
> name, please send us an email and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Discover Pharo: https://pharo.org/features
>
> Try Pharo: http://pharo.org/download 
>
> Learn Pharo: http://pharo.org/documentation
> 
>


[Pharo-users] Re: Null Object Pattern

2022-03-20 Thread Richard O'Keefe
Never forget that the Proxy pattern was developed in the context of a TYPED
programming
language.  So "Clients can't tell whether they work with a subject or its
proxy” means WITH REFERENCE
TO A STATED PROTOCOL.  Doing this in Ada or Java is fine, because you
define an interface type, and that
makes it safe.  Here is a sentence from a typical description of the
pattern: "Since the proxy implements the
INTERFACE as the original class, it can be passed to any client that
expects a real service object."  Having
a specified and *enforced* smallish interface prevents the maintenance
issues that plague attempts to use
this pattern in Smalltalk.

Remote objects and local objects have different semantics because remote
messages and local messages
have different semantics.  Local messages cannot be lost, duplicated, or
reordered, nor can communication
with a local object drop out for no local reason.  Version skew is a much
bigger problem with distributed
systems than local ones, so once again, it is proxying WITH REFERENCE TO A
STATED PROTOCOL (and
that not a large one!) that counts.  There is no such thing as a 100%
transparent remote proxy.  So it is
very useful to know what an object really is as well as what it pretends to
be.  That is,
  #class#apparentClass
  #isNil #apparentlyNil
are *different*,

So the argument thus far is
- a selector should not be inlined if it might need to be overridden
- such as in an application of the Proxy pattern
- but well-designed Proxies are such WITH REFERENCE TO STATED PROTOCOLS
- meaning that selectors that are NOT in such protocols are fair game for
inlining.


[Pharo-users] Re: Null Object Pattern

2022-03-20 Thread Richard O'Keefe
An override of #doesNotUnderstand: *is* (an instance of) the problem.
What part of "you may think you know what to forward now, but just
wait a couple of months or install an additional package and there
will be *more* selectors you needed to think about but didn't" is
hard to understand?

Proxies done right are proxies *relative to a specified protocol*.

Let me give you a personal example.
I wanted something that was like an OrderedCollection but
could only hold elements of a specific class.
No worries, just make a proxy.  Make a bare-bones object,
define all the #add... methods to check their argument,
and use #doesNotUnderstand to forward everything else to
the underlying OrderedCollection.

The first problem is the selectors that the bare-bones
object *does* understand by virtue of being an object.
(Remember there are *hundreds* of these selectors in
Squeak, Pharo, VisualWorks, even in gst there are more
than 120).  You must, for example, ensure that #instVarAt:
is forwarded, not handled locally, BUT you must also
ensure that #instVarAt:put: is handled locally, not forwarded.
And then one day you find that your program has broken,
because mutable collections now have
  aMutableCollection inPlaceCollect: collectBlock
and that can put unacceptable results in the collection
*without* going through any #add... method.

Eventually you realise "handing out a wrapper for this
collection constrained to only allow adding certain things"
is the wrong way to do it, and you do something like

constrainedAdder: constraint
  ^[:x | (constraint value: x)
   ifTrue:  [self add: x]
   ifFalse: [DomainError receiver: self selector: #add:]]

or you do something else entirely, like handing out a wrapper with
a *narrow* interface that doesn't make the slightest pretence of
*being* the other object.

I *could* make a batch of ricin and store it in my
granddaughter's bedroom, but I'm not going to.
I *could* make a proxy by going through #doesNotUnderstand:
but I am not going to.  That would be a textbook example of
maxim 38: "Just because it's easy for you doesn't mean it
can't be hard on your clients."






On Sun, 20 Mar 2022 at 15:18, James Foster  wrote:

> I don’t understand. Wouldn’t an override of #'doesNotUnderstand:’ solve
> this problem? The proxies I’ve seen subclass from nil or ProtoObject and
> forward almost everything to the target. It’s really very easy.
>
> On Mar 19, 2022, at 3:14 AM, Richard O'Keefe  wrote:
>
> An object should be a Proxy or Stub only with reference to a specific
> protocol, which should be kept narrow.
>
> Being a Proxy is a form of coupling.  Proxying a wide
> interface creates maintenance problems:
> Squeak 5.3 : Object selectors size => 485
> Pharo 9.0  : Object selectors size => 435
> astc   : Object selectors size => 325
> VW 8.3PUL  : Object selectors size => 304
>
> The interface of Object is HUGE.  You want to bet that
> your Proxy got *all* of the methods right?  This
> interface didn't get that way all at once; it grew.
> The number was 78 in Smalltalk-80.  At a minimum, then,
> Smalltalk systems have accreted one extra Object method
> every two months.
>
> So you set up your proxy to *flawlesly* mirror Object,
> and then, WHOOPS, upgrade Smalltalk and now there is a
> method that Object has and your Proxy either lacks (if
> it descends from ProtoObject but not Object) or inherits
> an inappropriate version of (if it descends from Object).
>
> What this means is that nobody ever *does* flawlessly
> mock everything in the public interface of an object
> they are Proxying.  They proxy a *limited* protocol.
> Because that is all they *can* do.
>
> Look, I know that people who have been trained to work
> with the stuff can use C4 as cooking fuel.  But I haven't
> had that training, so I won't touch the stuff.  In the
> same way, I dare say there are things *you* can safely
> do in Smalltalk that fumblefingers here would be burnt
> badly by.  There are many things that *can* be done that
> I *won't* do.  In a chemistry lab, I would not work with
> ClF3 let alone O2F2.  In Smalltalk, I don't monkey with
> #isNil.
>
> On Fri, 18 Mar 2022 at 03:52, James Foster  wrote:
>
>> Richard,
>>
>> I very much admire Dijkstra’s admonition regarding “The Humble
>> Programmer” and was pointing a student to that article just this week.
>>
>> In any case, I think you’ve demonstrated that you now comprehend the
>> argument against inlining—you just don’t agree. That’s fair and I think the
>> discussion has been clarified. Would it be fair to say that you have an
>> “ideological objection” to allowing a Proxy or Stub to transparently stand
>> in for another object (say, in a two-object-space environment such as Pharo
>> an

[Pharo-users] Re: Null Object Pattern

2022-03-19 Thread Richard O'Keefe
An object should be a Proxy or Stub only with reference to a specific
protocol, which should be kept narrow.

Being a Proxy is a form of coupling.  Proxying a wide
interface creates maintenance problems:
Squeak 5.3 : Object selectors size => 485
Pharo 9.0  : Object selectors size => 435
astc   : Object selectors size => 325
VW 8.3PUL  : Object selectors size => 304

The interface of Object is HUGE.  You want to bet that
your Proxy got *all* of the methods right?  This
interface didn't get that way all at once; it grew.
The number was 78 in Smalltalk-80.  At a minimum, then,
Smalltalk systems have accreted one extra Object method
every two months.

So you set up your proxy to *flawlesly* mirror Object,
and then, WHOOPS, upgrade Smalltalk and now there is a
method that Object has and your Proxy either lacks (if
it descends from ProtoObject but not Object) or inherits
an inappropriate version of (if it descends from Object).

What this means is that nobody ever *does* flawlessly
mock everything in the public interface of an object
they are Proxying.  They proxy a *limited* protocol.
Because that is all they *can* do.

Look, I know that people who have been trained to work
with the stuff can use C4 as cooking fuel.  But I haven't
had that training, so I won't touch the stuff.  In the
same way, I dare say there are things *you* can safely
do in Smalltalk that fumblefingers here would be burnt
badly by.  There are many things that *can* be done that
I *won't* do.  In a chemistry lab, I would not work with
ClF3 let alone O2F2.  In Smalltalk, I don't monkey with
#isNil.

On Fri, 18 Mar 2022 at 03:52, James Foster  wrote:

> Richard,
>
> I very much admire Dijkstra’s admonition regarding “The Humble Programmer”
> and was pointing a student to that article just this week.
>
> In any case, I think you’ve demonstrated that you now comprehend the
> argument against inlining—you just don’t agree. That’s fair and I think the
> discussion has been clarified. Would it be fair to say that you have an
> “ideological objection” to allowing a Proxy or Stub to transparently stand
> in for another object (say, in a two-object-space environment such as Pharo
> and GemStone)? That is, a domain object can’t be replaced by a Proxy or
> Stub without a wholesale rewrite of the rest of the application? I respect
> that as a reasonable position (demanding perfect clarity), but I see a cost
> to that position as well.
>
> Of course, if you really want to avoid allowing the receiver to chose its
> response to a message, you can use other messages. So if you want to find
> out if an object is identical to nil you should use `nil == myObject` to
> ensure that there was not an override of #’isNil’ or #’==‘ by the object’s
> class.
>
> James
>
> On Mar 17, 2022, at 2:27 AM, Richard O'Keefe  wrote:
>
> My chief concern is that I am a bear of very little brain,
> and if you change the meaning of #isNil to anything at all
> other than "is the receiver identical to nil" you *WILL*
> (not may) confuse me.  This extends to things that happen
> not to be inlined: if even a god-like Smalltalker like
> Andres Valloud overloads #, to something other than "combine
> the collection that is the receiver with the collection that
> is the argument to yield a new collection" than I *WILL*
> most certainly be confused and find the code unmaintainable.
> Smalltalk being Smalltalk, if you admit an inconsistent
> overload anywhere, I can no longer understand sends of that
> selector anywhere.  One of the things to like about Traits
> is that you can say "this class doesn't just *happen* to
> have selectors x and y, it has them *because* it has this
> whole consistent bundle of selectors."
>
> There are more annotations documented for my Smalltalk
> compiler than are actually implemented.  One that *is*
> implemented is , and it has caught more
> mistakes than I care to admit to.  It's particularly
> important for a bundle of methods with varying arguments
> that are meant to be routed through a single method,
> which *is* meant to be overridden.  It makes sure that
> I override the *right* method.  (Take #= and #~= as an
> obvious example.)
>
> Once you start down the path of lying about things like #isNil
> you find that EITHER you have to go very far down that path
> and override #== and #instVarAt: and a whole lot of other
> things OR you are working with a semantically incoherent system.
>
> "How should a proxy (https://en.wikipedia.org/wiki/Proxy_pattern) to nil
> respond to the #’isNil’ message?"
>
> It SHOULD NOT LIE.  A proxy *isn't* nil, and it doesn't *behave* like nil,
> even if it is a proxy for nil.  A proxy, qua proxy, can do things that nil
> cannot.  Use another selector, #isEffectivelyNil, or whatever 

[Pharo-users] Re: Null Object Pattern

2022-03-17 Thread Richard O'Keefe
he receiver gets to decide
> how to respond to a message. In C++ this is the distinction between a
> “virtual" and "non-virtual" function. By inlining, you are converting the
> function from a virtual function to a non-virtual function, and this can
> make a difference (which is why virtual functions exist).
>
> How should a proxy (https://en.wikipedia.org/wiki/Proxy_pattern) to nil
> respond to the #’isNil’ message? How should the Null Object Pattern (
> https://en.wikipedia.org/wiki/Null_object_pattern) respond to #’isNil’?
>
> And, yes, I’m sure you can come up with benchmarks that show a measurable
> difference, but what is the impact in realistic code? When someone asked
> about inlining #’yourself’ in GemStone I believe I measured the performance
> as taking 2 nanoseconds per call (on a 2012 machine). A 10% speedup would
> make it 1.8 nanoseconds. Is that worth it? Maybe, maybe not.
>
> Note that I described my position as a “concern,” not an ideological
> objection. Mostly I’m giving a rationale for something that doesn’t seem to
> be explained very well for you. I accept that there may be a time for
> inlining, but I can “comprehend" another side to the issue.
>
> James
>
> On Mar 16, 2022, at 9:42 PM, Richard O'Keefe  wrote:
>
> We're still not on the same page.
> You seem to have some ideological objection to inlining that
> I am completely failing to comprehend.
> Just because a procedure call (message send) is inlined doesn't
> in the least mean it *isn't* a procedure call (message send),
> just as compiling a procedure call (message send) as a jump
> (last-call optimisation) doesn't mean it *isn't* a procedure
> call (message send).
> By the way, forget about "40 years ago".
> I just did an experiment in Pharo 9, and found that
> using "_ ifNotNil: " instead of "_ izNil ifFalse: "
> -- where izNil is a non-inlined self == nil --
> gave a 10% speedup, in a test code where real work was going
> on as well.
> As for turning off all inlining, what do you think that would
> do to #ifFalse:ifTrue: and its relatives?
>
>
> On Thu, 17 Mar 2022 at 08:34,  wrote:
>
>>
>> To start with, why do you CARE whether a particular method is inlined or
>> not?
>>
>> I care because it makes “everything is a message” a lie! And I suspect
>> (no proof and could be wrong) it’s an optimization that only made sense
>> with the hardware constraints of 40+ years ago. Arguing against premature
>> optimization is hardly something I just made up ;-)
>>
>> This makes absolutely no sense to me. What makes you think that the
>> combination "_ isNil ifFalse: [_]" will NOT be inlined?
>>
>> I may have been unclear. My intent was to communicate: “I’d like to stop
>> ALL* inlining of messages by default if possible”
>>
>> *or as many as practical
>>
>> The thing that rings loud alarm bells for me is there being "long chains"
>> in the first place.
>>
>> I agree that it is in general a smell, but long chains was tangential to
>> the intention above
>>
>> Can you give an example?
>>
>> I don’t know if I can think of one that’s not contrived… Wrapping
>> something external? Squeak’s AppleScript support used to mirror the
>> underlying AS, which is pretty much exactly that.
>>
>> In my own programming, I've generally found that nils turning up in the
>> middle of a chain indicates a serious design error somewhere.
>>
>> Agreed. See smell comment above.
>>
>
>


[Pharo-users] Re: Null Object Pattern

2022-03-16 Thread Richard O'Keefe
We're still not on the same page.
You seem to have some ideological objection to inlining that
I am completely failing to comprehend.
Just because a procedure call (message send) is inlined doesn't
in the least mean it *isn't* a procedure call (message send),
just as compiling a procedure call (message send) as a jump
(last-call optimisation) doesn't mean it *isn't* a procedure
call (message send).
By the way, forget about "40 years ago".
I just did an experiment in Pharo 9, and found that
using "_ ifNotNil: " instead of "_ izNil ifFalse: "
-- where izNil is a non-inlined self == nil --
gave a 10% speedup, in a test code where real work was going
on as well.
As for turning off all inlining, what do you think that would
do to #ifFalse:ifTrue: and its relatives?


On Thu, 17 Mar 2022 at 08:34,  wrote:

>
> To start with, why do you CARE whether a particular method is inlined or
> not?
>
> I care because it makes “everything is a message” a lie! And I suspect (no
> proof and could be wrong) it’s an optimization that only made sense with
> the hardware constraints of 40+ years ago. Arguing against premature
> optimization is hardly something I just made up ;-)
>
> This makes absolutely no sense to me. What makes you think that the
> combination "_ isNil ifFalse: [_]" will NOT be inlined?
>
> I may have been unclear. My intent was to communicate: “I’d like to stop
> ALL* inlining of messages by default if possible”
>
> *or as many as practical
>
> The thing that rings loud alarm bells for me is there being "long chains"
> in the first place.
>
> I agree that it is in general a smell, but long chains was tangential to
> the intention above
>
> Can you give an example?
>
> I don’t know if I can think of one that’s not contrived… Wrapping
> something external? Squeak’s AppleScript support used to mirror the
> underlying AS, which is pretty much exactly that.
>
> In my own programming, I've generally found that nils turning up in the
> middle of a chain indicates a serious design error somewhere.
>
> Agreed. See smell comment above.
>


[Pharo-users] Re: BlockClosure folding

2022-03-16 Thread Richard O'Keefe
Pattern?  I'd call it an antipattern myself.
Note that we can already construct
  { block1
  . block2
  . block3
  }
and write
  { block1
  . block2
  . block3
  } allSatisfy: [:each | each value].
so we don't have to abuse the #, selector
or write a single new method to get the "flattened"
structure you're after.

Collection
  methods for: 'collections of blocks'
allSatisfied
  ^self allSatisfy: [:each | each value]
anySatisfied
  ^self anySatisfy: [:each | each value]
noneSatisfied
  ^self noneSatisfy: [:each | each value]

if you do feel like adding a few methods, whereupon
  { block1
  . block2
  . block3
  } allSatisfied

Didn't VW recently implement {} syntax natively?
Or was that VAST?

In all seriousness, when is it better to use
ComplexCondition than to rewrite?



On Wed, 16 Mar 2022 at 14:38, Hernán Morales Durand <
hernan.mora...@gmail.com> wrote:

> This is an interesting pattern.
> Thank you for sharing.
>
> Hernán
>
> El mar, 15 mar 2022 a las 4:43, Julián Maestri ()
> escribió:
>
>> Not satisfying the equality, but you can use polymorphism.
>>
>> Block >> , aBlock
>> ^ BlockCompositor andAll: OrderedCollection with: self with: aBlock
>>
>> BlockCompositor >> #, aBlock
>> conditions add: aBlock.
>>
>> BlockCompositor >> value: anObject
>> ^ conditions allSatisfy: [:e | e value: anObject ]
>>
>> I don't really like the name BlockCompositor, but can't think of a better
>> name at the moment.
>>
>> You could also implement logic for #or: using #+ and: #anySatisfy: for
>> example, but need to safeguard against mixing both conditions.
>>
>> On Mon, 14 Mar 2022 at 22:29, Hernán Morales Durand <
>> hernan.mora...@gmail.com> wrote:
>>
>>> I think I saw a coding pattern a while ago that allows you to do the
>>> following:
>>>
>>> cond1 , cond2 , cond3 , cond4
>>>
>>> And providing a kind of folding selector condition #and: you would get:
>>>
>>> [ cond1 and: [ cond2 and: [ cond3 and: [ cond4 ] ] ] ].
>>>
>>> for example:
>>>
>>> conditions := [ : each | each firstName = 'Boca' ] ,
>>> [ : each | each lastName = 'Baret' ] ,
>>> [ : each | each fullName = 'Virgasia' ].
>>>
>>> such that the following assert is met:
>>>
>>> self assert: conditions equals: [ : each | each firstName = 'Boca' and:
>>> [ each lastName = 'Baret' and: [ each fullName = 'Virgasia' ] ] ].
>>>
>>> Any ideas or pointers?
>>>
>>> Cheers,
>>>
>>> Hernán
>>>
>>>


[Pharo-users] Re: BlockClosure folding

2022-03-16 Thread Richard O'Keefe
The motivating example can be written

aHasDot := a includes: $..
bHasDot := b includes: $..
^aHasDot = bHasDot
   ifFalse: [bHasDot]
   ifTrue:  [aHasDot
   ifTrue:  [a < b]
   ifFalse: [a > b]]

(Dijkstra was right.  People *do* forget that '=' is
one of the standard Boolean operations, and it matters.)
This is absolutely straightforward, and without wasting
any time wondering what the three-headed IF monster is,
we can go straight to the big puzzle: "I can see at a
glance what this DOES, but what the heck does it MEAN?"
When would this be useful?  What would be a good name for
this combination, however expressed?

I think the moral here is "when you have code whose
structure is so complex that you are tempted to construct
special control flow objects to make it LOOK simpler,
rewrite it so that it IS simpler."

I once wrote a class called Distributor based on Boost
'signal's.  It was an interesting exercise, and I am
still finding mistakes in it.  It was not entirely unlike
ComplexCondition.  What I *haven't* done in the 10 years
since I wrote it is found any use for it.


On Wed, 16 Mar 2022 at 07:15,  wrote:

> ComplexCondition as described in Andres Valloud, "A Mentoring Course on
> Smalltalk"
> 
> is available at http://www.squeaksource.com/ComplexCondition.html
>
> With it, you can do something like:
>
> ^[a includes: $.], [b includes: $.]
> ifAllTrue: [a < b]
> ifAnyTrue: [b includes: $.]
> otherwise: [a > b]
>
>


[Pharo-users] Re: Null Object Pattern

2022-03-15 Thread Richard O'Keefe
I have a bad feeling about this.
To start with, why do you CARE whether a particular
method is inlined or not?


However, I’m struggling a bit with the refactor due to inlining. Since
#ifNil: variants might be inlined, it seems that something like:

anObject with a long chain of messages ifNotNil: [ :result | “…” ]

must be changed into something like:

anObject with a long chain of messages isNil ifFalse: [ anObject with a
long chain of messages “…” ].


This makes absolutely no sense to me.  What makes you think that the
combination "_ isNil ifFalse: [_]" will NOT be inlined?  In Squeak,
x ifNotNil: [...]
turns into x; nil; ==; jumpFalse
and
x isNil ifFalse: [...]
turns into x; send isNil; jumpFalse
where "send isNil" is a single byte.  I don't see a substantial difference
here.
(I'd have checked in Pharo, but after many interface changes I no longer
know
how to do view|bytecode.)
The thing that rings loud alarm bells for me is there being "long chains"
in the first place.

Can you give an example?

In my own programming, I've generally found that nils turning up in the
middle of a chain indicates a serious design error somewhere.

On Wed, 16 Mar 2022 at 07:16,  wrote:

> I had some chaining that was getting too complex due to many nil checks,
> so I started to refactor using a Null Object.
>
> However, I’m struggling a bit with the refactor due to inlining. Since
> #ifNil: variants might be inlined, it seems that something like:
>
> anObject with a long chain of messages ifNotNil: [ :result | “…” ]
>
> must be changed into something like:
>
> anObject with a long chain of messages isNil ifFalse: [ anObject with a
> long chain of messages “…” ].
>
> Obviously, I can use a temp to have:
>
> result := anObject with a long chain of messages.
>
> result isNil ifFalse: [ result “…” ].
>
> But both seem ugly and make me question using this pattern.
>
>1.
>
>What am I missing?
>2.
>
>After 40+ years of Moore’s Law, can we turn off these inlines by
>default?
>
>


[Pharo-users] Re: Pharo with Style (new version) is now available as physical book

2022-03-13 Thread Richard O'Keefe
Congratulations.



On Sun, 13 Mar 2022 at 08:44, stephane ducasse 
wrote:

>
> https://www.amazon.fr/Pharo-Style-Stéphane-Ducasse/dp/232218201X/ref=sr_1_1?__mk_fr_FR=ÅMÅŽÕÑ=15GN4OFOFHK56=Pharo+with+style=1647113931=pharo+with+style%2Caps%2C60=8-1
> 
>
> https://www.decitre.fr/livre-pod/pharo-with-style-9782322182015.html
>
>
> https://www.bod.fr/librairie/pharo-with-style-stephane-ducasse-9782322182015
>
> I will update the web site as soon as I get time.
>
> S
>


[Pharo-users] Re: Too many parenthesis - a matter of syntax

2022-02-28 Thread Richard O'Keefe
The fact that there is more than you want is precisely why you want to make
classes for the
data you *do* want.

I do have kit for streaming JSON out directly without creating JSON data
internally,
but I'm still trying to find a good way to stream JSON in creating wanted
objects
on-the-fly so that the unwanted data are never stored.  I think it can be
done from
the same schema language that I use to generate classes.

On Mon, 28 Feb 2022 at 20:09, Kasper Osterbye 
wrote:

> Thanks Richard,
>
> I tend to agree with your design experience. As it happens, in my concrete
> code I get JSON back from a github api which serves me more than I want. I
> am therefore not interested in making classes for those aspects of the data
> I throw out.
>
> The way I handle this in practice myself is to introduce a local variable
> for each level. Makes it easier to debug too.
>
> Best,
>
> Kasper
>
> On 27 Feb 2022, at 00.42, Richard O'Keefe  wrote:
>
> I was bemused to realise that I've actually been programming
> for literally 50 years. It finally seeped through my thick
> skull I make enough mistakes that if it's hard to read, I
> probably got it wrong.  And THIS code fragment is hard to
> read.  I don't care if you use parentheses or pipes, it's
> hard to read either way.  Oh, the pipes make the structure
> easier to see, true.  But I am still left guessing what it
> is FOR.  What's it SUPPOSED to mean?  And the problem is that
> there are some abstractions missing.  Of course this is JSON's
> fault.
>
> This is the first code smell, and in my experience it is
> almost ALWAYS a code smell:  you are using JSON as a
> "processing" data structure instead of as a "communication"
> syntax.  Using JSON inside your program, instead of at the
> edges, means that the semantics gets scattered all over the
> code, which leads to complexity and inconsistency.
>
> The convention I follow is that data structure more complicated
> than a string or an array of numbers has a Smalltalk class
> Whatsit>>asJson converts an instance to a JSON value
> Whatsit class>>fromJson: converts a JSON value to an instance.
> I'll start with
>topLevel := TopLevelWhatsit fromJson: someStream nextJson.
> and from then on I'm working with pure Smalltalk.
>
> This has the extra benefit of validating the input right away.
> I don't want my program running for several hours and then
> running into trouble because some component of the JSON value
> is missing or ill-formed.
>
> In practice, the time cost of converting JSON to (application-
> specific) Smalltalk is quite small compared with the cost of
> reading the JSON in the first place, and there can be seriously
> worthwhile savings in memory.
>
> For this example, we'd be looking at
>topLevel tree blobs
>   collect: [:each | each path]
>   thenSelect: [:path | path hasAnyExtension: #('md' 'mic')]
>
> My Filename class has methods
>   has[Any]Extension:[ignoringCase:]
> which I have shamelessly exploited here.  I like the
> way that they hide the structure of a Filename.
>
> The portmanteau methods
> Collection>>collect:thenSelect:
> Collection>>select:thenCollect:
> have existed in Pharo as long as Pharo has existed.
> They have two rationales:
> (a) improve readability
> (b) permit optimisation by eliminating an intermediate collection.
> Sequences exploit (b). Sets could too but happen not to.
>
> THEREFORE, here are free implementations of
> Set>>collect:thenSelect: and Set>>select:thenCollect:
> consistent with Pharo's Set>>collect:
>
> collect: collectBlock thenSelect: selectBlock
>   "Override Collection>>collect:thenSelect: like OrderedCollection.
> Beware: 'self species' is often inappropriate, as in #collect:."
>   |newSet|
>   newSet := self species new: self size.
>   self do: [:each |
> |item|
> item := collectBlock value: each.
>   (selectBlock value: each) ifTrue: [newSet add: item]].
>   ^newSet
>
> select: selectBlock thenCollect: collectBlock
>   "Override Collection>>select:thenCollect: like OrderedCollection.
> Beware: 'self species' is often inappropriate, as in #collect:."
>|newSet|
>newSet := self species new: self size.
>self do: [:each |
>  (selectBlock value: each) ifTrue: [
>newSet add: (collectBlock value: each)]].
>^newSet
>
>
>
> On Wed, 26 Jan 2022 at 22:19, Kasper Osterbye 
> wrote:
>
>> Cheers all
>>
>> I have noticed that I often ends up with quite a number of nested
>> expressions, for example:
>>
>> (((json at: 'tree')
>> select: [ :e | (e at: 'type') = ‘blob' ])
>

[Pharo-users] Re: Too many parenthesis - a matter of syntax

2022-02-26 Thread Richard O'Keefe
I was bemused to realise that I've actually been programming
for literally 50 years. It finally seeped through my thick
skull I make enough mistakes that if it's hard to read, I
probably got it wrong.  And THIS code fragment is hard to
read.  I don't care if you use parentheses or pipes, it's
hard to read either way.  Oh, the pipes make the structure
easier to see, true.  But I am still left guessing what it
is FOR.  What's it SUPPOSED to mean?  And the problem is that
there are some abstractions missing.  Of course this is JSON's
fault.

This is the first code smell, and in my experience it is
almost ALWAYS a code smell:  you are using JSON as a
"processing" data structure instead of as a "communication"
syntax.  Using JSON inside your program, instead of at the
edges, means that the semantics gets scattered all over the
code, which leads to complexity and inconsistency.

The convention I follow is that data structure more complicated
than a string or an array of numbers has a Smalltalk class
Whatsit>>asJson converts an instance to a JSON value
Whatsit class>>fromJson: converts a JSON value to an instance.
I'll start with
   topLevel := TopLevelWhatsit fromJson: someStream nextJson.
and from then on I'm working with pure Smalltalk.

This has the extra benefit of validating the input right away.
I don't want my program running for several hours and then
running into trouble because some component of the JSON value
is missing or ill-formed.

In practice, the time cost of converting JSON to (application-
specific) Smalltalk is quite small compared with the cost of
reading the JSON in the first place, and there can be seriously
worthwhile savings in memory.

For this example, we'd be looking at
   topLevel tree blobs
  collect: [:each | each path]
  thenSelect: [:path | path hasAnyExtension: #('md' 'mic')]

My Filename class has methods
  has[Any]Extension:[ignoringCase:]
which I have shamelessly exploited here.  I like the
way that they hide the structure of a Filename.

The portmanteau methods
Collection>>collect:thenSelect:
Collection>>select:thenCollect:
have existed in Pharo as long as Pharo has existed.
They have two rationales:
(a) improve readability
(b) permit optimisation by eliminating an intermediate collection.
Sequences exploit (b). Sets could too but happen not to.

THEREFORE, here are free implementations of
Set>>collect:thenSelect: and Set>>select:thenCollect:
consistent with Pharo's Set>>collect:

collect: collectBlock thenSelect: selectBlock
  "Override Collection>>collect:thenSelect: like OrderedCollection.
Beware: 'self species' is often inappropriate, as in #collect:."
  |newSet|
  newSet := self species new: self size.
  self do: [:each |
|item|
item := collectBlock value: each.
  (selectBlock value: each) ifTrue: [newSet add: item]].
  ^newSet

select: selectBlock thenCollect: collectBlock
  "Override Collection>>select:thenCollect: like OrderedCollection.
Beware: 'self species' is often inappropriate, as in #collect:."
   |newSet|
   newSet := self species new: self size.
   self do: [:each |
 (selectBlock value: each) ifTrue: [
   newSet add: (collectBlock value: each)]].
   ^newSet



On Wed, 26 Jan 2022 at 22:19, Kasper Osterbye 
wrote:

> Cheers all
>
> I have noticed that I often ends up with quite a number of nested
> expressions, for example:
>
> (((json at: 'tree')
> select: [ :e | (e at: 'type') = ‘blob' ])
> collect: [:e | Path from: (e at: 'path')])
> select: [ :p | p segments last
> in: [ :name | (name endsWith: '.md') |
> (name endsWith: '.mic') ] ]
>
> What kind of proposals (if any) have been for a different syntax which
> could give a more streamlined syntax?
>
> My own thinking has been around an alternative to the cascade semicolon.
> What symbol to use does not matter for me, but something like
> json at: ‘tree' º
> select: [ :e | ((e at: 'type') = 'blob’)]º
> collect: [:e | Path from: (e at: 'path’)]º
> select: [ :p | p segments last
> in: [ :name | (name endsWith: '.md') | (name endsWith:
> '.mic') ] ]
>
> Basically, a send the right hand expression to the result of the left hand
> expression.
>
> Has anyone ever tried this, or is it just one of the many small annoyances
> best left alone?
>
> Best,
>
> Kasper


[Pharo-users] Re: Pharo-WebView

2021-12-17 Thread Richard O'Keefe
Ta muchly.  Appreciated.


On Fri, 17 Dec 2021 at 06:03, Tomaž Turk  wrote:

> Dear all,
>
> Pharo-WebView package is now available on GitHub at
> https://github.com/eftomi/Pharo-Webview.
>
> Pharo-WebView is a package which implements a binding to webview dll
> library available at https://github.com/webview/webview in Pharo. Webview
> allows you to show HTML user interfaces in a native window, inject
> JavaScript code and HTML content into the window. It renders HTML
> originating via web requests or as a direct input.
>
> I tested it on Windows 64 bit in Pharo 64, I plan to do that on Pharo 32
> and Linux, however I don't have access to Mac, so if anybody is interested,
> I'd be grateful :-)
>
> Best wishes,
> Tomaz
>
>


[Pharo-users] Re: InstanceVariables

2021-12-08 Thread Richard O'Keefe
If you are coming from a Pascal background,
instance variables of an object
 correspond to
fields of a record.

They are called instance variables
- because they are variables
- that belong to INSTANCES of a class (object)
as opposed to class variables
 - which are variables
 - that belong to the CLASS itself and are thus
   shared by all instances.

Other programming languages use terminology like slots,
fields, data members, ...

The keyword 'instanceVariableNames:' is used because the
string that follows contains the names of the variables,
not the variables themselves.

One thing to note is that in Smalltalk all instance
variables (fields, slots, whatever) are PRIVATE.  These
are not the names of accessor methods, although there
may be accessor methods with the same spelling.


On Tue, 7 Dec 2021 at 05:32,  wrote:

> Object subclass: #Test
> instanceVariableNames: 'var1 var2'
> classVariableNames: ''
> package: 'MyTest'
>
> I was struggling with instanceVariableNames even though they show up under 
> methods.  Perhaps I'm just slow, but it wasn't until last night when I was 
> reading on Object Pascal and there was an example:
>
> type
>   TProjector = class(TTelevision)
> Brightness, Temperature: Integer;
> procedure Focus(Length: Single);
>   end;
>
> Then it finally clicked with me that "var1" and "var2" under instance 
> variables in Smalltalk would be like the method "Focus" in Object Pascal.  Is 
> that correct, or am I still not getting it?
>
>


[Pharo-users] Re: Pharo Graphs

2021-12-01 Thread Richard O'Keefe
Brilliant!  Ta muchly.


On Thu, 2 Dec 2021 at 03:56, Sebastian Jordan Montano <
sebastian.jor...@inria.fr> wrote:

> Hello everybody,
>
> We are happy to announce that we have a brand new library for graphs
> algorithms in Pharo! We have implemented some of the most-know graph
> algorithms like: Dijkstra, Tarjan, BFS, Kruskal, Topological Sort, and more.
> Here is the GitHub repository:
> https://github.com/pharo-ai/graph-algorithms
>
> Also, we wrote a booklet for the ones interested in graph theory in the
> computer science context. In the booklet, we explain how the algorithms
> work, the logic behind them, and the Pharo implementation. Also, we show in
> which real-life scenarios they can be applied.
> Here is the booklet link:
> https://github.com/SquareBracketAssociates/Booklet-PharoGraphs (there is
> the link of pdf on the README).
>
> We are interested in any kind of feedback!
>
> Thanks,
> Sebastian Jordan
>


[Pharo-users] Re: Silly question about storing and displaying currency amounts?

2021-08-31 Thread Richard O'Keefe
I have
  ScaledDecimal, based on the ANSI Smalltalk standard, but
  fixed point decimal arithmetic, because that's what the ANSI Smalltalk
  standard calls for (citing a non-existent part of the LIA standard) but
  contradicts

  FixedPoint, a version of that specifically intended for plugging into
  Squeak and/or Pharo, the snag being that I don't seem to have kept
  the change set, just the master.  I can recreate and donate the
  change set if anyone would like it.

  PackedDecimal, which just models VisualAge 31-digit packed decimal
  for interoperability, but does not do arithmetic.

On Tue, 31 Aug 2021 at 19:44, Guillermo Polito
 wrote:
>
> Hi all,
>
> In the past months I worked a bit with it and found many problems too, like:
>  - doing scaled decimal arithmetics losing precision
>https://github.com/pharo-project/pharo/issues/8668
>  - strange default scale values
>https://github.com/pharo-project/pharo/issues/8669
>
> I also got hit with “downgrading" issues during my vacation coding. For 
> example, when operating a scaled decimal with a float, the result gets 
> downgraded to a float.
> See
>
>   17.777 asScaledDecimal + 0.0
>
> From all the comments I understand that the current implementation is not 
> very useful, they all lead to “do not use it, instead do XXX” where XXX is 
> either
>  - write your own
>  - load that other package
>  - use an integer to represent pennies
>
> This this means that either it can be removed, or it can benefit with a new 
> and better implementation.
> I think it would be interesting to have a better ScaledDecimal 
> implementation, that not only does precise printing but also precise 
> arithmetics.
>
> Or maybe somebody has a good implementation already available?
>
> Cheers,
> Guille
>
> > El 31 ago 2021, a las 0:58, Richard O'Keefe  escribió:
> >
> > Ah, you have run into the insufficiently well known
> > "ScaledDecimal looks like what you need but isn't".
> >
> > In VisualAge, you have a data type that is basically a reflection of iBM
> > mainframe "packed decimal" format, and perfectly suits the needs of
> > an SQL or COBOL interface.  It gives you round-tripping with no error.
> >
> > In my Smalltalk, ScaledDecimal is a pair (n,s) where n and s are
> > unrestricted integers, representing n * (10 raisedTo: s).  This also
> > gives you exact round-tripping and suits the needs of an SQL or COBOL
> > interface.
> >
> > However, in Squeak and Pharo, ScaledDecimal is something else
> > entirely.  Basically, a pair (q,s) where q is an Integer or Fraction,
> > and s is a scale factor used for *printing*. This doesn't just lead to
> > oddities like two unequal ScaledDecimals printing identically, it
> > leads to rounding issues. This is not a bug, it is ScaledDecimal working
> > as designed.
> >
> > Working within Squeak, the simplest approach is to represent money as
> > pence, and the next simplest is to make or find a Money class.
> >
> > On Tue, 31 Aug 2021 at 00:02, David Pennington  
> > wrote:
> >>
> >> Hi everyone. I have a little bank analysis package for my own use but 
> >> having trouble displaying and storing amounts. I parse out a CSV file from 
> >> the bank and convert the amounts from text to ScaledDecimal. I then store 
> >> these into a STON file, which converts them back to text. I then read them 
> >> in and convert them back to ScaledDecimal again.
> >>
> >> I am not used to ~Pharo have spent 24 years using VisualAge Smalltalk so I 
> >> need a little bit of help because I am getting 1 Penny errors in the 
> >> conversions. I can cope with this but I would like to get it right.
> >>
> >> Can anyone give me a simple means of managing, say, an amount like £76.49 
> >> from the bank so that it stops coming back to me as £76.48?
> >>
> >> David
> >> Totally Objects


[Pharo-users] Re: Silly question about storing and displaying currency amounts?

2021-08-30 Thread Richard O'Keefe
Ah, you have run into the insufficiently well known
"ScaledDecimal looks like what you need but isn't".

In VisualAge, you have a data type that is basically a reflection of iBM
mainframe "packed decimal" format, and perfectly suits the needs of
an SQL or COBOL interface.  It gives you round-tripping with no error.

In my Smalltalk, ScaledDecimal is a pair (n,s) where n and s are
unrestricted integers, representing n * (10 raisedTo: s).  This also
gives you exact round-tripping and suits the needs of an SQL or COBOL
interface.

However, in Squeak and Pharo, ScaledDecimal is something else
entirely.  Basically, a pair (q,s) where q is an Integer or Fraction,
and s is a scale factor used for *printing*. This doesn't just lead to
oddities like two unequal ScaledDecimals printing identically, it
leads to rounding issues. This is not a bug, it is ScaledDecimal working
as designed.

Working within Squeak, the simplest approach is to represent money as
pence, and the next simplest is to make or find a Money class.

On Tue, 31 Aug 2021 at 00:02, David Pennington  wrote:
>
> Hi everyone. I have a little bank analysis package for my own use but having 
> trouble displaying and storing amounts. I parse out a CSV file from the bank 
> and convert the amounts from text to ScaledDecimal. I then store these into a 
> STON file, which converts them back to text. I then read them in and convert 
> them back to ScaledDecimal again.
>
> I am not used to ~Pharo have spent 24 years using VisualAge Smalltalk so I 
> need a little bit of help because I am getting 1 Penny errors in the 
> conversions. I can cope with this but I would like to get it right.
>
> Can anyone give me a simple means of managing, say, an amount like £76.49 
> from the bank so that it stops coming back to me as £76.48?
>
> David
> Totally Objects


[Pharo-users] Re: Private Methods

2021-08-20 Thread Richard O'Keefe
One of the claimed benefits of object-oriented programming is ENCAPSULATION.
The idea is that one of the ways a language helps you is by making some errors
difficult or impossible to express.
One of the things you need to understand an object is its INVARIANT.
For example, astc's SortedCollection includes

  methods for: 'checking'
invariant
  ^(opposite isNil or: [
opposite isKindOf: DyadicBlock]) and: [
   super invariant and: [
   (sortBlock
 ifNil:[(offset + 2 to: offset + size) allSatisfy: [:i |
 (array at: i-1) <= (array at: i)]]
 ifNotNil: [(sortBlock respondsTo: #value:value:) and: [
 [(offset + 2 to: offset + size) allSatisfy: [:i |
   (sortBlock value: (array at: i-1)
  value: (array at: i)))]]

Private methods are allowed to break the invariant.
Public methods are not.

For example, consider reversing a SortedCollection.
Part of this changes the order of the elements, and can be
shared with OrderedCollection.  Part of it swaps the arguments
of the sortBlock, and cannot be shared.

  methods for: 'rearranging'
pvtPrereverse
  |t|
  opposite
ifNil: [
  sortBlock ifNil: [sortBlock := Magnitude defaultSortBlock].
  t := sortBlock.
  opposite := sortBlock.
  sortBlock := [:x :y | t value: y value: x]]
ifNotNil: [
  t := sortBlock.
  sortBlock := opposite.
  opposite := t].

If this method could be called from "outside", it would certainly break
the invariant and leave the object in an unusable state.

Now a style rule doesn't *quite* prevent this method being called by
another object.
It is necessary to make sure that #perform: and friends cannot break
encapsulation
either, and this astc does by simply not creating Selector objects for
private methods.

Yes, it is a small increase in the complexity of the language, however
- you are not forced to write private methods
- if you run code that uses the pvt* convention in a Smalltalk that does
  not use that convention, it works, it's just not safe any longer
- it is not an arbitrary addition to the language, it is a restriction that
  makes programming *easier*.

Let's look at one additional example.
Behavior>>
new
^ self basicNew initialize

This means that *any* object can forcibly reinitialize *any* object it can
reach at *any* time.  In astc, it's

new
"other checks"
^self pvtNew pvtPostNew

and an object cannot be reinitialised against its will.

There is a long standing tradition of "program for the typical case and trust
the omniscient programmer to know what will probably work and what won't"
in Smalltalk.  This is why in many Smalltalks
  aCollection addAll: aCollection
or
  aCollection removeAll: aCollection
can go insane for some common collections.  And one *DOES* get away
with it most of the time.  It's typically when someone else triest to use your
code and doesn't know the assumptions you didn't bother to write down
that things go wrong.  It's obvious that Pharo has got to where it
amazingly well is without the "bondage and discipline" of, say, Ada or
Agda.  But there is a *reason* why Pharo has lint checking on by default.

On Fri, 20 Aug 2021 at 00:59, Jesus Mari Aguirre  wrote:
>
> Please keep Pharo simple, why do you need private methods...you can include 
> then in a protocol named private...other language have it...yes...next 
> addition will be namespaces...other...I don't know...at last we have Java
>
> El jue., 19 ago. 2021 9:00, Richard O'Keefe  escribió:
>>
>> Many years ago there was a proposal in the Squeak mailing list about 
>> enforcing
>> a naming convention, "pvt",  I implemented that in my Smalltalk system.  The
>> compiler enforces the rule that pvt.[A-Z].* message can only be sent to
>> (self|super) (basicNew|basicNew: n|new|new: n|pvtNew: n)?
>> in a class method or
>> (self|super) ((class (new|new: n)|pvtSpeciesNew: n|pvtClone)?
>> in an instance method.
>> There are currently
>> 9412 public selectors
>>  793 pvt* selectors and
>>23 private* selectors,
>> where the last group is methods that I *want* to be private in some sense but
>> cannot do with this machinery.  (For example, calling a "private" method on
>> another object known to be of the same class.)
>>
>> I think the evidence shows that this works well enough to be useful, even if 
>> it
>> isn't quite as expressive as I'd like.  And what *that* means is that
>> this can be
>> done with a style check, using the machinery Pharo already has for style 
>> checks.
>>
>>
>>
>> On Wed, 18 Aug 2021 at 08:14, Craig Johnson  wrote:
>> >
>> > Hi All,
>> >
>

[Pharo-users] Re: Private Methods

2021-08-19 Thread Richard O'Keefe
Many years ago there was a proposal in the Squeak mailing list about enforcing
a naming convention, "pvt",  I implemented that in my Smalltalk system.  The
compiler enforces the rule that pvt.[A-Z].* message can only be sent to
(self|super) (basicNew|basicNew: n|new|new: n|pvtNew: n)?
in a class method or
(self|super) ((class (new|new: n)|pvtSpeciesNew: n|pvtClone)?
in an instance method.
There are currently
9412 public selectors
 793 pvt* selectors and
   23 private* selectors,
where the last group is methods that I *want* to be private in some sense but
cannot do with this machinery.  (For example, calling a "private" method on
another object known to be of the same class.)

I think the evidence shows that this works well enough to be useful, even if it
isn't quite as expressive as I'd like.  And what *that* means is that
this can be
done with a style check, using the machinery Pharo already has for style checks.



On Wed, 18 Aug 2021 at 08:14, Craig Johnson  wrote:
>
> Hi All,
>
>
> Just a newb off-the-wall question.
>
> Is there any good reason why we can't create a true private method in a
> Pharo class by putting that method inside an instance or class variable
> as a lambda (block).
>
>
> This would reduce one of my biggest bugbears with Pharo, namely the
> pollution of the global namespace with every single message name in the
> entire system.
>
>
>
> Craig


[Pharo-users] Re: Introducing new feature dataTypes for the PolyMath/DataFrame project

2021-08-08 Thread Richard O'Keefe
Neither of those use cases actually works.
Consider the following partial class hierarchy from my Smalltalk system:
Object
 VectorSpace
  Complex
  Quaternion
 Magnitude
  MagnitudeWithAddition
   DateAndTime
   QuasiArithmetic
Duration
Number
 AbstractRationalNumber
  Integer
   SmallInteger

There is a whole fleet of "numeric" things like Matrix3x3 which have
some arithmetic properties
but which cannot be given a total order consistent with those
properties.  Complex is one of them.
It makes less than no sense to make Complex inherit from Magnitude, so
it cannot inherit from
Number, This means that the common superclass of 1 and 1 - 2 i is
Object.  Yet it makes perfect
sense to have a column of Gaussian integers some of which have zero
imaginary part.
So "the dataType is Object means there's an error" fails at the first
hurdle.  Conversely, the
common superclass of 1 and DateAndTime now is MagnitudeWithAddition,
which is not Object,
but the combination is probably wrong, and the dataType test fails at
the second hurdle.

"You might want to compute an average..."  But dataType is no use for
that either, as I was at
pains to explain.  If you have a bunch of angles expressed as Numbers,
you *can* compute an
arithmetic mean of them, but you *shouldn't*, because that's not how
you compute the
average of circular measures.  The obvious algorithm (self sum / self
size) does not work at
all for a collection of DateAndTimes, but the notion of average makes
perfect sense and a
subtly different algorithm works well.  (I wrote a technical report
about this, if anyone is interested.)
dataType will tell you you CAN take an average when you cannot or should not.
dataType will tell you you CAN'T take an average when you really honestly can.

The distinctions we need to make are not the distinctions that the
class hierarchy makes.

For example, how about the distinction between *ordered* factors and
*unordered* factors?



On Mon, 9 Aug 2021 at 03:03, Konrad Hinsen  wrote:
>
> "Richard O'Keefe"  writes:
>
> > My difficulty is that  from a statistics/data science perspective,
> > it doesn't seem terribly *useful*.
>
> There are two common use cases in my experience:
>
> 1) Error checking, most frequently right after reading in a dataset.
>A quick look at the data types of all columns shows if it is coherent
>with your expectations. If you have a column called "data" of data
>type "Object", then most probably something went wrong with parsing
>some date format.
>
> 2) Type checking for specific operations. For example, you might want to
>compute an average over all rows for each numerical column in your
>dataset.  That's easiest to do by selecting columns of the right data
>type.
>
> You are completely right that data type information is not sufficient
> for checking for all possible problems, such as unit mismatch. But it
> remains a useful tool.
>
> Cheers,
>   Konrad.


[Pharo-users] Re: Introducing new feature dataTypes for the PolyMath/DataFrame project

2021-08-08 Thread Richard O'Keefe
I am not quite sure what the point of the datatypes feature is.

x := nil.
aSequence do: [:each |
  each ifNotNil: [
x := x ifNil: [each class] ifNotNil: [x commonSuperclassWith: each class]]].

doesn't seem terribly complicated.
My difficulty is that  from a statistics/data science perspective,
it doesn't seem terribly *useful*.

I'm currently reading a book about geostatistics with R (based on a
survey of the Kola
peninsula).  For that task, it is ESSENTIAL to know the units in which
the items are
recorded.  If Calcium is measured in mg/kg and Caesium is measured in µg/kg,
you really really need to know that.  This is not information you can
derive by looking
at the representation of the data in Pharo.  Consider for example
1.  mass of animals in kg
2.  maximum speed of cars in km/h
3.  volume of rain in successive dates, in mL (for fixed area)
4.  directions taken by sand-hoppers released at different times of
day, in degrees
5.  region of space illuminated by light bulbs in steradians.
These might all have the *same* representation in Pharo, but they are
*semantically*
very different.  1 and 2 are linear, but cannot be negative.  3 also
cannot be negative,
but the variable is a *time series*, which 1 and 2 are not.  4 is a
circular measure,
and taking the usual arithmetic mean or median would be an elementary blunder
producing meaningless answers.  5 is perhaps best viewed as a proportion.
(These are all actual examples, by the way.)
THIS kind of information IS valuable for analysis.  The difference
between SmallInteger
and Float64 is nowhere near as interesting.

There's a bunch of weather data that i'm very interested in which has
things like
air temperature, soil temperature, relative humidity, wind speed and
direction (last
5 minutes), gust speed and direction (maximum in last 5 minutes), illumination
in W/m^2 (visible, UVB, UVA), rainfall, and of course date+time.
Temperatures are measured on an interval scale, so dividing them makes no sense.
Nor does adding them.  If it's 10C today and 10C tomorrow, nothing is 20C.  But
oddly enough arithmetic means DO make sense.
Humidity is bounded between 0 and 100; adding two relative humidities makes no
sense at all.  Medians make sense but means do not.
Wind speed and direction are reported as separate variables,
but they are arguably one 2D vector quantity.
Illumination is on a ratio scale.  Dividing one illumination by another makes
sense, or would if there were no moonless nights...
The total illumination over a day makes sense.
Rainfall is also on a ratio scale.  Dividing the rainfall on one day by that
on another would make sense if only the usual measurement were not 0.
Total rainfall over a day makes sense.

The whole problem a statistician/data scientist faces is that there is important
information you need to know even which *basic* operations make sense
that has already disappeared by the time Pharo stores it, and cannot be
inferred from the DataFrame.  I remember one time I was given a CSV file
with about 50 variables and it took me about 2 weeks to recover this missing
meta-information.

On Sat, 7 Aug 2021 at 04:23, Balaji G  wrote:
>
> Hello Everyone,
>
> I have been working on the addition of a new feature, DataFrame >> dataTypes, 
> which briefs us about the data type of columns in dataframes we work on.
> Summarising a dataset is really important during the initial stage of any 
> Data Science and Machine Learning tasks. Knowing the data type of the 
> attribute is one major thing to begin with.
> I have tried to work with some sample datasets for a clear understanding of 
> this new feature.
> Please go through the following blog post. Any kind of suggestion or feedback 
> is welcome.
>
> Link to the Post : 
> https://balaji612141526.wordpress.com/2021/08/06/introducing-new-feature-in-dataframe-project-datatypes/
>
> Previous discussions can be found here : 
> https://lists.pharo.org/empathy/thread/BFOHPRUU72MDYVTJP3YV2DQ5LAZHXELE and 
> here :   
> https://lists.pharo.org/empathy/thread/JZXKXGHSURC3DCDA2NXA7KDWZ2EINAZ5
>
>
>
> Cheers
> Balaji G


[Pharo-users] Re: The Greatest Contributors to Smalltalk since 1980

2021-07-25 Thread Richard O'Keefe
I'd like to call Stephan Ducasse for special mention for providing the
free Smalltalk books site.
And I'd like to mention all the other people who contributed to the
Squeak books and the
continuing Pharo documentation work.  Producing good documentation is
hard work and
when you're not being paid for it, reveals a deep commitment to the
community of users.

Nobody else has mentioned Claus Gittinger of Smalltalk/X, a fine system.
Then there is Dolphin, which is the most beautiful Smalltalk I've ever
come across,
and which is the only reason I bother running Windows on any machine.
There is innovative work in both systems.
perhaps the world's most *beautiful* Smalltalk system, the worst
feature of which is
being Windows-only.

On Sun, 25 Jul 2021 at 21:00, Clacton Server  wrote:
>
> Eric Clayberg - John O’Keefe??
>
> On 25 Jul 2021, at 09:33, Richard Sargent  wrote:
>
> Dave Thomas of OTI probably ranks in your list.
>
> On July 24, 2021 3:44:40 PM PDT, horrido.hobb...@gmail.com wrote:
>>
>> I’m looking for a list of individuals who have contributed greatly to the 
>> advancement of Smalltalk, post Xerox PARC period (1972-1980). By 
>> advancement, I don’t only mean on a technical basis but on an educational or 
>> public awareness basis (this could include books, podcasts, talk circuit, 
>> video instruction, etc.). Any basis that has made Smalltalk a success in the 
>> marketplace (including commercialization).
>>
>> I posted this question on LinkedIn and got one useful response: the late 
>> James Robertson.
>>
>> My personal nomination is Kent Beck.
>>
>> I’m not that familiar with the deep history of Smalltalk, so I’m looking for 
>> more nominations.
>>
>> Thanks.
>
>


[Pharo-users] Re: [ANN] Pharo 9 released!

2021-07-16 Thread Richard O'Keefe
Congratulations.  This must have been a huge amount of work.


On Thu, 15 Jul 2021 at 21:15, Esteban Lorenzano  wrote:

> Dear World and dynamic language lovers:
>
> The time has come for Pharo 9  !
>
> Pharo is a pure object-oriented programming language and a powerful
> environment, focused on simplicity and immediate feedback.
>
>
> Here are the key features of Pharo 9:
>
>
>- Full redesign of the Spec UI framework (new logic, application,
>style, GTK3 back-end)
>- New tools:
>-
>   - new playground,
>   - new object centric inspector,
>   - new object centric debugger.
>   - better and new Refactorings
>   - class comments are now written in Microdown format (Markdown
>   compatible)
>   - classes now can be defined using a "fluid" api (Preview)
>   - New completion framework that adapts better to edition contexts
>and is customizable
>- Fast universal non-blocking FFI which now uses libFFI as backend.
>- Pharo now supports Windows, OSX, Linux (Ubuntu, Debian, Fedora,
>openSUSE, Arch, Raspbian) and multiple architectures (Intel/ARM 32/64bits).
>- Virtual Machine
>-
>   - Idle VM
>   - Support for ARM 64bits
>   - Support for Apple M1
>   - More than 3000 tests
>   - Built for Ubuntu 18.04, 19.04, 20.04, 21.04, 21.10; Debian 9, 10,
>   Testing; Fedora 32, 32, 34; openSUSE 15.1, 15.2, Tumbleweed; Manjaro; 
> Arch
>   - Uses SDL 2.0 as back-end by default. It supports extended event
>handling, including trackpad support.
>- General speed up due to compiler optimisations and UI simplification.
>- And many, many more tests.
>
>
> These are just the more prominent highlights, but the details are just as
> important. We have closed a massive amount of issues: around 1400 issues
> and 2150 pull requests.
>
> A more extended changelog can be found at
> https://github.com/pharo-project/pharo-changelogs/blob/master/Pharo90ChangeLogs.md
> .
>
> While the technical improvements are significant, still the most
> impressive fact is that the new code that got in the main Pharo 9 image was
> contributed by more than 90 people.
>
> Pharo is more than code. It is an exciting project involving a great
> community.
>
> We thank all the contributors to this release:
>
> Aaron Bieber, Ackerley Tng, Alban Benmouffek, Ale Cossio, Alexandre
> Bergel, Alistair Grant, Allex Oliveira, Angela Chia-Ling, Arturo Zambrano,
> Asbathou Biyalou-Sama, Ben Coman, Benoit Verhaegue, Carlo Teixeira, Carlos
> Lopez, Carolina Hernandez, Charles A. Monteiro, Christoph Thiede,
> Christophe Demarey, Clotilde Toullec, Cyril Ferlicot, Damien Pollet, Daniel
> Aparicio, David Bajger, David Sánchez i Gregori, Denis Kudriashov, Ellis
> Harris, Eric Brandwein, Eric Gade, Erik Stel, ErikOnBike, Esteban
> Lorenzano, Esteban Villalobos, Evelyn Cusi Lopez, Evelyn Cusi Lopez, Ewan
> Dawson, Francis Pineda, Francis Pineda, Gabriel Omar Cotelli, Geraldine
> Galindo, Giovanni Corriga, Guille Polito, Himanshu jld, Johan Brichau,
> Jonathan van Alteren, Jordan Montt, Julien Delplanque, Kamil Kukura, Kasper
> Østerbye, Kurt Kilpela, Laurine Dargaud, Marco Rimoldi, Marcus Denker,
> Martin Dias, Martin McClure, Massimo Nocentini, Max Leske, Maximilian
> Ignacio Willembrinck Santander, Milton Mamani Torres, Moussa Saker,
> Myroslava Romaniuk, Nicolas Anquetil, Norbert Hartl, Nour Djihan, Oleksandr
> Zaitsev, Pablo Sánchez Rodríguez, Pablo Tesone, Pavel Krivanek, Philippe
> Lesueur, Pierre Misse, Rakshit P., Rob Sayers, Roland Bernard, Ronie
> Salgado, Sean DeNigris, Sebastian Jordan Montaño, Serge Stinckwich, Stephan
> Eggermont, Steven Costiou, Stéphane Ducasse, Sven Van Caekenberghe, Thomas
> Dupriez, Théo Lanord, Théo Rogliano, Todd Blanchard, Torsten Bergmann,
> Vincent Blondeau, Wéslleymberg Lisboa.
>
>
> (If you contributed with Pharo 9 development in any way and we missed your
> name, please send us an email and we will add you).
>
> Enjoy!
>
> The Pharo Team
>
> Try Pharo: http://pharo.org/download 
>
> Learn Pharo: http://pharo.org/documentation
> 
>


[Pharo-users] Re: Rounding in Floats

2021-06-16 Thread Richard O'Keefe
"first we are not good in math"
  First, I am not criticising YOU.  Pharo's weird ScaledDecimal is
Squeak's weird ScaledDecimal
  and you have not changed it.  Fine.
 "second Pharo is what we have and we never said that it is the best
system ever"
  True, but irrelevant.
"third I never saw a piece of code from you"
  That is not true.  Why, in this thread alone I contributed
#roundOut.  I have provided several
  pieces of code in this mailing list over the years. You can say that
my code is no good, or
  that you don't want it, or that you think there is a better way to
do the (admittedly small)
  things that I have provided, but if you never saw them you must have
shut your eyes.
  In addition, a snapshot of my system is available on the web for
anyone to play with.
  I shall post here when my GitHub repository is populated; I just
have to clear a few more
  things out of the local directory that I don't have the right to distribute.
  (For example, benchmarking my CSV library against NeoCSV meant having to have
  NeoCSV, but it's not mine to distribute.)


On Thu, 17 Jun 2021 at 08:45, ducasse  wrote:
>
> Richard
>
> As I said it thousands of times,
> - first we are not good in math
> - second Pharo is what we have and we never said that it is the best 
> system ever
> we just enhanced daily
> - third, I never saw a piece of code from you.
> - if you want to see Pharo improve (which I doubt about) just send us 
> code and tests
>
> I’m sad that you systematically ignore any of my emails on the topic.
> You could have an impact but you prefer to hide yourselves in your tower. 
> Good luck with it.
>
> S.


[Pharo-users] Re: Rounding in Floats

2021-06-16 Thread Richard O'Keefe
2Decimal floats are (a) part of the IEEE 758-2008 standard for
floating-point arithmetic,
(b) implemented as part of the instruction set in IBM z/Series and
POWER computers,
(c) allowed for in the current C standard, (d) partially supported by GCC
https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Decimal-Float.html
and (e) available for most machines via the "reference implementation" in C.
The current COBOL standard basically defines its arithmetic in terms of this.
Java of course has BigDecimal.  While decimal floats became part of IEEE 754 in
2008, they were previously covered by IEEE 854.

Reverting to ScaledDecimal, let us consider the 10.0s1 / 3 example.
There is a huge problem here with no really satisfactory answer.
In my library, it currently answers 3.3s1, exactly equal to 33/10.
In Squeak/Pharo, it answers "I am really 10/3 but print me with one decimal",
so you see 3.3a1 but it *behaves* like 10.3.
In VisualAge Smalltalk you get  3.33
If it were not for the fact that the ANSI Smalltalk standard appears to
require that  /  yield a ,
I would prefer to answer 10/3.  Decimals just plain are not closed under
division (although they are closed under addition, subtraction, and
multiplication).  When it comes to scaled decimals, the ANSI Smalltalk
standard is frankly a mess.  Amongst other things, it defers the
semantics of operations on them to the Language-Independent
Arithmetic standard, which explicitly denies having anything to say about them!

I understand why my library does what it does.  I even tried to
publish a paper about it.
I understand why VisualAge Smalltalk does what it does.  (I've read
IBM/360 PrincOps.)
I do NOT understand why Squeak and Pharo do what they do, and if anyone knows
the rationale for their ScaledDecmal please tell me.

On Thu, 17 Jun 2021 at 06:29, Esteban Maringolo  wrote:
>
> I didn't know there were decimal floats.
>
> Are they used elsewhere?
>
> Esteban A. Maringolo
>
> On Wed, Jun 16, 2021 at 11:20 AM Konrad Hinsen
>  wrote:
> >
> > On 16/06/2021 15:52, Sven Van Caekenberghe wrote:
> > > I am also a bit intrigued by this. Like you said: several other 
> > > programming languages (I tried a couple of Common Lisp and Scheme 
> > > implementations) do the same as Pharo, but handheld calculators, normal 
> > > and scientific, do not.
> >
> > Handheld calculators use decimal floats, not binary floats. That doesn't
> > remove rounding issues, but it makes conversion to and from print
> > representations loss-free.
> >
> >
> > Konrad


[Pharo-users] Re: Rounding in Floats

2021-06-16 Thread Richard O'Keefe
The problem is that while it is possible to read the ANSI Smalltalk
standard as requiring ScaledDecimals to be fixed point numbers (which are a
kind of exact rational number of the form x * 10**y, x and y integers), in
Squeak and Pharo ScaledDecimal numbers are NOT fixed-point numbers.  They
are unlimited rational numbers with the scale being used for printing
purposes only.  This creates enormous confusion and I really don't see any
point in Squeak/Pharo ScaledDecimal existing at all.  There *is* point in
having fixed-point decimal numbers as they are a perfect match for SQL data
bases and several programming languages.

I've now located a PDF of the USGA Rules of Handicapping.  Wow.  128 pages.
And with all that they couldn't explain the calculations precisely.
Rounding
arrives in more than one place.  For example you might have to average the
best 1-8 of the last (as many as are available up to 20) scores and then
round
to one decimal, but it is not stated how ties are to be broken (which can
arise
for the best 2, 4, 6, or 8).  It is probably safe to assume rounding out.

Number>>roundOut
  ^self negative
 ifTrue:  [((self * 2 - 1) / 2) ceiling]
 ifFalse: [((self * 2 + 1) / 2) floor]

On Wed, 16 Jun 2021 at 02:06, Esteban Maringolo 
wrote:

> Well... fixed point numbers (aka ScaledDecimals) had their issues as well.
>
> And in this particular case, it might cause issues, since the "full
> precision" (whatever that means) must be retained when using such a
> number to derive another one.
>
> E.g. in my case:
> ch := 6.7 + (32.8 - 35). "course handicap"
> allowance := 0.85. "85%"
> ph := (ch * allowance) roundedHandicap. "playing handicap"
>
> The #roundedHandicap is like #rounded but rounds -0.5 towards -1
> instead of toward 0.
>
> My first approach was to use fixed points, but then I hit issues where
> some results also produced "wrong" numbers (according to the
> reference), also in Pharo some ScaledDecimals compare as different
> even when they're printed as the same (which is not correct, IMO).
>
> I just tested using everything as fractions and converting to float
> (or ScaledDecimal) at the very last step and it produces the expected
> result. I'll review and convert whatever is needed (including database
> fields) to work with this. The good thing is that all the involved
> numbers only have one decimal as much.
>
> Thanks!
>
> Esteban A. Maringolo
>
> On Tue, Jun 15, 2021 at 3:48 AM Steffen Märcker  wrote:
> >
> > Have you considered using fixed-point arithmetic? For example:
> > 7.1s2 roundTo: 0.1s2
> >
> > The rule of thumb I stick to is to use FP only if I know the inaccuracies
> > won't bite me. Funny enough, both 7.1 and 0.1 are already not accurately
> > representable as floats. (And by coincidence, I prepared exam questions
> > about floats for my students yesterday. )
> >
> > Kind regards,
> > Steffen
> >
> >
> > Konrad Hinsen schrieb am Dienstag, 15. Juni 2021 07:02:30 (+02:00):
> >
> >  > On 15/06/2021 01:03, Esteban Maringolo wrote:
> >  > > Sure, but what initiated this thread was a reference to roundTo: 0.1
> >  > > which produced a "wrong" output.
> >  > >
> >  > > (9.1 + (-2.0)) roundTo: 0.1 "=> 7.1005"
> >  > > 7.1 roundTo: 0.1 "=> 7.1005"
> >  > >
> >  > > However, at this point I know that Pharo "does the right, raw,
> thing"
> >  > > (at least compared to other mainstream languages), but it still
> >  > > produces a surprise effect.
> >  >
> >  > That's the "floating point surprise" that everyone has at some point,
> no
> > matter the language and runtime system. If that surprise is a problem for
> > you, are you sure that floating-point arithmetic is what you really want?
> > Maybe your needs are better served with integers and fractions.
> >  >
> >  >
> >  > Konrad.
> >  >
> >  >
> > --
> > Gesendet mit Vivaldi Mail. Laden Sie Vivaldi kostenlos von vivaldi.com
> > herunter.
>


[Pharo-users] Re: Rounding in Floats

2021-06-15 Thread Richard O'Keefe
Whether 6.7 - 2.2 gives 4.5 or something else is a subtle issue,
starting with the fact
that 6.7 and 2.2 cannot be represented precisely in floating-point
format.  In this particular case, the errors happen to match up.
What you *can* rely on in Smalltalk is that (67/10) - (22/10) = (9/2).

Let's just consider h * s / 113 + (r - p).
If h, s, r, and p are all exact numbers (Integers or Fractions) the
result will be an exact number.
So what kinds of number are h, s, r, and p, and *why* are they
like that?  If you are reading them from a file, consider that
Fraction readFrom: '6.7' readStream >>> (67/10)

Is there a specification you could show us?  Some test data?


On Tue, 15 Jun 2021 at 14:24, Esteban Maringolo  wrote:
>
> On Mon, Jun 14, 2021 at 10:37 PM Richard O'Keefe  wrote:
>
> > For what it's worth, I expected ScaledDecimal to act like fixed point
> > arithmetic, and implemented it that way in my own Smalltalk library, where
> > two ScaledDecimals *do* print the same if and only if they are numerically
> > exactly the same.
> > What Squeak and Pharo do is exceedingly odd: a ScaledDecimal
> > is an exact rational number (Integer or Fraction) combined with a precision 
> > that
> > is used for printing, not for calculation.
>
> I pointed out before the weird behavior of ScaledDecimals in Pharo,
> two ScaledDecimal that print the same are not equal. Giving some weird
> comparison issues as result.
>
> > There really isn't any principle of least surprise when it comes to 
> > floating-
> > point arithmetic.  It's full of surprises and edge cases.  Excel in 
> > particular
> > is notorious for messing up due to trying to pretend all is well.
> > In this particular case, the exact result is 4.5
>
> Well... for the end user, it produces what they'd expect. So it might
> mess up, but in a spreadsheet 6.7 - 2.2 should give 4.5.
>
> > There are at least three rules for rounding such numbers: rounding out (5),
> > rounding in (4), and rounding in [banker'salgorithm] (4 here, but 5.5 -> 6).
> > So you are pushing up against an edge case for exact hand calculation!
>
> I implemented a Float>>#roundedHandicap method that does something
> like the banking algorithm, but rounds positive numbers towards the
> next integer and negative numbers towards zero.
> E.g.
> 0.49 -> 0
> 0.5 -> 1
> -0.5 -> 0
> -0.51 -> -1
>
> Nothing uses more than one decimal, so a ScaledDecimal would work but
> the specification says that it should use all possible precision in
> intermediate calculations, so I cannot use it.
>
> > I think you need to re-express your entire calculation to use exact 
> > arithmetic.
>
> I really don't know how to do this, any pointers?
>
> Nothing is more straightforward than addition and subtraction to me,
> 6.7 - 2.2 is the simplest it can get.
>
> The common formula here is: h * s / 113 + (r - p), but in this
> particular case s was 113 so it removed the "troubling" part.
>
> > That or get agreement on "de minimis non curat lex".
>
> I had to search for that expression. Now I know, I agree.
>
> Regards,
>
> Esteban A. Maringolo
>
>
>
> >
> >
> > On Tue, 15 Jun 2021 at 08:45, Esteban Maringolo  
> > wrote:
> > >
> > > I'm coming back to this because I've been bitten by these floating
> > > points things again.
> > >
> > > If in Pharo [1] you do:
> > > a := 6.7 + (32.8 - 35)
> > >
> > > It will produce:
> > > 4.497
> > >
> > > Which, when rounded, will produce 4.
> > >
> > > In other places [2] I do the same simple addition and subtraction it
> > > produces 4.5, that when rounded will produce 5.
> > >
> > > I know now that Pharo doesn't lie to me while other systems do, and
> > > all that Richard pointed to before.
> > >
> > > The issue here is that I'm following some calculation formula that was
> > > defined in some of the "other" systems, and so when I follow such a
> > > formula I get these edgy cases where my system produces a different
> > > output.
> > >
> > > In this case the formula is for golf handicap calculations, and it
> > > caused my system to give 4 instead of 5 to a player, resulting in
> > > giving the first place to a player other than the one deserved.
> > > It was no big deal (it's not The Masters), but these cases appear from
> > > time to time.
> > >
> > > Is there any way to "configure" the floating point calculation to
> > > behave as the "other syst

[Pharo-users] Re: Rounding in Floats

2021-06-14 Thread Richard O'Keefe
It's not quite clear what is happening in the other systems.
Here is R
> 6.7 + (32.8 - 35)
[1] 4.5
> round(6.7 + (32.8 - 35))
[1] 4
The result *is* 4.49 but is *printed* as 4.5.

Here is Gambit Scheme
> (+ 6.7 (- 32.8 35))
4.497
 > (round (+ 6.7 (- 32.8 35)))
 4.

Here is astc Smalltalk
6.7 + (32.8 - 35) printOn: Transcript
Transcript tab.
(6.7 + (32.8 - 35)) rounded printOn: Transcript.
Transcript cr.
4.497   4

And here is Python
>>> x = 6.7 + (32.8 - 35)
>>> x
4.497
>>> round(x)
4

For what it's worth, I expected ScaledDecimal to act like fixed point
arithmetic, and implemented it that way in my own Smalltalk library, where
two ScaledDecimals *do* print the same if and only if they are numerically
exactly the same.  What Squeak and Pharo do is exceedingly odd: a ScaledDecimal
is an exact rational number (Integer or Fraction) combined with a precision that
is used for printing, not for calculation.

There really isn't any principle of least surprise when it comes to floating-
point arithmetic.  It's full of surprises and edge cases.  Excel in particular
is notorious for messing up due to trying to pretend all is well.

In this particular case, the exact result is 4.5
There are at least three rules for rounding such numbers: rounding out (5),
rounding in (4), and rounding in [banker'salgorithm] (4 here, but 5.5 -> 6).
So you are pushing up against an edge case for exact hand calculation!

I think you need to re-express your entire calculation to use exact arithmetic.
That or get agreement on "de minimis non curat lex".


On Tue, 15 Jun 2021 at 08:45, Esteban Maringolo  wrote:
>
> I'm coming back to this because I've been bitten by these floating
> points things again.
>
> If in Pharo [1] you do:
> a := 6.7 + (32.8 - 35)
>
> It will produce:
> 4.497
>
> Which, when rounded, will produce 4.
>
> In other places [2] I do the same simple addition and subtraction it
> produces 4.5, that when rounded will produce 5.
>
> I know now that Pharo doesn't lie to me while other systems do, and
> all that Richard pointed to before.
>
> The issue here is that I'm following some calculation formula that was
> defined in some of the "other" systems, and so when I follow such a
> formula I get these edgy cases where my system produces a different
> output.
>
> In this case the formula is for golf handicap calculations, and it
> caused my system to give 4 instead of 5 to a player, resulting in
> giving the first place to a player other than the one deserved.
> It was no big deal (it's not The Masters), but these cases appear from
> time to time.
>
> Is there any way to "configure" the floating point calculation to
> behave as the "other systems"?
>
> What is the best way to anticipate these situations, am I the only one
> being bitten by these issues?
>
> Thanks in advance for any hints about these problems.
>
>
> Best regards,
>
> [1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as 
> Pharo.
> [2] VisualWorks, VAST, Excel, VB and all calculators I tried
>
>
>
> Esteban A. Maringolo
>
> On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo  
> wrote:
> >
> > On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe  wrote:
> > >
> > > "7.1 roundTo: 0.1 should return 7.1"
> > > You're still not getting it.
> >
> > I was until Konrad explained it.
> >
> > > Binary floating point CANNOT represent either of those numbers.
> > > You seem to be assuming that Pharo is making some mistake.
> > > It isn't.  All it is doing is refusing to lie to you.
> > 
> > > The systems that print 7.1 are LYING to you,
> > > and Pharo is not.
> >
> > I'm not assuming a mistake from Pharo, I had a wrong expectation what
> > to get if I round to that precision.
> > I don't know whether other systems lie or simply fulfill user
> > expectations, if you send the #roundTo: to a float, I did expect to
> > get a number with the same precision.
> > That is my expectation as a user. As in the other thread I expected
> > two scaled decimals that are printed equal to also be compared as
> > equal  (which they don't).
> >
> > Whether there is a good reason for those behaviors is beyond my
> > current comprehension, but it certainly doesn't follow the "principle
> > of least surprise".
> >
> > In any case, the method proposed by Tomohiro solved my issues.
> >
> > Regards,
> >
> > Esteban A. Maringolo


[Pharo-users] Re: creating a subclass in system browser

2021-04-29 Thread Richard O'Keefe
I hadn't actually noticed the "+" sign but it was there in V7 and is there
in V9 on Windows.

On Wed, 28 Apr 2021 at 03:15, Sanjay Minni  wrote:

> Don't think it's there in v9. Check in v8
>
> On Tue, 27 Apr, 2021, 7:50 pm Russ Whaley,  wrote:
>
>> Can you send a screenshot of the plus button?  I'm using v9 on MacOS and
>> I don't see a class + button...
>>
>> On Tue, Apr 27, 2021 at 9:47 AM kmo  wrote:
>>
>>> Doing it by hand is fiddly and error-prone. I know - because that's the
>>> way I
>>> used to do it before I realised that the plus button at the top of the
>>> browser bottom panel did it for me. (I had no idea that there was also a
>>> menu option on the refactorings menu). I think you might find the button
>>> to
>>> be the better way - I did.
>>>
>>>
>>>
>>>
>>> --
>>> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>>>
>>
>>
>> --
>> Russ Whaley
>> whaley.r...@gmail.com
>>
>


[Pharo-users] Re: Help Needed: Looking for projects to use in a study of transforming deprecations

2021-04-06 Thread Richard O'Keefe
This sounds like a very nice tool.
Just a word about this particular example:

Collection >> includesAllOf: values
  self
deprecated: ‘Use #includesAll: instead’
transformWith: ‘`@rec includesAllOf: `@arg’ ->
   ‘`@rec includesAll: `@arg’.

  ^ self includesAll: values

Surely this is back to front?  #includesAllOf: reads well and is
compatible with GNU Smalltalk (and classic Squeak), while #includesAll:
doesn't work in most of the Smalltalks I have access to.

My own library has
  {includes,excludes}{All,Any,None,One}Of:
which wouldn't read nearly so well without "Of".

On Wed, 7 Apr 2021 at 00:50, Oleksandr Zaitsev 
wrote:

> Hello,
>
> I need your help to recommend some projects that I can use in my study of
> transforming deprecations.
>
> As many of you know, Pharo supports a very powerful concept of
> "transforming" deprecations. You can deprecate a method, providing a
> transformation rule. Then when a client application calls the deprecated
> method, the call-site will be automatically rewritten to use the new API.
> Here is an example of a transforming deprecation:
>
> Collection >> includesAllOf: values
>   self
> deprecated: ‘Use #includesAll: instead’
> transformWith: ‘`@rec includesAllOf: `@arg’ ->
>‘`@rec includesAll: `@arg’.
>
>   ^ self includesAll: values
>
>
> You can read more about transforming deprecations in my blog post:
> https://blog.oleks.fr/deprewriter
>
> I am working on a tool that can analyse the commit history of a project
> and recommend deprecations and transformation rules that can be inserted
> before the release. It works like this:
>
> 1. Collect all commits between two releases of a project
> 2. Mine those commits to identify method call replacements (deletions and
> additions) that happen frequently
> 3. Infer the mapping between the methods of the old and new API
> 4. Recommend deprecations and generate transformation rules
>
> I have validated my approach on Pharo, Moose, Pillar, Famix, and DataFrame
> projects.
>
> Now I am looking for other projects that could benefit from recommended
> deprecations and could be used in my study.
>
> *Required:*
> - open source project with accessible commit history (e.g. public git
> repository)
> - written in Pharo (although if you know projects in other languages that
> could be interesting for my study, please let me know about them as well)
>
> *Prefered:*
> - ongoing development
> - multiple releases
> - has users (other projects that depend on it)
>
> If you have some projects in mind, please let me know about them!
>
> And if you are interested in this study and want to learn more, don't
> hesitate to contact me by email.
>
> Oleksandr
>
>
>


[Pharo-users] Re: change process variable while process is running

2021-03-29 Thread Richard O'Keefe
Code fragments are by definition incomplete.
SharedQueue with a "d".


On Sun, 28 Mar 2021 at 03:38,  wrote:

> thanks! I am now sure I am using the highest priority.
>
> one last question about this, maybe very newbie nut I would like to
> understand things.
>
> so, in your code example for the Process using the ShareQueue and in my
> running demo, the ShareQueues are not put between pipes ( | | ) before
> declaration. I thought it was mandatory to have the pipes to declare
> variables. what is the meaning of having them declare without pipes?
>


[Pharo-users] Re: change process variable while process is running

2021-03-26 Thread Richard O'Keefe
Open a Playground in Pharo.
Enter the following text.

(((ProcessorScheduler selectors)
  select:  [:each | each endsWith: 'Priority'])
  collect: [:each | {Processor perform: each. each}])
  sorted:  [:x :y | x first <= y first]

Select it, the ctrl-i or "Inspect It" from a menu).
That gives you a list of the named priorities.

>From that you will be able to answer your own question.

On Fri, 26 Mar 2021 at 06:39,  wrote:

> this is what I was able to put together thanks to your advice Richard.
>
> https://www.youtube.com/watch?v=NFaR3ZQfOUU=youtu.be
>
> I am further developing this research on Pharo as a tool for live coding.
> I am sending many OSC messages and they sounds pretty on time if the
> Process is forked at Processor timingPriority.
>
> is that the maximum priority?
>


[Pharo-users] Re: [ANN] Develop in Pharo 9, run on Javascript

2021-03-13 Thread Richard O'Keefe
Well done!

On Sat, 13 Mar 2021 at 04:17, Noury Bouraqadi  wrote:

> Hi everyone,
>
> We have been working on porting PharoJS to Pharo 9 for a while now.
> And we managed to reach the end of the tunnel this week.
> All PharoJS tests are now green on Pharo 9.
>
> Find out more at: https://github.com/PharoJS/PharoJS
> Dave & Noury
>


[Pharo-users] Re: change process variable while process is running

2021-03-02 Thread Richard O'Keefe
Why do the parameters for the sequencer have to be
*process* variables?  Why can't they be instance
variables of an object?

SequenceControl (mutex v1 v2 ...)
  initialize
mutex := Mutex new.
v1 := default for v1.
v2 := default for v2.
...
  v1
^v1
  v1: x
   validate x all by itself
   mutex critical: [
 validate x in context of other variables
 v1 := x].

This takes care of all the memory fiddling necessary.
Once again, the existence of this object would be a shared
secret between the process and the creating process.


On Wed, 3 Mar 2021 at 00:48,  wrote:

> thanks Sven and thanks Richard.
>
> I already thought it was not a good idea to change a variable inside the
> process as for OOP principles.
>
> but I dint find any solution to do what I want to do, that is a tool for
> live coding in which the process variables are values for a sequencer
> sendin OSC messages to another application. I need the process for the
> timing.
>
> what I had in mind came from the fact that in c++ frameworks to build
> audio application you can modify variable values inside a thread.
>
> after your answers I think I will have to look for another approach.
>


[Pharo-users] Re: change process variable while process is running

2021-03-02 Thread Richard O'Keefe
How do you modify a variable in another process?
DON'T.
Yes, it is possible.
No, it's an amazingly bad idea in any programming language.

First, let us see a simple, obvious, and portable way to do
what you want.  (It has one minor problem which I'll get to.)

shared := Array new: 1.
shared at: 1 put: initialValue.
[ 1 to: 100 do: [:i |
Transcript show: (shared at: 1); cr
] fork.

The 'shared' object is a secret shared between the new Process and the
(method in the) Process that created it.  Nothing else can see it, let
alone change it.  This is a good thing.

The minor problem I mentioned?
It might not work.  If the two Processes are running on different
cores, and if the compiler is (too) smart (enough), memory writes
from one Process might not be noticed by memory reads at the other.

You should think about processes the way you think about objects.
"How do I change a variable in another object?  DON'T!"
"How do I change a variable in another process? DON'T!"
What variables another object has or another process has are
PRIVATE IMPLEMENTATION DETAILS.
The Object-Oriented rule is

  ASK, DON'T TELL.

That is, you should never *force* an object or process to do
anything, you should ASK it to do something by sending a
message.

The way you send a message to a Process is via a SharedQueue.

shared := SharedQueue new.
[ |text next|
  text := 'Kalimera Kosmou'.
  1 to: 100 do: [:i |
next := shared nextOrNil.
next ifNotNil: [text := next].
Transcript show: text; cr]
] fork.
shared nextPut: 'Pozdrav svijete'.
shared nextPut: 'Hello world'.

With this approach, the receiving process has complete
and absolute control over when the variable ('text') is
changed and indeed whether it is changed.

There are several other tools you can use, but my experience
has been that getting things right using Processes and
SharedQueues FIRST before trying other kinds of things
(like rolling your own Mailbox or Rendezvous classes) makes
concurrent programming so much easier.

It also drives home that the originating process does not
know when or whether the receiving process has acted on
the message, but that's the case with shared variables too,
modern hardware and operating systems being what they are.
It's just more OBVIOUS this way and more CONTROLLED.


On Tue, 2 Mar 2021 at 22:42,  wrote:

> Hello everybody, I am kind of new to Pharo so I apologise if my
> question is silly :)
> how can a change a variable in a process while the process is running?
> for example in:
> [[ | msg| msg := 'help me'. 100 timesRepeat: [(Delay forSeconds: 0.5)
> wait. Transcript show: msg; cr]] fork.
>
> how do I change the value of msg while the process is running in order
> to modify what the Transcript is showing?
> is that possible?
> thanks.
> Domenico
>


[Pharo-users] Re: Strings in Playground are read only in Pharo 9

2021-03-01 Thread Richard O'Keefe
For what it's worth, the ANSI Smalltalk standard says
"The protocols specified for literals do not include any messages
 that modify the state of the literal objects.
 The effect of sending a message to an object that is the value
 of a literal that modifies the state of the literal is undefined."
This also includes trying to modify an array literal, and fiddling
with the bits of a large integer.

That is, according to the ANSI standard, 'abc' is a string but not
necessarily a String.  I hope that is clear (:-).


On Sun, 28 Feb 2021 at 22:57, Sven Van Caekenberghe  wrote:

> Markus,
>
> 'hello' is a literal string constant, part of the set of constants of a
> method (or a doit which like a temporary method disconnected from a class).
>
> Constants like these are managed by the compiler and can be shared between
> different expressions to avoid duplication.
>
> Changing such a constant is dangerous because it means you are changing
> static/compiled code. Consider a method like
>
> name
>  ^ 'Markus'
>
> I could call this method and change the returned string destructively in
> place. Next time someone calls it, s/he would get the modified string. Even
> worse, s/he would not understand since the source code did not change.
>
> In the past it was not possible to mark such strings as being constant,
> now we can. Which is a big win.
>
> You can use #copy to get a string that you can modify.
>
> 'hello' copy at: 2 put: $a; yourself
>
> HTH,
>
> Sven
>
> > On 28 Feb 2021, at 00:50, Markus Wedel  wrote:
> >
> > Hi all,
> >
> > strings in Playground are read only in Pharo 9.0 Build 1153 so that
> >
> > 'hello' at: 2 put: $a; yourself
> > ctrl+p
> >
> > This throws an error:
> > „Modification forbidden: ‚hello‘ is read-only, hence its field cannot be
> modified with $a
> >
> > which is actually a very nice error message but is this supposed to
> happen?
> > The example does work in Pharo 8 without problems.
> >
> >
> > Greetings
> > Markus
>


[Pharo-users] Re: NeoCSVReader and wrong number of fieldAccessors

2021-01-07 Thread Richard O'Keefe
Thank you very much.
I converted your benchmark to my Smalltalk dialect and was
pleased with the results.  This gave me the impetus I needed
to implement the #recordClass: feature of NeoCSVReader,
although in my case it requires the class to implement #withAll:
and the operand is a (reused) OrderedCollection.

There's one difference between CSVEncoder and NeoCSVWriter that
might be of interest: you can't tell CSVEncoder whether a field
is #raw or #quoted because it always figures that out for itself.
I was prepared to pay an efficiency penalty to make sure I did not
get this wrong, and am pleased to find it wasn't as much of a
penalty as I feared.



On Wed, 6 Jan 2021 at 22:52, Sven Van Caekenberghe  wrote:

> Hi Richard,
>
> Benchmarking is a can of worms, many factors have to be considered. But
> the first requirement is obviously to be completely open over what you are
> doing and what you are comparing.
>
> NeoCSV contains a simple benchmark suite called NeoCSVBenchmark, which was
> used during development. Note that it is a bit tricky to use: you need to
> run a write benchmark with a specific configuration before you can try read
> benchmarks.
>
> The core data is a 100.000 line file (2.5 MB) like this:
>
> 1,-1,9
> 2,-2,8
> 3,-3,7
> 4,-4,6
> 5,-5,5
> 6,-6,4
> 7,-7,3
> 8,-8,2
> 9,-9,1
> 10,-10,0
> ...
>
> That parses in ~250ms on my machine.
>
> NeoCSV has quite a bit of features and handles various edge cases.
> Obviously, a minimal, custom implementation could be faster.
>
> NeoCSV is called efficient not just because it is reasonably fast, but
> because it can be configured to generate domain objects without
> intermediate structures and because it can convert individual fields (parse
> numbers, dates, times, ...) while parsing.
>
> Like you said, some generated CSV output out in the wild is very
> irregular. I try to stick with standard CSV as much as possible.
>
> Sven
>
> > On 6 Jan 2021, at 05:10, Richard O'Keefe  wrote:
> >
> > NeoCSVReader is described as efficient.  What is that
> > in comparison to?  What benchmark data are used?
> > Here are benchmark results measured today.
> > (5,000 data line file, 9,145,009 characters).
> >  methodtime(ms)
> >  Just read characters   410
> >  CSVDecoder>>next  3415   astc's CSV reader (defaults). 1.26 x
> CSVParser
> >  NeoCSVReader>>next4798   NeoCSVReader (default state). 1.78 x
> CSVParser
> >  CSVParser>>next   2701   pared-to-the-bone CSV reader. 1.00
> reference.
> >
> > (10,000 data line file, 1,544,836 characters).
> >  methodtime(ms)
> >  Just read characters93
> >  CSVDecoder>>next   530   astc's CSV reader (defaults). 1.26 x
> CSVParser
> >  NeoCSVReader>>next 737   NeoCSVReader (default state). 1.75 x
> CSVParser
> >  CSVParser>>next421   pared-to-the-bone CSV reader. 1.00
> reference.
> >
> > CSVParser is just 78 lines and is not customisable.  It really is
> > stripped to pretty much an absolute minimum.  All of the parsers
> > were configured (if that made sense) to return an Array of Strings.
> > Many of the CSV files I've worked with use short records instead
> > of ending a line with a lot of commas.  Some of them also have the
> occasional stray comment off to the right, not mentioned in the header.
> > I've also found it necessary to skip multiple lines at the beginning
> > and/or end.  (Really, some government agencies seem to have NO idea
> > that anyone might want to do more with a CSV file than eyeball it in
> > Excel.)
> >
> > If there is a benchmark suite I can use to improve CSVDecoder,
> > I would like to try it out.
> >
> > On Tue, 5 Jan 2021 at 02:36, jtuc...@objektfabrik.de <
> jtuc...@objektfabrik.de> wrote:
> > Happy new year to all of you! May 2021 be an increasingly less crazy
> > year than 2020...
> >
> >
> > I have a question that sounds a bit strange, but we have two effects
> > with NeoCSVReader related to wrong definitions of the reader.
> >
> > One effect is that reading a Stream #upToEnd leads to an endless loop,
> > the other is that the Reader produces twice as many objects as there are
> > lines in the file that is being read.
> >
> > In both scenarios, the reason is that the CSV Reader has a wrong number
> > of column definitions.
> >
> > Of course that is my fault: why do I feed a "malformed" CSV file to poor
> > NeoCSVReader?
> >
> > Let me explain: we have a few import interfaces which end users can
>

[Pharo-users] Re: NeoCSVReader and wrong number of fieldAccessors

2021-01-06 Thread Richard O'Keefe
You aren't sure what point I was making?
How about the one I actually wrote down:
  What test data was NeoCSV benchmarked with
  and can I get my hands on it?
THAT is the point.  The data points I showed (and
many others I have not) are not satisfactory to me.
I have been searching for CSV test collections.
One site offered 6 files of which only one downloaded.
I found a "benchmark suite" for CSV containing no
actual CSV files.
So where *else* should I look for benchmark data than
associated with a parser people in this community are
generally happy with that is described as "efficient"?

Is it so unreasonable to suspect that my results might
be a fluke?  Is it bad manners to assume that something
described as efficient has tests showing that?



On Wed, 6 Jan 2021 at 22:23, jtuc...@objektfabrik.de <
jtuc...@objektfabrik.de> wrote:

> Richard,
>
> I am not sure what point you are trying to make here.
> You have something cooler and faster? Great, how about sharing?
> You could make a faster one when it doesn't convert numbers and stuff?
> Great. I guess the time will be spent after parsing in 95% of the use
> cases. It depends. And that is exactly what you are saying. The word
> efficient means nothing without context. How is that related to this thread?
>
> I think this thread mostly shows the strength of a community, especially
> when there are members who are active, friendly and highly motivated. My
> problem git solved in blazing speed without me paying anything for it. Just
> because Sven thought my problem could be other people's problem as well.
>
> I am happy with NeoCSV's speed, even if there may be more lightweigt and
> faster solutions. Tbh, my main concern with NeoCSV is not speed, but how
> well I can understand problems and fix them. I care about data types on
> parsing. A non-configurable csv parser gives me a bunch of dictionaries and
> Strings. That could be a waste of cycles and memory once you need the data
> as objects.
> My use case is not importing trillions of records all day, and for a few
> hundred or maybe sometimes thousands, it is good/fast enough.
>
>
> Joachim
>
>
>
>
>
> Am 06.01.21 um 05:10 schrieb Richard O'Keefe:
>
> NeoCSVReader is described as efficient.  What is that
> in comparison to?  What benchmark data are used?
> Here are benchmark results measured today.
> (5,000 data line file, 9,145,009 characters).
>  methodtime(ms)
>  Just read characters   410
>  CSVDecoder>>next  3415   astc's CSV reader (defaults). 1.26 x
> CSVParser
>  NeoCSVReader>>next4798   NeoCSVReader (default state). 1.78 x
> CSVParser
>  CSVParser>>next   2701   pared-to-the-bone CSV reader. 1.00 reference.
>
> (10,000 data line file, 1,544,836 characters).
>  methodtime(ms)
>  Just read characters93
>  CSVDecoder>>next   530   astc's CSV reader (defaults). 1.26 x
> CSVParser
>  NeoCSVReader>>next 737   NeoCSVReader (default state). 1.75 x
> CSVParser
>  CSVParser>>next421   pared-to-the-bone CSV reader. 1.00 reference.
>
> CSVParser is just 78 lines and is not customisable.  It really is
> stripped to pretty much an absolute minimum.  All of the parsers
> were configured (if that made sense) to return an Array of Strings.
> Many of the CSV files I've worked with use short records instead
> of ending a line with a lot of commas.  Some of them also have the
> occasional stray comment off to the right, not mentioned in the header.
> I've also found it necessary to skip multiple lines at the beginning
> and/or end.  (Really, some government agencies seem to have NO idea
> that anyone might want to do more with a CSV file than eyeball it in
> Excel.)
>
> If there is a benchmark suite I can use to improve CSVDecoder,
> I would like to try it out.
>
> On Tue, 5 Jan 2021 at 02:36, jtuc...@objektfabrik.de <
> jtuc...@objektfabrik.de> wrote:
>
>> Happy new year to all of you! May 2021 be an increasingly less crazy
>> year than 2020...
>>
>>
>> I have a question that sounds a bit strange, but we have two effects
>> with NeoCSVReader related to wrong definitions of the reader.
>>
>> One effect is that reading a Stream #upToEnd leads to an endless loop,
>> the other is that the Reader produces twice as many objects as there are
>> lines in the file that is being read.
>>
>> In both scenarios, the reason is that the CSV Reader has a wrong number
>> of column definitions.
>>
>> Of course that is my fault: why do I feed a "malformed" CSV file to poor
>> NeoCSVReader?
>>
>> Let me explain: we have a few import interfaces which end users can
>&g

[Pharo-users] Re: NeoCSVReader and wrong number of fieldAccessors

2021-01-05 Thread Richard O'Keefe
NeoCSVReader is described as efficient.  What is that
in comparison to?  What benchmark data are used?
Here are benchmark results measured today.
(5,000 data line file, 9,145,009 characters).
 methodtime(ms)
 Just read characters   410
 CSVDecoder>>next  3415   astc's CSV reader (defaults). 1.26 x CSVParser
 NeoCSVReader>>next4798   NeoCSVReader (default state). 1.78 x CSVParser
 CSVParser>>next   2701   pared-to-the-bone CSV reader. 1.00 reference.

(10,000 data line file, 1,544,836 characters).
 methodtime(ms)
 Just read characters93
 CSVDecoder>>next   530   astc's CSV reader (defaults). 1.26 x
CSVParser
 NeoCSVReader>>next 737   NeoCSVReader (default state). 1.75 x
CSVParser
 CSVParser>>next421   pared-to-the-bone CSV reader. 1.00 reference.

CSVParser is just 78 lines and is not customisable.  It really is
stripped to pretty much an absolute minimum.  All of the parsers
were configured (if that made sense) to return an Array of Strings.
Many of the CSV files I've worked with use short records instead
of ending a line with a lot of commas.  Some of them also have the
occasional stray comment off to the right, not mentioned in the header.
I've also found it necessary to skip multiple lines at the beginning
and/or end.  (Really, some government agencies seem to have NO idea
that anyone might want to do more with a CSV file than eyeball it in
Excel.)

If there is a benchmark suite I can use to improve CSVDecoder,
I would like to try it out.

On Tue, 5 Jan 2021 at 02:36, jtuc...@objektfabrik.de <
jtuc...@objektfabrik.de> wrote:

> Happy new year to all of you! May 2021 be an increasingly less crazy
> year than 2020...
>
>
> I have a question that sounds a bit strange, but we have two effects
> with NeoCSVReader related to wrong definitions of the reader.
>
> One effect is that reading a Stream #upToEnd leads to an endless loop,
> the other is that the Reader produces twice as many objects as there are
> lines in the file that is being read.
>
> In both scenarios, the reason is that the CSV Reader has a wrong number
> of column definitions.
>
> Of course that is my fault: why do I feed a "malformed" CSV file to poor
> NeoCSVReader?
>
> Let me explain: we have a few import interfaces which end users can
> define using a more or less nice assistant in our Application. The CSV
> files they upload to our App come from third parties like payment
> providers, banks and other sources. These change their file structures
> whenever they feel like it and never tell anybody. So a CSV import that
> may have been working for years may one day tear a whole web server
> image down because of a wrong number of fieldAccessors. This is bad on
> many levels.
>
> You can easily try the doubling effect at home: define a working CSV
> Reader and comment out one of the addField: commands before you use the
> NeoCSVReader to parse a CSV file. Say your CSV file has 3 lines with 4
> columns each. If you remove one of the fieldAccessors, an #upToEnd will
> yoield an Array of 6 objects rather than 3.
>
> I haven't found the reason for the cases where this leads to an endless
> loop, but at least this one is clear...
>
> I *guess* this is due to the way #readEndOfLine is implemented. It seems
> to not peek forward to the end of the line. I have the gut feeling
> #peekChar should peek instead of reading the #next character form the
> input Stream, but #peekChar has too many senders to just go ahead and
> mess with it ;-)
>
> So I wonder if there are any tried approaches to this problem.
>
> One thing I might do is not use #upToEnd, but read each line using
> PositionableStream>>#nextLine and first check each line if the number of
> separators matches the number of fieldAccessors minus 1 (and go through
> the hoops of handling separators in quoted fields and such...). Only if
> that test succeeds, I would then hand a Stream with the whole line to
> the reader and do a #next.
>
> This will, however, mean a lot of extra cycles for large files. Of
> course I could do this only for some lines, maybe just the first one.
> Whatever.
>
>
> But somehow I have the feeling I should get an exception telling me the
> line is not compatible to the Reader's definition or such. Or
> #readAtEndOrEndOfLine should just walk the line to the end and ignore
> the rest of the line, returnong an incomplete object
>
>
> Maybe I am just missing the right setting or switch? What best practices
> did you guys come up with for such problems?
>
>
> Thanks in advance,
>
>
> Joachim
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


[Pharo-users] Re: is there a better way

2021-01-02 Thread Richard O'Keefe
What do you want the code to do?
Have you profiled the code to see where the time is going?

A quick look at the code shows
 - Paintings does one web get
 - each Painting does two more web gets
   ! and the first of those seems to be pretty pointless,
 as it refetches an object that Paintings already fetched
 and just looked at.



On Sun, 3 Jan 2021 at 01:16, Roelof Wobben via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Hello,
>
> I have now this code : https://github.com/RoelofWobben/Rijksmuseam
>
> but it seems to be slow.
>
> Can anyone help me with a way I can use a sort of cache so the page
> looks first at the cache if a image is there .
> If so, take the image from there , if not , ask the api for the url of
> the image.
>
> Roelof
>


[Pharo-users] Re: Can a class be not equal to itself?

2021-01-01 Thread Richard O'Keefe
Well, when you talk about "THE copying machinery" you have to be a bit more
specific.  There is no such thing as #deepCopy or #shallowCopy in the ANSI
Smalltalk standard.  Many Smalltalks have
Object>>copy
  ^self shallowCopy postCopy
and encourage you to override #postCopy.
But nothing stops you doing
MyClass
  methods for: 'copying'
copy
  ^self
deepcopy
  ^self
postCopy
  ^self
shallowCopy
  ^self
You will note that in Pharo, AtomicCollection, Behavior, Boolean,
Character, Float, SmallFloat64, Form, ColorForm, Morph, Paragraph,
Point, SmallInteger, String, UndefinedObject, and perhaps others
override #deepCopy.  Also, Boolean, Character, Float, SmallFloat64,
SmallInteger, Symbol, UndefinedObject, and perhaps others
override #shallowCopy.

So it *is* possible to have singletons in Smalltalk.
Classes can be copied in Pharo because someone thought it
would be a good idea.

On to the next point.
'I have an object whose internal state is updated
by incoming messages. I need to take immutable snapshots of that
object's state at some points. And that I do by sending "deepCopy"
and then "beRecursivelyReadOnlyObject".'

You do not know which objects will be copied by #deepCopy and
which won't, or if you do, you cannot be sure that that will not
change in a future release, or indeed if you load a package.
You do not know whether some of these objects will break if made
read-only.

#deepCopy is *serious* "Hic sunt dracones" territory.
It's marked on the Hunt-Lenox Globe, just beside the
Vesuvian introitus ad infernum.

Seriously, the OOP way to do this is
MyClass>>immutableSnapshot
  "Answer an immutable copy of myself."
  ...
and then whatever it takes to make precisely that happen.


On Fri, 1 Jan 2021 at 23:35, Konrad Hinsen 
wrote:

> "Richard O'Keefe"  writes:
>
> > #deepCopy is one of those things that is best avoided,
> > because it violates the key principle of OOP that an
>
> In the abstract, I agree. In practice, I don't see what else I could do
> for my use case. I have an object whose internal state is updated
> by incoming messages. I need to take immutable snapshots of that
> object's state at some points. And that I do by sending "deepCopy"
> and then "beRecursivelyReadOnlyObject".
>
> Benoit St-Jean via Pharo-users  writes:
>
> > It never occurred to me that it would ever be the case!
> > I've always thought classes were singleton and that SomeClass copy would
> > always return the sole instance of that class!
>
> Me too. But after taking a closer look at how copy and deepCopy work, it
> seems that maintaining singletons under copy operations is impossible.
> There is no way to tell the copying machinery to return the original
> object instead of making a new one. Unlike e.g. Python, where this is
> possible and even quite common.
>
> Konrad.
>


[Pharo-users] Re: Can a class be not equal to itself?

2020-12-31 Thread Richard O'Keefe
What I said just now is true, but it doesn't tell the
whole story.  It turns out that Squeak, VisualWorks,
GNU Smalltalk, and Pharo *deliberately* make
aClass copy return a new class with the same superclass
and methods (but no subclasses).  Dolphin and VisualAge
do not.  So if you don't want to make copies of classes,
you must avoid ALL of #deepCopy, #shallowCopy, AND #copy.


On Fri, 1 Jan 2021 at 13:59, Richard O'Keefe  wrote:

> #deepCopy is one of those things that is best avoided,
> because it violates the key principle of OOP that an
> object is in charge of its own data and behaviour.
> It can not so much break invariants as crush them and
> bury them in an unmarked grave, just like #shallowCopy.
>
>
>
> On Fri, 1 Jan 2021 at 03:25, Konrad Hinsen 
> wrote:
>
>> On 31/12/2020 12:19, Konrad Hinsen wrote:
>>
>> > It's been a while since I have encountered mysterious behavior in
>> > Pharo, but today it happened. I set up a dictionary with classes as
>> > keys, and got "Key not found" errors for keys that were definitely in
>> > my dictionary. A quick debugging session showed the underlying issue:
>> > I had two references to a class which look the same when inspected,
>> > but turn out to be not identical (==) and thus not equal (=). How can
>> > this happen?
>>
>>
>> Update, after a few more debugging sessions: my dictionary is the result
>> of a deepCopy operation, meaning the class has been copied. And the copy
>> of a class is indeed a distinct but otherwise indistinguishable class.
>> 'Object copy = Object' is 'false'.
>>
>>
>> Konrad.
>>
>


[Pharo-users] Re: Can a class be not equal to itself?

2020-12-31 Thread Richard O'Keefe
#deepCopy is one of those things that is best avoided,
because it violates the key principle of OOP that an
object is in charge of its own data and behaviour.
It can not so much break invariants as crush them and
bury them in an unmarked grave, just like #shallowCopy.



On Fri, 1 Jan 2021 at 03:25, Konrad Hinsen 
wrote:

> On 31/12/2020 12:19, Konrad Hinsen wrote:
>
> > It's been a while since I have encountered mysterious behavior in
> > Pharo, but today it happened. I set up a dictionary with classes as
> > keys, and got "Key not found" errors for keys that were definitely in
> > my dictionary. A quick debugging session showed the underlying issue:
> > I had two references to a class which look the same when inspected,
> > but turn out to be not identical (==) and thus not equal (=). How can
> > this happen?
>
>
> Update, after a few more debugging sessions: my dictionary is the result
> of a deepCopy operation, meaning the class has been copied. And the copy
> of a class is indeed a distinct but otherwise indistinguishable class.
> 'Object copy = Object' is 'false'.
>
>
> Konrad.
>


[Pharo-users] Re: [exercism bowling challenge] Is there a better way to do this

2020-12-22 Thread Richard O'Keefe
Yes, there is a better way to do it.
I found this particular problem at the Programming Praxis
web site, which took it from
http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata

This is a superb example of how an informal specification
and a set of test cases can diverge.

The specification says to score a bowling game according
to a particular set of rules.  Here is exactly the algorithm
called for, written in the functional programming language
Haskell:

score (10:b:c:xs) = b+10+c+(if null xs then 0 else score (b:c:xs))
score (a:b:c:xs) | a+b = 10 = 10+c+(if null xs then 0 else score (c:xs))
score (a:b:xs) =   a+b+(if null xs then 0 else score xs)

That's *it*.  Explanation, (10:b:c:xs) means "a sequence starting
with 10, followed by something (call it b), followed by something
(call it c), followed by the rest of the sequence (call that xs).
This is actually strictly statically typed as well.
And it shows the while the data are *provided* from first to
last, the score is most easily *computed* from last to first.

Let's remind ourselves of Kent Beck's four rules of good code:
1. Runs all the tests
2. Contains no duplication
3. Expresses all the important design intentions
4. Minimizes entities (e.g. classes and methods).

Hence the Extreme Programming slogan
"You Ain't Gonna Need It."

Now we come to the divergence between the specification
(which calls for #roll: and #score methods)
and the tests (which call for a #scoreAfterRolling: method
and then in test 15 calls for #scoreRolling:after:).

There are two kind of test case for this exercise.
+ check that the result is correct in a good case
- check that the right error is raised given bad data.
Now the second kind go far beyond the informal
specification and require not only that certain errors
be detected but *when* they are detected.

And this is something you have to bear in mind when
writing down your test cases:  you have to prevent ideas
you may have about *how* the code might work creeping into
your test cases and forcing the code to work that way.
Most of my code, and most of the trouble I had writing the
code, was about these "does it report the right error at
the right time and oh yeah I made up these 'right' definitions
with no warrant in the customer's requirements" test cases.

I mean, seriously, NO methods in common between the specifications
and tests?

Returning to Kent Beck's maxims.  How many classes do we need?
The test code calls for ONE class, "Bowling".
There are no tests for any Frame pr Roll classes,
and no need for any.
How many methods does it need?
The test code checks #scoreAfterRolling and #scoreRolling:after:
There are not tests for any others.
What state should the instances of the class hold?
There is hint
  You will need to store some game state.
but that applies to the #roll:/#score interface,
NOT to the interface that's actually tested.

Use as many classes and methods as you NEED,
but remember that you need a lot fewer than you think,


On Mon, 21 Dec 2020 at 23:05, r.wobben--- via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Hello,
>
>
> To come back at this one.
>
> I made a class Bowling and a class Frame which contains two instance
> variables named firstThrow and secondThrow.
>
>
> but I still wonder how do I know which one to fill in.
>
> I can do ` (firstThrow nil?) ` but that feels not right.
>
>
> Is there a more idiomatic solution for this ?
>
>
> Roelof
>
>
>


[Pharo-users] Re: Please explain self

2020-12-12 Thread Richard O'Keefe
#subclassResponsibility is defined in Object.
A good way to find this out is to
 - select 'subclassResponsibility' with the mouse
 - type Control-M
Control-M asks for a list of the iMplementors of the method.
Control-N asks for a list of the seNders of the message.

This particular method just raises an exception.
It is how you define what some languages call an "abstract method";
a method whose *interface* is defined in the current class
but whose *implementation* is deferred to subclasses.

I can't help you with #session except to suggest that it is
probably defined in some superclass.  In the browser button bar
between the upper and lower panes you may see
(*) Flat ( ) Hier
Clicking on Hier will change the class pane (2nd from the left,
upper level) to an indented list, making it easy to see what
the superclass chain is.

On Sun, 13 Dec 2020 at 08:21, g_patrickb--- via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> I understand if you have Class A with methods p and q that you can call q
> from p doing:
>
> self q
>
> But there are some cases where a method doesn’t exist but self is still
> used. I found a tutorial on creating a Reddit type app and it had a .mcz
> which I loaded.
>
> Here is an example from Class StLoggedInComponent and method refreshReport:
>
> self report rows: (self session user tasks select: self filterBlock).
>
> There is a method ‘report’ so I understand that, but there is no method
> named ‘session’ so what is the use of self?
>
> And Class StDatabase has method ‘updateTask:’ has:
>
> self subclassResponsibility.
>
> But no method called ‘subclassResponsibility’ exists in the Class.
>
> Also, Class StLoggedInComponents has method ‘testTasks’ with this:
>
> ^ self class testTasks
>
> What is ‘self class’?
>
> Thank you.
>


[Pharo-users] Re: Energy efficiency of Pharo/Smalltalk

2020-10-20 Thread Richard O'Keefe
The energy comparison web site is a useful reference.
However, it measures a combination of
 - hardware platform
 - operating system (for example, FASTA does oodles of output)
 - compiler
 - runtime system (for example, garbage collector)
 - algorithm.
Where there are multiple algorithms for a single language,
we can see that that matters a LOT.  For example, the fastest
Rust code for FASTA is five times faster than the slowest, and
we can expect a similar range in energy use.

In the case of Smalltalk, do we expect Pharo and Amber to have
the same time or energy costs?

One of my earliest papers examined a "language X vs language Y"
paper where I pointed out that they had compared moderately bad
language X code to appallingly bad language Y code and when you
improved both the only real difference was the efficiency of the
'print' function in each language.  For this reason, amongst
others, if you want to compare *languages*, you need multiple
implementations in each language, otherwise what you are measuring
is as much programmer skill as anything else.

The one supremely useful thing in the language efficiency paper is
that all the code they used is on github, including the tool they
used to measure energy use.  (It's a software-only tool.)  That
means that you can do your own measurements, and that's what really
matters.

On Wed, 21 Oct 2020 at 03:29, Mariano Martinez Peck 
wrote:

> Here is an interesting article that could help as a start:
>
>
> https://thenewstack.io/which-programming-languages-use-the-least-electricity/
>
> Cheers,
>
>
> On Thu, Oct 15, 2020 at 8:41 PM Richard O'Keefe  wrote:
>
>> It doesn't make a whole lot of sense to talk about the energy efficiency
>> of a programming language.  For example, I've seen the run time of a
>> C benchmark go from 50 seconds to 1 microsecond when the optimisation
>> level was changed.  It doesn't even make much sense to talk about the
>> energy efficiency of the code generated by a specific compiler with
>> specific options: the underlying hardware counts too.   A colleague of
>> mine, looking at text compression algorithms for an information retrieval
>> engine, found that the fastest algorithm depended on just which x86-64
>> chip, even what motherboard, was in use.  It's obviously going to be
>> the same for energy efficiency.
>>
>> So let's specify a particular physical machine, a particular compiler,
>> and a particular set of compiler options.  NOW does it make sense to
>> talk about energy efficiency?  Nope.  It's going to depend on the
>> problem as well.  And the thing is that people tend to do different
>> things in different programming languages, and different communities
>> attract different support.  There is no portable Smalltalk equivalent
>> of NumPy, able to automatically take advantage of GPUs, for example.
>>
>> You can get some real surprises.
>> For example, just now while writing this message, I fired up
>> powerstat(8).  I had the browser open and power consumption was
>> about 12.8 W.  I then launched Squeak and ran some benchmarks.
>> Power consumption went DOWN to 11.4 W.
>> That is, Squeak was "costing" me -1.4 W.
>>
>> If you understand the kind of things modern CPUs get up to, that
>> is not as surprising as it seems.  All it demonstrates is that
>> getting MEANINGFUL answers is hard enough; getting GENERALISBLE
>> answers is going to be, well, if anyone succeeded, I think they
>> would have earned at least a Masters.
>>
>>
>> On Tue, 13 Oct 2020 at 23:38, Jonathan van Alteren <
>> jvalte...@objectguild.com> wrote:
>>
>>> Hi Stéphane,
>>>
>>> Thanks for your feedback. I agree that the usefulness of these results
>>> is limited. However, if we (Object Guild) want to make a case for energy
>>> efficiency, it can help if the language itself can be shown to be efficient
>>> as well.
>>>
>>> For now, I think the efficiency will need to come from a good object
>>> design.
>>>
>>> Kind regards,
>>>
>>> Jonathan van Alteren
>>>
>>> Founding Member | Object Guild B.V.
>>> *Sustainable Software for Purpose-Driven Organizations*
>>>
>>> On 11 Oct 2020, 16:49 +0200, Stéphane Ducasse ,
>>> wrote:
>>>
>>> The problem is that what do you measure.
>>> When you move computation from the CPU to a GPU for example does it
>>> consume less or more.
>>> I think that such analyses are totally stupid.
>>> Is a fast execution consume less? I have serious doubts about it.
>>> Now if we measure how fast we drain a battery because of polling vs
&g

[Pharo-users] Re: Energy efficiency of Pharo/Smalltalk

2020-10-15 Thread Richard O'Keefe
It doesn't make a whole lot of sense to talk about the energy efficiency
of a programming language.  For example, I've seen the run time of a
C benchmark go from 50 seconds to 1 microsecond when the optimisation
level was changed.  It doesn't even make much sense to talk about the
energy efficiency of the code generated by a specific compiler with
specific options: the underlying hardware counts too.   A colleague of
mine, looking at text compression algorithms for an information retrieval
engine, found that the fastest algorithm depended on just which x86-64
chip, even what motherboard, was in use.  It's obviously going to be
the same for energy efficiency.

So let's specify a particular physical machine, a particular compiler,
and a particular set of compiler options.  NOW does it make sense to
talk about energy efficiency?  Nope.  It's going to depend on the
problem as well.  And the thing is that people tend to do different
things in different programming languages, and different communities
attract different support.  There is no portable Smalltalk equivalent
of NumPy, able to automatically take advantage of GPUs, for example.

You can get some real surprises.
For example, just now while writing this message, I fired up
powerstat(8).  I had the browser open and power consumption was
about 12.8 W.  I then launched Squeak and ran some benchmarks.
Power consumption went DOWN to 11.4 W.
That is, Squeak was "costing" me -1.4 W.

If you understand the kind of things modern CPUs get up to, that
is not as surprising as it seems.  All it demonstrates is that
getting MEANINGFUL answers is hard enough; getting GENERALISBLE
answers is going to be, well, if anyone succeeded, I think they
would have earned at least a Masters.


On Tue, 13 Oct 2020 at 23:38, Jonathan van Alteren <
jvalte...@objectguild.com> wrote:

> Hi Stéphane,
>
> Thanks for your feedback. I agree that the usefulness of these results is
> limited. However, if we (Object Guild) want to make a case for energy
> efficiency, it can help if the language itself can be shown to be efficient
> as well.
>
> For now, I think the efficiency will need to come from a good object
> design.
>
> Kind regards,
>
> Jonathan van Alteren
>
> Founding Member | Object Guild B.V.
> *Sustainable Software for Purpose-Driven Organizations*
>
> On 11 Oct 2020, 16:49 +0200, Stéphane Ducasse ,
> wrote:
>
> The problem is that what do you measure.
> When you move computation from the CPU to a GPU for example does it
> consume less or more.
> I think that such analyses are totally stupid.
> Is a fast execution consume less? I have serious doubts about it.
> Now if we measure how fast we drain a battery because of polling vs event
> based then this is different.
>
> S.
>
> On 1 Oct 2020, at 13:47, Jonathan van Alteren 
> wrote:
>
> Hi all,
>
> I am interested in energy efficiency metrics for Pharo (version >=8). Just
> now, I came across this research and related GitHub project:
>
>- https://sites.google.com/view/energy-efficiency-languages
>- https://github.com/greensoftwarelab/Energy-Languages
>
>
> Unfortunately, the paper mentions that Smalltalk was excluded from the
> results because the (VW) compiler was proprietary :-S However, the GitHub
> repository does contain Smalltalk code and results, but I haven't been able
> to evaluate those.
>
> [1] Does anyone here have more information on this topic?
>
>
> The benchmarks seem to be low-level algorithms. Although that is useful, I
> think that a better argument for Pharo/Smalltalk efficiency is that a good
> OO design (e.g. created using responsibility-driven design with
> behaviorally complete objects) will be a better fit, can be much simpler
> and will thus be more efficient during development, as well as easier to
> maintain and evolve.
>
> [2] Has anyone done any research in this area that can quantify this
> aspect?
>
> Kind regards,
>
> Jonathan van Alteren
>
> Founding Member | Object Guild B.V.
> *Sustainable Software for Purpose-Driven Organizations*
>
> jvalte...@objectguild.com
>
>
> 
> Stéphane Ducasse
> http://stephane.ducasse.free.fr / http://www.pharo.org
> 03 59 35 87 52
> Assistant: Aurore Dalle
> FAX 03 59 57 78 50
> TEL 03 59 35 86 16
> S. Ducasse - Inria
> 40, avenue Halley,
> Parc Scientifique de la Haute Borne, Bât.A, Park Plaza
> Villeneuve d'Ascq 59650
> France
>
>


[Pharo-users] Re: exercism bowling challenge

2020-09-25 Thread Richard O'Keefe
It turns out that this problem has appeared elsewhere,
at least twice to my knowledge, and I had already solved
the version at Programming Praxis over a year ago.
I actually wrote two solutions, in different programming
languages.  One of them was 8 lines.  That was the longer.
The Haskell version was just 3 lines.

The Exercism tasks are what they are.  They DO provide
drill in using the more conventional aspects of Smalltalk.
They DON'T provide good drill in object-oriented DESIGN.

This particular problem can be solved clearly and cleanly
with a ByteArray and a handful of integers.

The fact that the test harness enforces the raising of
certain exceptions which are nowhere mentioned in the
specification complicates things rather.  (As does the
fact that the interface enforced by the test harness
contradicts the interface required by the specification.)

Remember, given a list of rolls, Haskell can do the
whole calculation in three straightforward lines.  Getting
the code to work is tricky, not because the calculations
are intrinsically hard, but because the specification is
very confusingly worded.


On Fri, 25 Sep 2020 at 19:23, David Bajger  wrote:

> Hi Richard,
> I want to reply to some of your insights here, because I think it is
> sometimes a matter of personal preference on a problem solution, so I
> want to compete with your opinion here. I might be totally wrong, when I
> see your way of solution and tell just 'you were right, your solution is
> more elegant'. For me it is an approach discussion.
>
>
>
> čt 24. 9. 2020 v 15:16 odesílatel Richard O'Keefe 
> napsal:
>
>> Since the problem can be solved, and has been solved, in programming
>> languages that do not support object-oriented programming, there is
>> obviously no unique "right" factoring of this problem into classes.  I'll
>> be honest with you: this is the only Pharo exercism I have not tackled, and
>> the reason is that I just found the problem specification too ugly to care
>> about.  I had better get over that.
>>
>
> We are using OO language to isolate problems into particular objects and
> their responsibility. I would say there is no "ugly problem to care about".
> Sometimes it can be the "right" factoring of a problem into classes and
> sometimes it is too hard and that is the point. I think this exercise is
> about finding the right place to delegate problems in fitting classes
> that are small enough. Of course, it can be resolved by one "long method"
> with a total of less lines of code. But in general I like more verbosity
> over one compact algorithm that wouldn't tell readers too much. This is a
> personal preference.
>
>
>>
>> The two primary difficulties are
>> (a) the game is described one ROLL at a time, but scored one FRAME at a
>> time.
>> (b) the rolls are recorded from past to future, but the score can only be
>> calculated from future to past.
>>
>
> Way of evaluation is definitely relevant. Key thing for me was to realize
> "I always need to evaluate the current state of things", the same way, when
> you play bowling.
> - Each frame should be able to tell, if it is completed from the point of
> actual throw. So, why not just pass throws by game into the current frame,
> that would tell, if it is completed or not?
> - Frame can calculate score immediately, but bonuses can be later. Maybe
> it isn't 'the throw thing' to care about. It is a matter of the game, that
> can tell when is the right moment to evaluate bonuses. Game can delegate
> such information to the passed frames at the right moment (maybe after each
> thow, or maybe when the current frame is completed?). But maybe my previous
> sentence can be interpreted as:  "this is a big hammer for this solution
> already".
>
>
>
>> The fact that there may be one extra roll at the end which is not
>> technically
>> part of any of the 10 frames is just icing on the cake.
>>
>> But this is *algorithmic* trickiness, not *world model* trickiness.
>>
>> Let's imagine a Frame class.
>> - You get the first roll of the frame.  Fewer than 10 pins are knocked
>> down.
>>   You cannot complete initialising the Frame yet.
>>
>
> Well, why not just initialize frame by "collection of 1-2 (maybe 3)
> throws"? Depending on the actual state of collection, frame just tells the
> game "I have enough throws, so you can pass throws to my neighbor". Rules
> for completeness can be different, based on circumstances. For me, it is a
> matter of frame responsibility to deal with this.
>
>
>> - All 10 pins are knocked down.  You cannot determine the *score* of the
>>   frame yet.  This casts some doub

[Pharo-users] Re: exercism bowling challenge

2020-09-24 Thread Richard O'Keefe
Since the problem can be solved, and has been solved, in programming
languages that do not support object-oriented programming, there is
obviously no unique "right" factoring of this problem into classes.  I'll
be honest with you: this is the only Pharo exercism I have not tackled, and
the reason is that I just found the problem specification too ugly to care
about.  I had better get over that.

The two primary difficulties are
(a) the game is described one ROLL at a time, but scored one FRAME at a
time.
(b) the rolls are recorded from past to future, but the score can only be
calculated from future to past.
The fact that there may be one extra roll at the end which is not
technically
part of any of the 10 frames is just icing on the cake.

But this is *algorithmic* trickiness, not *world model* trickiness.

Let's imagine a Frame class.
- You get the first roll of the frame.  Fewer than 10 pins are knocked down.
  You cannot complete initialising the Frame yet.
- All 10 pins are knocked down.  You cannot determine the *score* of the
  frame yet.  This casts some doubt on the idea of the score being part
  of the state of the frame.  The score actually depends on the next two
  THROWS (rolls), not the next frame or the next two frames.  This casts
  much doubt on the idea of the concept "frame" being useful for the
  analysis.  At the very least, you will need to manipulate BOTH frames
  AND throws (rolls).
It looks as though a Frame class may just make things harder.
Since the only thing there is to know about a Throw is how many pins
were knocked down, it doesn't look as though a Throw class is much use
either.  This leaves us with a BowlingGame class that just keeps tracks
of rolls and then runs a moderately complex algorithm when it is asked
for the score.

Long past my bed-time or I would get stuck into it.

On Thu, 24 Sep 2020 at 23:53, Roelof Wobben via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Op 24-9-2020 om 13:42 schreef DavidBajger:
> > Hi Roelof,
> > I always wonder, what kind of answer you expect from your prior
> statement.
> > To your question: "Can this plan be working or is there improvements to
> this
> > plan." I can have this answer: Yes, it could be both: working or fail,
> but
> > you don't know before you try.
> >
> > This exercise is a bit tricky:
> > 1) I can recommend to use also LastFrame class, which has specific
> handling
> > of bonuses in last round of game (subclass of Frame). Bowling game can be
> > then initialized with array 9 Frame instances and last instance could be
> > LastFrame. I used specific test methods on frame classes like:
> > #isFrameComplete, #isLastFrame, #isSpare, #isStrike, #isOpen.
> > 2) Beware that Bowling game should know only necessary things and
> delegate
> > responsibility to its frames. Game itself knows that only if all frames
> are
> > completed, game ends.
> > 3) Total score is sum of all throws+bonuses of individual frames, etc.
> >
> > Does it help to start with exercise?
> > David
> >
> >
> >
> >
> >
> > -
> > David Bajger
> > --
> > Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>
> Thanks,
>
> Maybe I have to make it more clear.
> What I trying to ask and what you have answered. Do I use the right
> classes or too much classes there.
> So if my idea of using these classes are right.
>
> What you wrote is what I had in mind with 2  classes but the idea of a
> lastFrame could also be working.
> and I also agree with you about the responsibilities of the classes.
>
> Roelof
>


[Pharo-users] Re: roman numbers

2020-09-19 Thread Richard O'Keefe
This is a problem where the only data structures you need,
other than the integer you are encoding and the string you
are building, is a small number of array literals.

Here is pseudo-code.
If self is negative, emit a negative sign.
If self is zero, emit N and finish.
Let n be the absolute value of self.
Emit M (n//1000) times -- use #next:put:
Encode n // 100 \\ 10 using M D C.
Encode n // 10 \\ 10 using C L X.
Encode n \\10 using X V I
To encode a digit using x v i,
write the characters of
 #('' 'i' 'ii' 'iii' 'iv' 'v' 'vi' 'vii' 'viii' 'ix' 'x')
 at the digit + 1 (use #nextPutAll:).

I have checked this pseudocode by writing
#asRomanPrintString (2 lines including header) calling
#asRomanPrintOn: (9 lines including header)
and verified that each number from -4000 to +4000
gets the same result from #printStringRoman and
#asRomanPrintString (except 0, which Pharo gets wrong).

Now we *could* do the "encode a digit" using smaller
or no tables, but it would take more code.  In this
case we can check that the right output for a digit
is produced just by LOOKING at the table, rather than
by checking complicated code.



On Sat, 19 Sep 2020 at 02:13, Pablo Navarro  wrote:

> Hi! Maybe you can use this algorithm:
>
> Define a dictionary with these elements:
>
> 1000:'M',
> 900:'CM',
> 500: 'D',
> 400: 'CD',
> 100:"C",
> 90:'XC',
> 50:'L',
> 40:'XL',
> 10:'X',
> 9:'IX',
> 5:'V',
> 4:'IV',
> 1:'I'
>
> Using this dictionary (romansDic), you define a recursive function:
>
> toRomans(number){
>   i = return the greatest key less than or equal to given key from
> ‘romansDic'  .
>   if (number == i ){
> return romansDic.get(number)
> }
>   return string_concat(romansDic.get(i), toRomans(number-i))
> }
>
> Sorry for the pseudocode.
>
> Saludos Pablo.
>
>
> El 18 de sep. de 2020 10:46 -0300, Roelof Wobben via Pharo-users <
> pharo-users@lists.pharo.org>, escribió:
>
> Op 18-9-2020 om 06:45 schreef Richard O'Keefe:
>
> Roman numerals are much more complicated and much less consistent
> than most people realise.  The regular M DC LX VI system is both
> more modern and less capable than anything the Romans would have
> recognised.  In particular,
>  - in the 8th century, N (short for "nulla") was adopted for zero
>  - the Roman system always had fractions like S for 1/2, . for 1/12
>  - there were numerals for much larger numbers.
> Unicode code block [2150] has characters for the Roman numerals
> including
> 216C L ROMAN NUMERAL FIFTY
> 216D C ROMAN NUMERAL ONE HUNDRED
> 216E D ROMAN NUMERAL FIVE HUNDRED
> 216F M ROMAN NUMERAL ONE THOUSAND
> 2181 ↁ ROMAN NUMERAL FIVE THOUSAND
> 2182 ↂ ROMAN NUMERAL TEN THOUSAND
> 2187 ↇ ROMAN NUMERAL FIFTY THOUSAND
> 2188 ↈ ROMAN NUMERAL ONE HUNDRED THOUSAND
> (In fact these are ligated versions of forms using "apostrophic" brackets;
> the pattern goes as high as you want, e.g., (((|))) for a million.
> D and M were originally |) and (|).   There is
>
> So the first thing is to make sure that you understand the
> requirements for the problem.
> - Are you required to produce ASCII characters, required to
>   produce Unicode ones, or allowed to produce either?
>
>
> as far as I can see from the tests only ASCI characters.
>
> - Are you required to support zero?
>
>
> No
>
> - Are you required to support n/12 fractions (1<=n<=11)?
>
>
> NO
>
> - Are you allowed, required, or forbidden to use the "overline"
>   convention, where an overline means "multiply by 1000"?
>   =---
>
>
> In the test that one is not used.
>
>   ICCXXXIVDLXVII = 1,234,567
> - Are you allowed, required, or forbidden to use "additive"
>   form "" as well as/instead of "subtractive" form "IV"?
> - Are you to use upper case or lower case letters?
> - And so on.
>
>
>
>
> the number 4 needs to be  "IV"
>
> Roelof
>
>


[Pharo-users] Re: roman numbers

2020-09-17 Thread Richard O'Keefe
Roman numerals are much more complicated and much less consistent
than most people realise.  The regular M DC LX VI system is both
more modern and less capable than anything the Romans would have
recognised.  In particular,
 - in the 8th century, N (short for "nulla") was adopted for zero
 - the Roman system always had fractions like S for 1/2, . for 1/12
 - there were numerals for much larger numbers.
Unicode code block [2150] has characters for the Roman numerals
including
216C L ROMAN NUMERAL FIFTY
216D C ROMAN NUMERAL ONE HUNDRED
216E D ROMAN NUMERAL FIVE HUNDRED
216F M ROMAN NUMERAL ONE THOUSAND
2181 ↁ ROMAN NUMERAL FIVE THOUSAND
2182 ↂ ROMAN NUMERAL TEN THOUSAND
2187 ↇ ROMAN NUMERAL FIFTY THOUSAND
2188 ↈ ROMAN NUMERAL ONE HUNDRED THOUSAND
(In fact these are ligated versions of forms using "apostrophic" brackets;
the pattern goes as high as you want, e.g., (((|))) for a million.
D and M were originally |) and (|).   There is

So the first thing is to make sure that you understand the
requirements for the problem.
- Are you required to produce ASCII characters, required to
  produce Unicode ones, or allowed to produce either?
- Are you required to support zero?
- Are you required to support n/12 fractions (1<=n<=11)?
- Are you allowed, required, or forbidden to use the "overline"
  convention, where an overline means "multiply by 1000"?
  =---
  ICCXXXIVDLXVII = 1,234,567
- Are you allowed, required, or forbidden to use "additive"
  form "" as well as/instead of "subtractive" form "IV"?
- Are you to use upper case or lower case letters?
- And so on.

I am not happy with the way that (0 printStringRoman) quietly
produces ''.

Assuming you're generating regular modern Roman numbers,
you pretty much have to think of an integer as having 4 parts:
n // 1000  -- this many copies of M
n // 100 \\ 10 -- hundreds using M, D, C
n // 10 \\ 100 -- tens using C, L, X
n \\ 10-- units usingX, V, I

If Squeak/Pharo's (0 printStringRoman) would answer 'N'
instead of '' I'd be happier with it.

While you really want to write your own code --- this
being an exercism task --- it would be a very good idea
to start by using #printStringRoman so that you know
what it's like to pass the tests.



On Fri, 18 Sep 2020 at 04:58, Roelof Wobben via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Hello,
>
> The challenge is to do it manually.
> But I can take a look how that function is implented.
>
> Roelof
>
>
>
> Op 17-9-2020 om 18:13 schreef Aliaksei Syrel:
>
> Hi Roelof,
>
> You will not believe!
>
> 2 printStringRoman “II”
> Have fun!
>
> On Thu, 17 Sep 2020 at 18:20, Roelof Wobben via Pharo-users <
> pharo-users@lists.pharo.org> wrote:
>
>> Hello,
>>
>>
>>
>> Can someone help me with a good plan to convert numbers to roman numbers.
>>
>>
>>
>> I could make a dictionary with 1,4,5,9,10,99,100, 999, 1000 but that
>>
>> feels like a overkill.
>>
>>
>>
>> Regards,
>>
>>
>>
>> Roelof
>>
>> --
> Cheers,
> Alex
>
>
>


[Pharo-users] Re: How can I make this more OOP

2020-09-15 Thread Richard O'Keefe
In a language like Java or C# or Ada we can insist at
compile time that an argument conforms to a protocol,
whatever class it might be an instance of.

In Smalltalk, we can use #isKindOf: to test whether
an object inherits from a class, but that is often the
wrong test.  We can use (multiple calls to) #respondsTo:
to tell whether an object conforms to a protocol.

The only snag, of course, is that in too many Smalltalk
systems, #respondsTo: is not trustworthy.  If a class
has a method that sends #subclassResponsibility or
#shouldNotImplement, it's still counted as responding
to the selector in question.

This is not a problem in my Smalltalk because
(a) you are not allowed to create a direct instance of
a class where any method calls #subclassResponsibility.
(b) #shouldNotImplement appears only in test cases.
Since I already have named protocols, with classes
declaring their intention to conform to them, I've
been thinking about adding
  aClass implements: aProtocol
  anInstance conformsTo: aProtocol
but have not done that yet.

I note that Pharo V7.0.3 had 132 senders of #respondsTo:
and Pharo V8.0.0 has 126 senders of #respondsTo:.
These neatly bracket Dolphin 7's 130.



On Wed, 16 Sep 2020 at 06:50, Stéphane Ducasse 
wrote:

>
>
> On 14 Sep 2020, at 16:02, Roelof Wobben via Pharo-users <
> pharo-users@lists.pharo.org> wrote:
>
>
> Thanks Richard for this explanation.
> and I like also your idea of using #respondTo instead of asking a object
> if its a collection or a item.
>
>
> refrain from using respondTo:
> I make code difficult to evolve and can introduce vicious bugs.
>
> S.
>
> Roelof
>
>
> Op 14-9-2020 om 14:28 schreef Richard O'Keefe:
>
> "OOP is not asking an object what it is"?  You've lost me.
> I'm reminded of a joke exam question that goes something
> like this:
>Some things have ping nature and other things have pong nature.
>Discuss, with examples.
>
> Whatever else it is, OOP is a means to an end, not an end in itself.
> It's not a religion.  Allah will not cast you into the Fire for using
> something which is not ritually pure.
>
> The whole point of the Design Patterns movement was not to present
> canned solutions but to describe common *situations* characterised
> by (metaphorical) *forces* pushing you in incompatible directions.
>
> Question 1: Why do you even have a stream there?
> flattenArray: aCollection
> |buffer|
> buffer := OrderedCollection new: aCollection size.
> self flattenArray: aCollection into: buffer.
> ^buffer asArray
>
> flattenArray: anObject into: buffer
> (anObject respondsTo: #do:)
>ifTrue:  [anObject do: [:each | self flattenArray: each into:
> buffer]
>ifFalse: [anObject ifNotNil: [buffer addLast: anObject].
>
> (CAUTION: untested code.)
>
> Question 2: is there any point in *trying* to make this more ping and less
> pong?
> I have to say that in 40 years of programming, I have *never* wanted to
> flatten
> a completely arbitrary structure.  When I have wanted to flatten
> something, it
> has always been an instance of the Composite design pattern, so that a
> specific
> and quite small set of classes has been involved.
>
> I am well aware that some Smalltalk systems have some sort of 'flatten'
> lying around like a rake in the grass, but I have found no two which agree
> on the specification.
>
> Question 3: Let's consider an if-less alternative.
>
> Stream
>   flattenInto: buffer
> self do: [:each| each flattenInto: buffer].
>
> Collection
>   flattenInto: buffer
> self do:[:each | each flattenInto: buffer].
>
> Object
>   flattenInto: buffer
> buffer addLast: self.
>
> UndefinedObject
>   flattenInto: buffer
> "Do nothing."
>
> This is Smalltalk, where we *can* add methods to system classes like these.
> When the payoff is worth it, I have no qualms whatever in doing so.
> But putting methods of little or no utility into the interface of EVERY
> object just feels so wrong.
>
> Here we have opposing forces:
>  - The first approach adds two methods to your worker class,
>and no methods to any system class.  Instead, it uses
>"does this object know how to iterate over its elements?"
>and "is this object nil?".  This does minimal damage to
>system structure at the price of a little ritual impurity.
>
>  - The second approach adds a method to four system classes,
>enlarging the interface of every object in the system,
>creating a level of coupling we'd be better without, and
>making it harder for someone reading your code to figure
>out what's going on.
>
> In the context of a Composite, with a limited number of
> appli

[Pharo-users] Re: how can I improve this

2020-09-15 Thread Richard O'Keefe
SequenceableCollection has with:do:.
Add
with: other count: testBlock
|r|
r := 0.
self with: other do: [:x :y |
(testBlock value: x value: y) ifTrue: [r := r + 1]].
^r

I have this in my library anyway.  Now

distanceStrand1: a strand2: b
^a with: b count: [:x :y | x ~= y]

#with:do: already checks that the sequences have the same size;
it's too confusing if the error reported in this case is different
from the error for #with:do:.

On Tue, 15 Sep 2020 at 16:59, Roelof Wobben via Pharo-users <
pharo-users@lists.pharo.org> wrote:

> Op 14-9-2020 om 22:19 schreef Hernán Morales Durand:
>
> ^ (1 to: self size) count: [ : i | (self at: i) ~= (aString at: i) ]
>
>
>
> With that code I get a few problems but this is working
>
> distanceStrand1: aString strand2: aString2
> aString size == aString2 size
> ifFalse: [ DomainError signal: (self messageFor: aString strand2:
> aString2) ].
> ^ (1 to: aString size)
> count: [ :i | (aString2 at: i) ~= (aString at: i) ]
>
> Roelof
>
>
>


[Pharo-users] Re: Rounding in Floats

2020-09-15 Thread Richard O'Keefe
If you are going to use floating point numbers in any programming
language, Pharo included, you need to understand something about
them.  Things like
 - the relevant precision is *fixed*; a Float in Pharo is *always*
   a 64-bit IEEE floating-point number, which amongst other things
   means (to a first approximation) 54 binary digits of precision.
   It doesn't make the slightest amount of difference how many
   decimal digits you use when writing the number, the precision
   is *always* 54 binary digits.  So you *did* get the precision
   out of rounding that you put in, it's just that the precision
   you put in was not what you thought it was.
 - almost all modern architectures offer BINARY arithmetic, not
   decimal.  (The main exceptions are IBM z/series and IBM POWER,
   which offer binary *and* decimal.)  Rounding a number to n
   decimals is ALWAYS problematic using binary floats.  This has
   little or nothing to do with Smalltalk: it's the hardware.
   (This is why you are advised to keep money in cents, not dollars.)
 - Again, this is NOT a language issue, it is a hardware issue.
   IF you understand how binary floating point arithmetic works,
   then the arithmetic you get in C or R or Smalltalk or Matlab
   does not surprise you at all.
   If you DON'T understand how binary floating point arithmetic works,
   the hardware will *get* you sooner or later.
 - ScaledDecimal in Pharo didn't have to violate the principle of
   least surprise, but it does, big time.
 - It would be really nice if Pharo offered true decimal arithmetic
   as an option.  There may already be a package for this.



On Tue, 8 Sep 2020 at 15:46, Esteban Maringolo  wrote:

> On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe  wrote:
> >
> > "7.1 roundTo: 0.1 should return 7.1"
> > You're still not getting it.
>
> I was until Konrad explained it.
>
> > Binary floating point CANNOT represent either of those numbers.
> > You seem to be assuming that Pharo is making some mistake.
> > It isn't.  All it is doing is refusing to lie to you.
> 
> > The systems that print 7.1 are LYING to you,
> > and Pharo is not.
>
> I'm not assuming a mistake from Pharo, I had a wrong expectation what
> to get if I round to that precision.
> I don't know whether other systems lie or simply fulfill user
> expectations, if you send the #roundTo: to a float, I did expect to
> get a number with the same precision.
> That is my expectation as a user. As in the other thread I expected
> two scaled decimals that are printed equal to also be compared as
> equal  (which they don't).
>
> Whether there is a good reason for those behaviors is beyond my
> current comprehension, but it certainly doesn't follow the "principle
> of least surprise".
>
> In any case, the method proposed by Tomohiro solved my issues.
>
> Regards,
>
> Esteban A. Maringolo
>
>


[Pharo-users] Re: How can I make this more OOP

2020-09-15 Thread Richard O'Keefe
I take Sean's point.  However, while I agree that practising using
polymorphism instead of 'if' is a good idea, I don't think that
*this* exercise is a good one for getting such practice.
Roelof is going through the Pharo track of Exercism.
This particular one is called 'flatten-array'.
The one concession to "hey, this is Pharo!" in the description
of the exercise is a veiled warning against using Pharo's
#flattened/#flattenOn:, which
(a) does not add anything to Object or UndefinedObject
(just Collection>>flattened and Collection>>flattenOn:)
(b) does not make a special case of nil
(c) DOES make a special case of strings, treating them as atomic.
Possibly the most challenging part for me in this exercise was
trying to figure out "what does  mean for Smalltalk here?"
In Pharo's existing #flattened, why does a String count as atomic
but a Semphore is just another collection?

This is a Lisp programming exercise from the early 1960s.
It had unpleasant ambiguities back then and it has not got
better since.

If this were rewritten as
  "Make a Composite implementation of binary search trees
   with a class for empty trees, a class for non-empty ones,
   and perhaps a class for singleton ones.
   Implement #do:, traversing the elements in increasing order.
   Use this to implement #asOrderedCollection."
then that *would* be a good exercise for using polymorphism
instead of conditionals.

BST ()
  asOrderedCollection
^OrderedCollection new in: [:coll |
   self do: [:each | coll addLast: each].
   coll]
  EmptyBST ()
do: aBlock
  "Nothing to do."
  NonemptyBST (less key greater)
do: aBlock
  less do: aBlock.
  aBlock value: key.
  greater do: aBlock.




On Tue, 15 Sep 2020 at 18:33, Sean P. DeNigris 
wrote:

> Richard O'Keefe wrote
> > Whatever else it is, OOP is a means to an end, not an end in itself.
> > It's not a religion.
>
> Richard makes an important point here.
>
> As I mentioned on Discord (slightly edited to fit this thread), it’s a
> judgment call with trade-offs, but for the purposes of an OOP exercise, I
> would say absolutely put the methods in object and wherever else you may
> need them - if only to get practice with that particular idiom. I needed to
> do a lot of that sort of thing - probably way *too* much, just to break my
> procedural thinking habits. Once I got it "in my bones" I became more
> pragmatic. While in theory, this may always be the “most“ OOP way, in
> practice it can be confusing due to the limitations of our system
> organization and the fact that people will have to scroll through more
> methods on kernel objects (not to mention the extra dependencies Richard
> noted). That is the dogma, and I think is a fine answer for an OOP
> exercise,
> but IMHO in practice there are justifiable exceptions. The two major axes
> are understandability and adaptability. If in your domain there are only
> two
> choices and there can not logically be more, it may be easier to understand
> one method with a conditional that documents that domain fact, than it
> would
> be to dive down a polymorphism rabbit hole spread across the system. Of
> course, tooling is a big factor in understandability. In GT it may be
> trivial because you can open implementors in a plane right next to the code
> browser. Different toolsets themselves mean different trade offs. There are
> no one size fits all answers for all time. There are principles that have
> to
> be negotiated with your current environment, use case, experience level,
> team size...
>
>
>
> -
> Cheers,
> Sean
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>


  1   2   3   4   >