Pharo-users
By thread
pharo-users@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- 1 participants
- 50346 messages
Re: [Pharo-users] mentor question 4
by Ben Coman
On Sun, 3 May 2020 at 03:09, Roelof Wobben <r.wobben(a)home.nl> wrote:
> Op 2-5-2020 om 19:33 schreef Ben Coman:
>
>
>
> On Sat, 2 May 2020 at 15:52, Roelof Wobben via Pharo-users <
> pharo-users(a)lists.pharo.org> wrote:
>
>> Op 1-5-2020 om 08:35 schreef Roelof Wobben:
>> >> On Fri, 1 May 2020 at 02:16, Roelof Wobben <r.wobben(a)home.nl> wrote:
>> >>> Op 30-4-2020 om 16:06 schreef Richard O'Keefe:
>> >>>> This sounds very much like the Luhn test task at RosettaCode.
>> >>>> https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers
>> >>>> except that there it is described as working on the digits of an
>> >>>> integer.
>> >>>>
>> >>>> (1) There are two approaches to traversing a sequence in reverse.
>> >>>> (A) Reverse the sequence, then traverse the copy forward.
>> >>>> aString reverse do: [:each | ...]
>> >>>> (B) Just traverse the sequence in reverse
>> >>>> aString reverseDo: [:each | ...]
>> >>>> My taste is for the second.
>> >>>>
>> >>>> (2) There are two approaches to deleting spaces.
>> >>>> (A) Make a copy of the string without spaces.
>> >>>> x := aString reject: [:each | each = Character space].
>> >>>> x do: ...
>> >>>> (B) Ignore spaces as you go:
>> >>>> (i) aString do: [:each | each = Character space ifFalse:
>> >>>> [...]]
>> >>>> (ii) aString select: [:each | each ~= Character space]
>> >>>> thenDo:
>> >>>> [:each | ...]
>> >>>>
>> >>>> Combining (1A) and (2A) you get very obvious code:
>> >>>> (aString reject: [:each | each = Character space]) reverse do:
>> >>>> [:digit } ...]
>> >>>> Combining (1B) and (2Bi) you get more efficient code:
>> >>>> aString reverseDo: [:digit |
>> >>>> digit = Character space ifFalse: [ ...]]
>> >>>>
>> >>>> By the way, let's start by checking that the character in the
>> >>>> string *are*
>> >>>> digits or spaces:
>> >>>> (aString allSatisfy: [:each | each isDigit or: [each =
>> >>>> Character s[ace]])
>> >>>> ifFalse: [^false],
>> >>>>
>> >>>> (3) There are two approaches to doubling the even digits.
>> >>>> (A) Make a new string that starts as a copy and change every
>> >>>> second
>> >>>> digit from the right.
>> >>>> (B) Simply *act* as if this has been done; keep track of
>> >>>> whether the
>> >>>> current digit position is even or odd and multiply by 1
>> >>>> or 2 as
>> >>>> appropriate.
>> >>>> nextIsOdd := true.
>> >>>> aString reverseDo: [:digit |
>> >>>> digit = Character space ifFalse: [
>> >>>> nextIsOdd
>> >>>> ifTrue: [oddSum := ...]
>> >>>> ifFalse: [evenSum := ...].
>> >>>> nextIsOdd := nextIsOdd not]].
>> >>>>
>> >>>> I *like* code that traverses a data structure exactly once and
>> >>>> allocates no intermediate garbage, so I'd be making (B) choices.
>> >>>>
>> >>>>
>> >>> For me , I use this to practice solving problems and doing the
>> >>> "right"
>> >>> steps.
>> >>> So I love it , that so many people share there way of solving it.
>> >>> I can learn a lot from it
>> >>> Expecially when they explain there thinking process so detailed.
>> >>>
>> >>> I like this code also a lot.
>> >>> Am I correct for testing if it is a valid string by doing this ^
>> >>> (oddSum + evenSum) dividedBy: 10
>> >>>
>> >>> Roelof
>> >>>
>> >
>> >
>> > oke,
>> >
>> > so this is better
>> >
>> > cardNumber := '8273 1232 7352 0569'.
>> > oddSum := 0.
>> > evenSum := 0.
>> > nextIsOdd := false.
>> > cardNumber reverseDo: [:character |
>> > digit := character digitValue.
>> > character = Character space ifFalse: [
>> > nextIsOdd
>> > ifFalse: [oddSum := oddSum + digit ]
>> > ifTrue: [(digit >= 5 )
>> > ifTrue: [evenSum := evenSum + (digit * 2) - 9 ]
>> > ifFalse: [ evenSum := evenSum + (digit * 2) ]].
>> > nextIsOdd := nextIsOdd not]].
>> > ^ evenSum + oddSum // 10 == 0.
>> >
>> >
>> > where I could even make a seperate method of the ifTrue branch when
>> > the digit is greater then 5.
>> >
>> >
>> nobody who can say if this is a good solution ?
>>
>
> You didn't actually ask a question :)
>
> btw, Its good you are stretching yourself to do it the most complicated
> way,
> but pay attention that when Richard says HE "likes code that traverses a
> data structure exactly once"
> its because he is starting with the philosophy to OPTIMISE for EFFICIENCY.
> Often in programming that is the LAST thing you should do because to do so
> your code often becomes more complex,
> and Kernagan's law applies...
> https://talixa.com/blog/why-i-write-simple-code/
>
> In general, you want to avoid premature optimization.
> https://effectiviology.com/premature-optimization/
>
> The catch-phrase I see around this forum priorities things in this order:
> 1. Make it work.
> 2. Make it right.
> 3. Make it fast.
> and often you can stop at 2 because it is already "fast enough".
>
> Considering your code above, if I take TIME to go through it, I can
> evaluate that it seems right
> but I remain feeling that I could have missed something.
>
> Something like Richard's (A) examples without loops I would consider to
> be "more good".
> since each line can be dealt with individually.
>
> cardNumber := '4539 1488 0343 6467'.
> cleanDigits := cardNumber copyWithout: Character space.
> preWrapDigits := cleanDigits asArray collectWithIndex: [ :char :idx |
> (idx\\2 + 1) * char digitValue ].
> wrappedDigits := preWrapDigits collect: [ :d | d > 9 ifFalse: [ d ]
> ifTrue: [ d-9 ] ].
> ^ wrappedDigits sum isDivisibleBy: 10.
>
> A side benefit is having full result of each transformation available to
> be reviewed,
> rather than having only pieces of it in view when you debug a loop.
>
> In the end though, yours is a good solution first and foremost because
> tried a more detailed way and you got it working!!
> Remember there is more than one "good way" to do it depending on what you
> are optimising for - efficiency or readability.
>
> cheers -ben
>
>
>
> I think I find readability more important then efficieny.
>
> But I think I have to alter your code. At first look it does not look like
> that every second value from the right is multiplied by 2.
>
> When the index is for example 7 .
>
> 7 // 2 gives 3.
> Maybe it needs to be %.
>
But why are you testing // when my code uses \\ ? :)
small details can have a big impact.
cheers -ben
May 3, 2020
Re: [Pharo-users] [ANN] Pharo Compendium
by Gabriel Cotelli
Really cool Torsten!. A much needed tool :)
On Sat, May 2, 2020 at 5:35 PM Torsten Bergmann <astares(a)gmx.de> wrote:
> Hi,
>
> time flows and Pharo-Project is improving on all ends since its inception
> in 2008. As you know over time for the code project hosting we used
> SqueakSource, SS3 repos and other and later switched to SmalltalkHub
> available on http://smalltalkhub.com.
> Starting with Iceberg in Pharo 6 many community projects are now hosted
> elsewhere - most of them moved to GitHub. Pharo's git support allows
> also for GitLab, BitBucket and other git hosting services.
>
> I still think easy and quick accessibility to external (re)sources
> directly from the image is key - especially for new users who often get lost
> among all the various things that are available. Back in 2013 I therefore
> provided a small tool called ConfigBrowser as a replacement for
> MetacelloConfigurationBrowser to easily load Metacello configs directly
> into Pharo.
>
> Later we improved quick loading with a primary tool called "Catalog"
> written by Esteban. Catalog is indexing every 24 hours all configs within
> specific meta-repositories on SmalltalkHub (per Pharo version) like
>
> http://www.smalltalkhub.com/#!/~Pharo/MetaRepoForPharo80
>
> to automatically build
>
> http://catalog.pharo.org/
>
> and also a JSON source
>
> http://catalog.pharo.org/catalog/json
>
> The last one feeds the catalog browser and catalog spotter search within
> the Pharo image.
>
> So Catalog helped us and especially new Pharo users to find what is
> available as external project or package. Unfortunately some package
> maintainers
> are too lazy and do not maintain their configs over old and new Pharo
> versions. Also SmalltalkHub.com is now seen as legacy and will only be
> available
> in a read only mode or as a browseable archive soon.
>
> So we have to think about others steps beyond Catalog and (triggered by a
> recent discussion on Discord) I started now a simple tool that helped me
> finding all GitHub projects marked with "pharo" as GitHub topic. I
> additionally also added previous catalog loading. More sources could be
> added
> as well as some kind of custom stores/plugins. Maybe this tool could be
> the base for a future replacement of the catalog tool.
>
> Long story short - let me introduce "Pharo Compendium":
>
> Compendium is a new UI tool to list, browse and load Pharo artefacts from
> the web like:
>
> - GitHub Projects
> - Catalog Projects
>
> and other
>
> By default there are two plugin packages available for GitHub and Catalog
> - but you can implement own ones easily to connect to other sources
> on the web. Compendium is available on:
>
> https://github.com/astares/Pharo-Compendium
>
> It is implemented using the new Spec2 UI framework - so you need a recent
> Pharo 9 image to give it a try. Just run:
>
> Metacello new
> repository: 'github://astares/Pharo-Compendium/src';
> baseline: 'Compendium';
> load
>
> to load the tool. Then go to "Tools" -> "Compendium Browser". Attached is
> a screenshot demoing the primary functionality.
>
> If you want your GitHub project to be listed in the tool you simply need
> to add the topic "pharo" to the GitHub repository on the GitHub webpage.
>
> Feel free to comment or help improving the tool by sending PR's.
>
> Thx
> T. (aka astares)
>
>
>
May 3, 2020
[ANN] Pharo Compendium
by Torsten Bergmann
Hi,
time flows and Pharo-Project is improving on all ends since its inception in 2008. As you know over time for the code project hosting we used
SqueakSource, SS3 repos and other and later switched to SmalltalkHub available on http://smalltalkhub.com.
Starting with Iceberg in Pharo 6 many community projects are now hosted elsewhere - most of them moved to GitHub. Pharo's git support allows
also for GitLab, BitBucket and other git hosting services.
I still think easy and quick accessibility to external (re)sources directly from the image is key - especially for new users who often get lost
among all the various things that are available. Back in 2013 I therefore provided a small tool called ConfigBrowser as a replacement for
MetacelloConfigurationBrowser to easily load Metacello configs directly into Pharo.
Later we improved quick loading with a primary tool called "Catalog" written by Esteban. Catalog is indexing every 24 hours all configs within
specific meta-repositories on SmalltalkHub (per Pharo version) like
http://www.smalltalkhub.com/#!/~Pharo/MetaRepoForPharo80
to automatically build
http://catalog.pharo.org/
and also a JSON source
http://catalog.pharo.org/catalog/json
The last one feeds the catalog browser and catalog spotter search within the Pharo image.
So Catalog helped us and especially new Pharo users to find what is available as external project or package. Unfortunately some package maintainers
are too lazy and do not maintain their configs over old and new Pharo versions. Also SmalltalkHub.com is now seen as legacy and will only be available
in a read only mode or as a browseable archive soon.
So we have to think about others steps beyond Catalog and (triggered by a recent discussion on Discord) I started now a simple tool that helped me
finding all GitHub projects marked with "pharo" as GitHub topic. I additionally also added previous catalog loading. More sources could be added
as well as some kind of custom stores/plugins. Maybe this tool could be the base for a future replacement of the catalog tool.
Long story short - let me introduce "Pharo Compendium":
Compendium is a new UI tool to list, browse and load Pharo artefacts from the web like:
- GitHub Projects
- Catalog Projects
and other
By default there are two plugin packages available for GitHub and Catalog - but you can implement own ones easily to connect to other sources
on the web. Compendium is available on:
https://github.com/astares/Pharo-Compendium
It is implemented using the new Spec2 UI framework - so you need a recent Pharo 9 image to give it a try. Just run:
Metacello new
repository: 'github://astares/Pharo-Compendium/src';
baseline: 'Compendium';
load
to load the tool. Then go to "Tools" -> "Compendium Browser". Attached is a screenshot demoing the primary functionality.
If you want your GitHub project to be listed in the tool you simply need to add the topic "pharo" to the GitHub repository on the GitHub webpage.
Feel free to comment or help improving the tool by sending PR's.
Thx
T. (aka astares)
May 2, 2020
Re: [Pharo-users] mentor question 4
by Richard Sargent
On Sat, May 2, 2020 at 12:38 PM Roelof Wobben via Pharo-users <
pharo-users(a)lists.pharo.org> wrote:
> Op 2-5-2020 om 21:09 schreef Roelof Wobben via Pharo-users:
>
>
> but this seems to work :
>
> cardNumber := '4539 1488 0343 6467'.
> cleanDigits := cardNumber copyWithout: Character space.
> preWrapDigits := (cleanDigits asArray reverse collectWithIndex: [ :char
> :idx | (idx even) ifTrue: [ 2 * char digitValue ] ifFalse:[char
> digitValue]]).
> wrappedDigits := preWrapDigits collect: [ :d | d > 9 ifFalse: [ d ]
> ifTrue: [ d-9 ] ].
> ^ wrappedDigits sum isDivisibleBy: 10.
>
> Can the code be more improved ?
>
As a general guideline, the best code will correspond closely to the
documented algorithm.
In this latest example, you have two visible loop iterations plus to hidden
loop iterations. It also includes object creation from both #asArray and
#reverse, the two messages with the hidden loop iteration.
For this exercise, the number of loops and object creations isn't relevant.
However, you always want to understand when you are doing such things. They
will have an impact if they are used inside a high frequency loop. Again,
that's not the case with this exercise. It often is in real world
applications.
But again, you should not optimize for performance at the expense of
clarity and readability until you need to. And when you do need to, you
annotate the code to explain how the implementation corresponds to or
differs from the more comprehensible implementation. (Comments should
explain the why and/or the background rather than the what.)
> Roelof
>
>
>
May 2, 2020
Re: [Pharo-users] mentor question 4
by Stéphane Ducasse
check with the finder and example
S.
> On 2 May 2020, at 21:09, Roelof Wobben <r.wobben(a)home.nl> wrote:
>
>
> From: Roelof Wobben <r.wobben(a)home.nl>
> Subject: Re: [Pharo-users] mentor question 4
> Date: 2 May 2020 at 21:09:12 CEST
> To: Ben Coman <btc(a)openinworld.com>, Any question about pharo is welcome <pharo-users(a)lists.pharo.org>
>
>
> Op 2-5-2020 om 19:33 schreef Ben Coman:
>>
>>
>> On Sat, 2 May 2020 at 15:52, Roelof Wobben via Pharo-users <pharo-users(a)lists.pharo.org <mailto:pharo-users@lists.pharo.org>> wrote:
>> Op 1-5-2020 om 08:35 schreef Roelof Wobben:
>> >> On Fri, 1 May 2020 at 02:16, Roelof Wobben <r.wobben(a)home.nl <mailto:r.wobben@home.nl>> wrote:
>> >>> Op 30-4-2020 om 16:06 schreef Richard O'Keefe:
>> >>>> This sounds very much like the Luhn test task at RosettaCode.
>> >>>> https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers <https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers>
>> >>>> except that there it is described as working on the digits of an
>> >>>> integer.
>> >>>>
>> >>>> (1) There are two approaches to traversing a sequence in reverse.
>> >>>> (A) Reverse the sequence, then traverse the copy forward.
>> >>>> aString reverse do: [:each | ...]
>> >>>> (B) Just traverse the sequence in reverse
>> >>>> aString reverseDo: [:each | ...]
>> >>>> My taste is for the second.
>> >>>>
>> >>>> (2) There are two approaches to deleting spaces.
>> >>>> (A) Make a copy of the string without spaces.
>> >>>> x := aString reject: [:each | each = Character space].
>> >>>> x do: ...
>> >>>> (B) Ignore spaces as you go:
>> >>>> (i) aString do: [:each | each = Character space ifFalse:
>> >>>> [...]]
>> >>>> (ii) aString select: [:each | each ~= Character space]
>> >>>> thenDo:
>> >>>> [:each | ...]
>> >>>>
>> >>>> Combining (1A) and (2A) you get very obvious code:
>> >>>> (aString reject: [:each | each = Character space]) reverse do:
>> >>>> [:digit } ...]
>> >>>> Combining (1B) and (2Bi) you get more efficient code:
>> >>>> aString reverseDo: [:digit |
>> >>>> digit = Character space ifFalse: [ ...]]
>> >>>>
>> >>>> By the way, let's start by checking that the character in the
>> >>>> string *are*
>> >>>> digits or spaces:
>> >>>> (aString allSatisfy: [:each | each isDigit or: [each =
>> >>>> Character s[ace]])
>> >>>> ifFalse: [^false],
>> >>>>
>> >>>> (3) There are two approaches to doubling the even digits.
>> >>>> (A) Make a new string that starts as a copy and change every
>> >>>> second
>> >>>> digit from the right.
>> >>>> (B) Simply *act* as if this has been done; keep track of
>> >>>> whether the
>> >>>> current digit position is even or odd and multiply by 1
>> >>>> or 2 as
>> >>>> appropriate.
>> >>>> nextIsOdd := true.
>> >>>> aString reverseDo: [:digit |
>> >>>> digit = Character space ifFalse: [
>> >>>> nextIsOdd
>> >>>> ifTrue: [oddSum := ...]
>> >>>> ifFalse: [evenSum := ...].
>> >>>> nextIsOdd := nextIsOdd not]].
>> >>>>
>> >>>> I *like* code that traverses a data structure exactly once and
>> >>>> allocates no intermediate garbage, so I'd be making (B) choices.
>> >>>>
>> >>>>
>> >>> For me , I use this to practice solving problems and doing the
>> >>> "right"
>> >>> steps.
>> >>> So I love it , that so many people share there way of solving it.
>> >>> I can learn a lot from it
>> >>> Expecially when they explain there thinking process so detailed.
>> >>>
>> >>> I like this code also a lot.
>> >>> Am I correct for testing if it is a valid string by doing this ^
>> >>> (oddSum + evenSum) dividedBy: 10
>> >>>
>> >>> Roelof
>> >>>
>> >
>> >
>> > oke,
>> >
>> > so this is better
>> >
>> > cardNumber := '8273 1232 7352 0569'.
>> > oddSum := 0.
>> > evenSum := 0.
>> > nextIsOdd := false.
>> > cardNumber reverseDo: [:character |
>> > digit := character digitValue.
>> > character = Character space ifFalse: [
>> > nextIsOdd
>> > ifFalse: [oddSum := oddSum + digit ]
>> > ifTrue: [(digit >= 5 )
>> > ifTrue: [evenSum := evenSum + (digit * 2) - 9 ]
>> > ifFalse: [ evenSum := evenSum + (digit * 2) ]].
>> > nextIsOdd := nextIsOdd not]].
>> > ^ evenSum + oddSum // 10 == 0.
>> >
>> >
>> > where I could even make a seperate method of the ifTrue branch when
>> > the digit is greater then 5.
>> >
>> >
>> nobody who can say if this is a good solution ?
>>
>> You didn't actually ask a question :)
>>
>> btw, Its good you are stretching yourself to do it the most complicated way,
>> but pay attention that when Richard says HE "likes code that traverses a data structure exactly once"
>> its because he is starting with the philosophy to OPTIMISE for EFFICIENCY.
>> Often in programming that is the LAST thing you should do because to do so your code often becomes more complex,
>> and Kernagan's law applies...
>> https://talixa.com/blog/why-i-write-simple-code/ <https://talixa.com/blog/why-i-write-simple-code/>
>>
>> In general, you want to avoid premature optimization.
>> https://effectiviology.com/premature-optimization/ <https://effectiviology.com/premature-optimization/>
>>
>> The catch-phrase I see around this forum priorities things in this order:
>> 1. Make it work.
>> 2. Make it right.
>> 3. Make it fast.
>> and often you can stop at 2 because it is already "fast enough".
>>
>> Considering your code above, if I take TIME to go through it, I can evaluate that it seems right
>> but I remain feeling that I could have missed something.
>>
>> Something like Richard's (A) examples without loops I would consider to be "more good".
>> since each line can be dealt with individually.
>>
>> cardNumber := '4539 1488 0343 6467'.
>> cleanDigits := cardNumber copyWithout: Character space.
>> preWrapDigits := cleanDigits asArray collectWithIndex: [ :char :idx | (idx\\2 + 1) * char digitValue ].
>> wrappedDigits := preWrapDigits collect: [ :d | d > 9 ifFalse: [ d ] ifTrue: [ d-9 ] ].
>> ^ wrappedDigits sum isDivisibleBy: 10.
>>
>> A side benefit is having full result of each transformation available to be reviewed,
>> rather than having only pieces of it in view when you debug a loop.
>>
>> In the end though, yours is a good solution first and foremost because tried a more detailed way and you got it working!!
>> Remember there is more than one "good way" to do it depending on what you are optimising for - efficiency or readability.
>>
>> cheers -ben
>>
>
> I think I find readability more important then efficieny.
>
> But I think I have to alter your code. At first look it does not look like that every second value from the right is multiplied by 2.
>
> When the index is for example 7 .
>
> 7 // 2 gives 3.
> Maybe it needs to be %.
>
> Roelof
>
>
--------------------------------------------
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
May 2, 2020
Re: [Pharo-users] Thinking aloud about project at hand
by Stéphane Ducasse
>
>> I'm thinking about implementing a software solution in Pharo (as one of the
> candidate environments), it's
>> a project that I'm dealing with professionally. The goal is to develop a
>> financial planning/simulation
>> application on the country level, which is at present developed as a set
>> of interrelated Excel spreadsheets.
>> The requirement is that the solution should be more "manageable",
>> resilient and straightforward than
>> Excel permits, that it should present a workflow to the user - i.e. , that
>> the tasks the user should do are
>> suggested through the GUI.
>
> Thanks again for all the ideas regarding my project. So far I prepared the
> domain model and all the calculations. The model might be changed in the
> future, but that's basically it. Now I'm going to focus on the user's
> workflow and GUI.
>
> I have to say that I'm positively surprised by Pharo. Besides Pharo, I
> explored the feasibility of using other environments for the same project,
> namely VBA, .NET, Python. What took me in VBA and C#.NET roughly two weeks -
> and these are my 'native' programming environments - I finished in five days
> in Pharo. If GUI and finalization will go smoothly, this will be a success.
> I'm playing with Pharo for some time, but until now I haven't done any
> serious work with it. Nice!
>
Thanks Tomaz.
This is a really interesting story.
Let us know and we will do our best to help you.
Spec20 has still some rough edges. But one step at a time.
I think that we will get to a point where we can start to breath a bit around Spec2.0.
S.
May 2, 2020
Re: [Pharo-users] mentor question 4
by Roelof Wobben
Op 2-5-2020 om 21:09 schreef Roelof Wobben via Pharo-users:
but this seems to work :
cardNumber := '4539 1488 0343 6467'.
cleanDigits := cardNumber copyWithout: Character space.
preWrapDigits := (cleanDigits asArray reverse collectWithIndex: [ :char
:idx | (idx even) ifTrue: [ 2 * char digitValue ] ifFalse:[char
digitValue]]).
wrappedDigits :=Â preWrapDigits collect: [ :d | d > 9 ifFalse: [ d ]
ifTrue: [ d-9 ] ].
^ wrappedDigits sum isDivisibleBy: 10.
Can the code be more improved ?
Roelof
May 2, 2020
Re: [Pharo-users] mentor question 4
by Ben Coman
On Sat, 2 May 2020 at 15:52, Roelof Wobben via Pharo-users <
pharo-users(a)lists.pharo.org> wrote:
> Op 1-5-2020 om 08:35 schreef Roelof Wobben:
> >> On Fri, 1 May 2020 at 02:16, Roelof Wobben <r.wobben(a)home.nl> wrote:
> >>> Op 30-4-2020 om 16:06 schreef Richard O'Keefe:
> >>>> This sounds very much like the Luhn test task at RosettaCode.
> >>>> https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers
> >>>> except that there it is described as working on the digits of an
> >>>> integer.
> >>>>
> >>>> (1) There are two approaches to traversing a sequence in reverse.
> >>>> (A) Reverse the sequence, then traverse the copy forward.
> >>>> aString reverse do: [:each | ...]
> >>>> (B) Just traverse the sequence in reverse
> >>>> aString reverseDo: [:each | ...]
> >>>> My taste is for the second.
> >>>>
> >>>> (2) There are two approaches to deleting spaces.
> >>>> (A) Make a copy of the string without spaces.
> >>>> x := aString reject: [:each | each = Character space].
> >>>> x do: ...
> >>>> (B) Ignore spaces as you go:
> >>>> (i) aString do: [:each | each = Character space ifFalse:
> >>>> [...]]
> >>>> (ii) aString select: [:each | each ~= Character space]
> >>>> thenDo:
> >>>> [:each | ...]
> >>>>
> >>>> Combining (1A) and (2A) you get very obvious code:
> >>>> (aString reject: [:each | each = Character space]) reverse do:
> >>>> [:digit } ...]
> >>>> Combining (1B) and (2Bi) you get more efficient code:
> >>>> aString reverseDo: [:digit |
> >>>> digit = Character space ifFalse: [ ...]]
> >>>>
> >>>> By the way, let's start by checking that the character in the
> >>>> string *are*
> >>>> digits or spaces:
> >>>> (aString allSatisfy: [:each | each isDigit or: [each =
> >>>> Character s[ace]])
> >>>> ifFalse: [^false],
> >>>>
> >>>> (3) There are two approaches to doubling the even digits.
> >>>> (A) Make a new string that starts as a copy and change every
> >>>> second
> >>>> digit from the right.
> >>>> (B) Simply *act* as if this has been done; keep track of
> >>>> whether the
> >>>> current digit position is even or odd and multiply by 1
> >>>> or 2 as
> >>>> appropriate.
> >>>> nextIsOdd := true.
> >>>> aString reverseDo: [:digit |
> >>>> digit = Character space ifFalse: [
> >>>> nextIsOdd
> >>>> ifTrue: [oddSum := ...]
> >>>> ifFalse: [evenSum := ...].
> >>>> nextIsOdd := nextIsOdd not]].
> >>>>
> >>>> I *like* code that traverses a data structure exactly once and
> >>>> allocates no intermediate garbage, so I'd be making (B) choices.
> >>>>
> >>>>
> >>> For me , I use this to practice solving problems and doing the
> >>> "right"
> >>> steps.
> >>> So I love it , that so many people share there way of solving it.
> >>> I can learn a lot from it
> >>> Expecially when they explain there thinking process so detailed.
> >>>
> >>> I like this code also a lot.
> >>> Am I correct for testing if it is a valid string by doing this ^
> >>> (oddSum + evenSum) dividedBy: 10
> >>>
> >>> Roelof
> >>>
> >
> >
> > oke,
> >
> > so this is better
> >
> > cardNumber := '8273 1232 7352 0569'.
> > oddSum := 0.
> > evenSum := 0.
> > nextIsOdd := false.
> > cardNumber reverseDo: [:character |
> > digit := character digitValue.
> > character = Character space ifFalse: [
> > nextIsOdd
> > ifFalse: [oddSum := oddSum + digit ]
> > ifTrue: [(digit >= 5 )
> > ifTrue: [evenSum := evenSum + (digit * 2) - 9 ]
> > ifFalse: [ evenSum := evenSum + (digit * 2) ]].
> > nextIsOdd := nextIsOdd not]].
> > ^ evenSum + oddSum // 10 == 0.
> >
> >
> > where I could even make a seperate method of the ifTrue branch when
> > the digit is greater then 5.
> >
> >
> nobody who can say if this is a good solution ?
>
You didn't actually ask a question :)
btw, Its good you are stretching yourself to do it the most complicated
way,
but pay attention that when Richard says HE "likes code that traverses a
data structure exactly once"
its because he is starting with the philosophy to OPTIMISE for EFFICIENCY.
Often in programming that is the LAST thing you should do because to do so
your code often becomes more complex,
and Kernagan's law applies...
https://talixa.com/blog/why-i-write-simple-code/
In general, you want to avoid premature optimization.
https://effectiviology.com/premature-optimization/
The catch-phrase I see around this forum priorities things in this order:
1. Make it work.
2. Make it right.
3. Make it fast.
and often you can stop at 2 because it is already "fast enough".
Considering your code above, if I take TIME to go through it, I can
evaluate that it seems right
but I remain feeling that I could have missed something.
Something like Richard's (A) examples without loops I would consider to be
"more good".
since each line can be dealt with individually.
cardNumber := '4539 1488 0343 6467'.
cleanDigits := cardNumber copyWithout: Character space.
preWrapDigits := cleanDigits asArray collectWithIndex: [ :char :idx |
(idx\\2 + 1) * char digitValue ].
wrappedDigits := preWrapDigits collect: [ :d | d > 9 ifFalse: [ d ]
ifTrue: [ d-9 ] ].
^ wrappedDigits sum isDivisibleBy: 10.
A side benefit is having full result of each transformation available to be
reviewed,
rather than having only pieces of it in view when you debug a loop.
In the end though, yours is a good solution first and foremost because
tried a more detailed way and you got it working!!
Remember there is more than one "good way" to do it depending on what you
are optimising for - efficiency or readability.
cheers -ben
May 2, 2020
Re: [Pharo-users] mentor question 4
by Richard Sargent
It's a good solution.
On Sat, May 2, 2020, 00:52 Roelof Wobben via Pharo-users <
pharo-users(a)lists.pharo.org> wrote:
> Op 1-5-2020 om 08:35 schreef Roelof Wobben:
> > Op 1-5-2020 om 02:51 schreef Richard O'Keefe:
> >> (oddSum + evenSum) dividedBy: 10
> >>
> >> You previously had _ isDivisibleBy: 10
> >> which certainly works.
> >>
> >> Squeak, Pharo, and ST/X have #isDivisibleBy:
> >> VisualWorks. Dolphin, and GNU Smalltalk do not.
> >>
> >> Here's the code from Number.st in ST/X.
> >> isDivisibleBy:aNumber
> >> "return true, if the receiver can be divided by the argument,
> >> aNumber without a remainder.
> >> Notice, that the result is only worth trusting, if the receiver
> >> is an integer."
> >>
> >> aNumber = 0 ifTrue: [^ false].
> >> aNumber isInteger ifFalse: [^ false].
> >> ^ (self \\ aNumber) = 0
> >>
> >> The comment is wrong: the question makes sense for any combination
> >> of exact numbers.
> >> When, as in this case, aNumber is a literal integer, all
> >> #isDivisibleBy: really adds is overhead.
> >>
> >> (oddSum + evenSum) \\ 10 = 0
> >>
> >> is quite clear, and completely portable.
> >>
> >>
> >>
> >> On Fri, 1 May 2020 at 02:16, Roelof Wobben <r.wobben(a)home.nl> wrote:
> >>> Op 30-4-2020 om 16:06 schreef Richard O'Keefe:
> >>>> This sounds very much like the Luhn test task at RosettaCode.
> >>>> https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers
> >>>> except that there it is described as working on the digits of an
> >>>> integer.
> >>>>
> >>>> (1) There are two approaches to traversing a sequence in reverse.
> >>>> (A) Reverse the sequence, then traverse the copy forward.
> >>>> aString reverse do: [:each | ...]
> >>>> (B) Just traverse the sequence in reverse
> >>>> aString reverseDo: [:each | ...]
> >>>> My taste is for the second.
> >>>>
> >>>> (2) There are two approaches to deleting spaces.
> >>>> (A) Make a copy of the string without spaces.
> >>>> x := aString reject: [:each | each = Character space].
> >>>> x do: ...
> >>>> (B) Ignore spaces as you go:
> >>>> (i) aString do: [:each | each = Character space ifFalse:
> >>>> [...]]
> >>>> (ii) aString select: [:each | each ~= Character space]
> >>>> thenDo:
> >>>> [:each | ...]
> >>>>
> >>>> Combining (1A) and (2A) you get very obvious code:
> >>>> (aString reject: [:each | each = Character space]) reverse do:
> >>>> [:digit } ...]
> >>>> Combining (1B) and (2Bi) you get more efficient code:
> >>>> aString reverseDo: [:digit |
> >>>> digit = Character space ifFalse: [ ...]]
> >>>>
> >>>> By the way, let's start by checking that the character in the
> >>>> string *are*
> >>>> digits or spaces:
> >>>> (aString allSatisfy: [:each | each isDigit or: [each =
> >>>> Character s[ace]])
> >>>> ifFalse: [^false],
> >>>>
> >>>> (3) There are two approaches to doubling the even digits.
> >>>> (A) Make a new string that starts as a copy and change every
> >>>> second
> >>>> digit from the right.
> >>>> (B) Simply *act* as if this has been done; keep track of
> >>>> whether the
> >>>> current digit position is even or odd and multiply by 1
> >>>> or 2 as
> >>>> appropriate.
> >>>> nextIsOdd := true.
> >>>> aString reverseDo: [:digit |
> >>>> digit = Character space ifFalse: [
> >>>> nextIsOdd
> >>>> ifTrue: [oddSum := ...]
> >>>> ifFalse: [evenSum := ...].
> >>>> nextIsOdd := nextIsOdd not]].
> >>>>
> >>>> I *like* code that traverses a data structure exactly once and
> >>>> allocates no intermediate garbage, so I'd be making (B) choices.
> >>>>
> >>>>
> >>> For me , I use this to practice solving problems and doing the
> >>> "right"
> >>> steps.
> >>> So I love it , that so many people share there way of solving it.
> >>> I can learn a lot from it
> >>> Expecially when they explain there thinking process so detailed.
> >>>
> >>> I like this code also a lot.
> >>> Am I correct for testing if it is a valid string by doing this ^
> >>> (oddSum + evenSum) dividedBy: 10
> >>>
> >>> Roelof
> >>>
> >
> >
> > oke,
> >
> > so this is better
> >
> > cardNumber := '8273 1232 7352 0569'.
> > oddSum := 0.
> > evenSum := 0.
> > nextIsOdd := false.
> > cardNumber reverseDo: [:character |
> > digit := character digitValue.
> > character = Character space ifFalse: [
> > nextIsOdd
> > ifFalse: [oddSum := oddSum + digit ]
> > ifTrue: [(digit >= 5 )
> > ifTrue: [evenSum := evenSum + (digit * 2) - 9 ]
> > ifFalse: [ evenSum := evenSum + (digit * 2) ]].
> > nextIsOdd := nextIsOdd not]].
> > ^ evenSum + oddSum // 10 == 0.
> >
> >
> > where I could even make a seperate method of the ifTrue branch when
> > the digit is greater then 5.
> >
> >
> nobody who can say if this is a good solution ?
>
> Roelof
>
>
May 2, 2020