thanks this is interesting. S.
> On 12 May 2020, at 07:12, Richard O'Keefe <rao...@gmail.com> wrote: > > For what it's worth, here's a moderately thorough examination of several > different Smalltalk systems. > Let A = astc, D = Dolphin, G = GNU Smalltalk, Q = Squeak, > S = ANSI standard, T = Strongtalk, V = VisualWorks, X = ST/X > > #asString > > ADGPQST!X Character => String with: self > ADGPQSTVX String => self > ADGPQSTVX Symbol => String withAll: self > ......... Text/Paragraph, where provided, => underlying string. > A-G-----X Collection => String withAll: self > ---PQ---- Collection => self printString > A........ ByteArray => "decoded as Unicode" > .DGPQ-TVX ByteArray => "decoded as Latin1" > ADG.Q..VX Filename => "unparse (Filename, FilePath, whatever) > AdgpQ.TVX URI => "unparse (ZnUrl in P) > Ad.PQ...X UUID => "unparse (d, GUID equivalent)" > .DGpq...X Number => self displayString "or self printString, maybe via > Object" > ...PQ...X Object => self printString > > There's a rough consensus here: > - if something *is* textual (Character, String, Symbol, Text, > Paragraph) #asString returns it as a normal string > - if something is a parsed form of structured text (file name, > URI, UUID) its unparsed form is returned, converting it back > should yield an equal parsed form > - if something is a byte array, it may be converted to a string > (the rule is to preserve the bytes, my library presumes byte > arrays are UTF8-encoded) > - if numbers are accepted at all, their #printString is returned > - if is none of the above, but has a #name or #title, that is > commonly the result. > > The open question is what converting an array of characters using > #asString will do. There is at least one Smalltalk out there > where #(65 66 67) asString => 'ABC', but that's a step further > than I personally want, though it is consistent with ByteArray. > > > > > On Tue, 12 May 2020 at 11:16, Jerry Kott <jk...@image-ware.com > <mailto:jk...@image-ware.com>> wrote: > Hi all, > > I’ve been lurking so far, but I must add my voice here and agree with Richard. > > The malleability of Smalltalk tempts people into implementing #asString, > #name, and similar semantically ambiguous method names. Like Richard, I > regretted every single time I (or someone else on my team before me) decided > to use these. It goes back to ’Smalltalk with Style’ (probably the best > little red book you could ever own): write intention revealing code whenever > you can, and comment liberally when you can’t. > > Jerry Kott > This message has been digitally signed. > PGP Fingerprint: > A9181736DD2F1B6CC7CF9E51AC8514F48C0979A5 > > > >> On 11-05-2020, at 2:48 PM, Richard Sargent <rsarg...@5x5.on.ca >> <mailto:rsarg...@5x5.on.ca>> wrote: >> >> >> >> On May 11, 2020 2:19:49 PM PDT, Richard O'Keefe <rao...@gmail.com >> <mailto:rao...@gmail.com>> wrote: >>> I was saying that I expected #($a $b $c) asString ==> 'abc'. >> >> Over the years, I found myself being opposed to the idea that all objects >> can sensibly have an #asString implementation. When it's been done, it >> ultimately caused more problems than it solved. >> >> Consider $(48 49 50) asString. Do you expect it to give you a string with >> all the digits? Or perhaps it's meant to interpret the elements as byte-like >> things, as you would need for "String withAll: aCollection". So, the numbers >> could be interpreted as codepoints, as they are in a ByteArray. >> >> But, what does "(Array with: Object new with: ProcessScheduler) asString" >> mean? >> >> It seems to me that having all objects understand #asString leads to >> confusion. >> >> If you want an array to print as its literal representation, implement >> #printAsLiteral, so that your intention is clear. >> >> >>> If you want something that can be read back, that's what #storeString >>> is for, >>> >>> On Tue, 12 May 2020 at 01:28, Stéphane Ducasse >>> <stephane.duca...@inria.fr <mailto:stephane.duca...@inria.fr>> wrote: >>>> >>>> >>>> >>>> On 5 May 2020, at 16:16, Richard O'Keefe <rao...@gmail.com >>>> <mailto:rao...@gmail.com>> wrote: >>>> >>>> By the way, while playing with this problem, I ran into a moderately >>>> painful issue. >>>> >>>> There is a reason that Smalltalk has both #printString (to get a >>>> printable representation of an object) and #asString (to convert a >>>> sequence to another kind of sequence with the same elements.) If I >>>> *want* #printString, I know where to find it. The definition in my >>>> Smalltalk no reads >>>> >>>> asString >>>> "What should #($a $b $c) do? >>>> - Blue Book, Inside Smalltalk, Apple Smalltalk-80: >>>> there is no #asString. >>>> - ANSI, VW, Dolphin, CSOM: >>>> #asString is defined on characters and strings >>>> (and things like file names and URIs that are sort of >>> strings), >>>> so expect an error report. >>>> - VisualAge Smalltalk: >>>> '($a $b $c)' >>>> - Squeak and Pharo: >>>> '#($a $b $c)' >>>> - GNU Smalltalk, Smalltalk/X, and astc: >>>> 'abc' >>>> I don't intend any gratuitous incompatibility, but when there >>>> is no consensus to be compatible with, one must pick something, >>>> and this seems most useful. >>>> " >>>> ^String withAll: self >>>> >>>> Does anyone here know WHY Squeak and Pharo do what they do here? >>>> >>>> >>>> Oops I did not see the quotes on my screen.. >>>> >>>> #( a b c) asString >>>>>>> '#(#a #b #c)’ >>>> >>>> this is unclear to me why this is not good but I have no strong >>> opinion >>>> that this is good. >>>> >>>> I worked on printString for literals because I wanted to have >>>> self evaluating properties for basic literal like in Scheme and >>> others. >>>> where >>>> #t >>>>>>> >>>> #t >>>> >>>> And I payed attention that we get the same for literal arrays. >>>> Now the conversion is open to me. >>>> >>>> #($a $b $c) asString >>>>>>> >>>> '#($a $b $c)’ >>>> >>>> In fact I do not really understand why a string >>>> >>>> #($a $b $c) asString would be '(a b c)’ >>>> and its use >>>> if this is to nicely display in the ui I would have >>>> displayString doing it. >>>> >>>> S. >>>> >>>> >>>> >>>> On Wed, 6 May 2020 at 01:20, Richard O'Keefe <rao...@gmail.com >>>> <mailto:rao...@gmail.com>> >>> wrote: >>>> >>>> >>>> The irony is that the code I was responding to ISN'T obviously >>> correct. >>>> Indeed, I found it rather puzzling. >>>> The problem specification says that the input string may contain >>> digits >>>> AND SPACES. The original message includes this: >>>> >>>> Strings of length 1 or less are not valid. Spaces are allowed in the >>>> input, but they should be stripped before checking. All other >>>> non-digit characters are disallowed. >>>> >>>> Now it isn't clear what "disallowed" means. I took it to mean "may >>> occur and >>>> should simply mean the input is rejected as invalid." Perhaps "may >>> not occur" >>>> was the intention. So we shall not quibble about such characters. >>>> >>>> But I can't for the life of me figure out how Trygve's code checks >>> for spaces. >>>> One reason this is an issue is that the behaviour of #digitValue is >>> not >>>> consistent between systems. >>>> Character space digitValue >>>> does not exist in the ANSI standard >>>> answers -1 in many Smalltalks (which is a pain) >>>> answers a positive integer that can't be mistake for a digit in my >>> Smalltalk >>>> raises an exception in some Smalltalks. >>>> >>>> This is a comment I now have in my Smalltalk library for #digitValue >>>> "This is in the Blue Book, but unspecified on non-digits. >>>> Squeak, Pharo, Dolphin, VW, VAST, and Apple Smalltalk-80 >>>> answer -1 for characters that are not digits (or ASCII >>> letters), >>>> which is unfortunate but consistent with Inside Smalltalk >>>> which specifies this result for non-digits. >>>> ST/X and GST raise an exception which is worse. >>>> Digitalk ST/V documentation doesn't specify the result. >>>> This selector is *much* easier to use safely if it >>>> returns a 'large' (>= 36) value for non-digits." >>>> >>>> Let's compare three versions, the two I compared last time, >>>> and the "version A" code I discussed before, which to my mind >>>> is fairly readable. >>>> >>>> "Don't add slowness": 1 (normalised time) >>>> "Trygve's code": 6.5 >>>> "High level code": 30.6 (or 4.7 times slower than Trygve's) >>>> >>>> Here's the "High level code". >>>> ^(aString allSatisfy: [:each | each isSpace or: [each isDigit]]) >>> and: [ >>>> |digitsReverse| >>>> digitsReverse := (aString select: [:each | each isDigit]) >>> reverse. >>>> digitsReverse size > 1 and: [ >>>> |evens odds evenSum oddSum| >>>> odds := digitsReverse withIndexSelect: [:y :i | i odd]. >>>> evens := digitsReverse withIndexSelect: [:x :i | i even]. >>>> oddSum := odds detectSum: [:y | y digitValue]. >>>> evenSum := evens detectSum: [:x | >>>> #(0 2 4 6 8 1 3 5 7 9) at: x digitValue + 1]. >>>> (oddSum + evenSum) \\ 10 = 0]] >>>> >>>> This is the kind of code I was recommending that Roelof write. >>>> >>>> As a rough guide, by counting traversals (including ones inside >>> existing >>>> methods), I'd expect the "high level" code to be at least 10 times >>> slower >>>> than the "no added slowness" code. >>>> >>>> We are in vehement agreement that there is a time to write high level >>>> really obvious easily testable and debuggable code, and that's most >>>> of the time, especially with programming exercises. >>>> >>>> I hope that we are also in agreement that factors of 30 (or even 6) >>>> *can* be a serious problem. I mean, if I wanted something that slow, >>>> I'd use Ruby. >>>> >>>> I hope we are also agreed that (with the exception of investigations >>>> like this one) the time to hack on something to make it faster is >>> AFTER >>>> you have profiled it and determined that you have a problem. >>>> >>>> But I respectfully suggest that there is a difference taking slowness >>> OUT >>>> and simply not going out of your way to add slowness in the first >>> place. >>>> >>>> I'd also like to remark that my preference for methods that traverse >>> a >>>> sequence exactly once has more to do with Smalltalk protocols than >>>> with efficiency. If the only method I perform on an object is #do: >>>> the method will work just as well for readable streams as for >>>> collections. If the only method I perform on an object is >>> #reverseDo: >>>> the method will work just as well for Read[Write]Streams as for >>>> SequenceReadableCollections, at least in my library. It's just like >>>> trying to write #mean so that it works for Durations as well as >>> Numbers. >>>> >>>> Oh heck, I suppose I should point out that much of the overheads in >>>> this case could be eliminated by a Self-style compiler doing dynamic >>>> inlining + loop fusion. There's no reason *in principle*, given >>> enough >>>> people, money, and time, that the differences couldn't be greatly >>>> reduced in Pharo. >>>> >>>> On Tue, 5 May 2020 at 21:50, Trygve Reenskaug <tryg...@ifi.uio.no >>>> <mailto:tryg...@ifi.uio.no>> >>> wrote: >>>> >>>> >>>> Richard, >>>> >>>> Thank you for looking at the code. It is comforting to learn that the >>> code has been executed for a large number of examples without breaking. >>> The code is not primarily written for execution but for being read and >>> checked by the human end user. It would be nice if we could also check >>> that it gave the right answers, but I don't know how to do that. >>>> >>>> The first question is: Can a human domain expert read the code and >>> sign their name for its correctness? >>>> >>>> >>>> When this is achieved, a programming expert will transcribe the first >>> code to a professional quality program. This time, the second code >>> should be reviewed by an independent programmer who signs their name >>> for its correct transcription from the first version. >>>> >>>> --Trygve >>>> >>>> PS: In his 1991 Turing Award Lecture, Tony Hoare said: "There are two >>> ways of constructing a software design: One way is to make it so simple >>> that there are obviously no deficiencies and the other is to make it so >>> complicated that there are no obvious deficiencies. The first method is >>> far more difficult." >>>> >>>> --Trygve >>>> >>>> On tirsdag.05.05.2020 04:41, Richard O'Keefe wrote: >>>> >>>> As a coding experiment, I adapted Trygve Reenskoug's code to my >>>> Smalltalk compiler, put in my code slightly tweaked, and benchmarked >>>> them on randomly generated data. >>>> >>>> Result: a factor of 6.3. >>>> >>>> In Squeak it was a factor of ten. >>>> >>>> I had not, in all honesty, expected it to to be so high. >>>> >>>> On Tue, 5 May 2020 at 02:00, Trygve Reenskaug <tryg...@ifi.uio.no >>>> <mailto:tryg...@ifi.uio.no>> >>> wrote: >>>> >>>> A coding experiment. >>>> Consider a Scrum development environment. Every programming team has >>> an end user as a member. >>>> The team's task is to code a credit card validity check. >>>> A first goal is that the user representative shall read the code and >>> agree that it is a correct rendering of their code checker: >>>> >>>> luhnTest: trialNumber >>>> | s1 odd s2 even charValue reverse | >>>> ----------------------------------------------- >>>> " Luhn test according to Rosetta" >>>> "Reverse the order of the digits in the number." >>>> reverse := trialNumber reversed. >>>> "Take the first, third, ... and every other odd digit in the reversed >>> digits and sum them to form the partial sum s1" >>>> s1 := 0. >>>> odd := true. >>>> reverse do: >>>> [:char | >>>> odd >>>> ifTrue: [ >>>> s1 := s1 + char digitValue. >>>> ]. >>>> odd := odd not >>>> ]. >>>> "Taking the second, fourth ... and every other even digit in the >>> reversed digits: >>>> Multiply each digit by two and sum the digits if the answer is >>> greater than nine to form partial sums for the even digits" >>>> "The subtracting 9 gives the same answer. " >>>> "Sum the partial sums of the even digits to form s2" >>>> s2 := 0. >>>> even := false. >>>> reverse do: >>>> [:char | >>>> even >>>> ifTrue: [ >>>> charValue := char digitValue * 2. >>>> charValue > 9 ifTrue: [charValue := charValue - >>> 9]. >>>> s2 := s2 + charValue >>>> ]. >>>> even := even not >>>> ]. >>>> "If s1 + s2 ends in zero then the original number is in the form of a >>> valid credit card number as verified by the Luhn test." >>>> ^(s1 + s2) asString last = $0 >>>> --------------------------------- >>>> Once this step is completed, the next step will be to make the code >>> right without altering the algorithm (refactoring). The result should >>> be readable and follow the team's conventions. >>>> >>>> >>>> P.S. code attached. >>>> >>>> >>>> -- >>>> >>>> The essence of object orientation is that objects collaborate to >>> achieve a goal. >>>> Trygve Reenskaug mailto: tryg...@ifi.uio.no >>>> <mailto:tryg...@ifi.uio.no> >>>> Morgedalsvn. 5A http://folk.uio.no/trygver/ >>>> <http://folk.uio.no/trygver/> >>>> N-0378 Oslo http://fullOO.info <http://fulloo.info/> >>>> Norway Tel: (+47) 468 58 625 >>>> >>>> >>>> >>>> -------------------------------------------- >>>> Stéphane Ducasse >>>> http://stephane.ducasse.free.fr <http://stephane.ducasse.free.fr/> / >>>> http://www.pharo.org <http://www.pharo.org/> >>>> 03 59 35 87 52 >>>> Assistant: Julie Jonas >>>> 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 >>>> >> >> > -------------------------------------------- Stéphane Ducasse http://stephane.ducasse.free.fr / http://www.pharo.org 03 59 35 87 52 Assistant: Julie Jonas 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