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> wrote: > > > > On May 11, 2020 2:19:49 PM PDT, Richard O'Keefe <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> wrote: >>> >>> >>> >>> On 5 May 2020, at 16:16, Richard O'Keefe <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> >> 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> >> 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> >> 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 >>> Morgedalsvn. 5A http://folk.uio.no/trygver/ >>> N-0378 Oslo http://fullOO.info >>> Norway Tel: (+47) 468 58 625 >>> >>> >>> >>> -------------------------------------------- >>> 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 >>> > >
signature.asc
Description: Message signed with OpenPGP