--- Begin Message ---
Thanks for the lessson and its correct that English is not my mother language. Im from the Netherlands and were very bad at languages but good at math, science  and that sort of things at school.

Some of the names as squareAt:  were given by the exercism challenge.

The things you said about the computer challenge which was a AdventOfCode one I agree.  im still not happy with my answer at this moment.

For me at this point , its  something a puzzle to find a way to  make the code to solve things that I do not spend and think a lot about names.

That is why I asked here a few times on a mentor which can learn me how to solve things like the computer one the smalltalk way but it seems that every one is very busy with thier own projects and work, which I understand but for my feeling I do not come to a higher level to understand OOP and things like how to solve things the smalltalk way and also learn more how to name things better.  As you hint to use a person to explain it to me , I do not have. My wife works full-time and has at the evening no time to help me with this.

So im now in a doubt if I want to go on with smalltalk, which I find a pity because I love it.
But on solving this sort of puzzles and learning how to make my own websie in seaside , i  get the feeling my learning is coming to a still stand.

Also enoough rambling  on this side.

Roelof





Op 4-1-2020 om 22:11 schreef Richard Sargent:
On Sat, Jan 4, 2020 at 11:51 AM Roelof Wobben <r.wob...@home.nl> wrote:
Oke,

I have reread the challenge and a hint was to use recursion.
But also is said to think how you can make one for speed or readability.

And I find the one I made certain not good for readability.

Roelof,

I think you are making good progress on the mechanics of programming. However, I assume that English is not your first language. (I would be embarrassed by your answer if I were to ask how many you do know!)

One of the things you can improve - after you focus on proficiency in the programming language itself - is to look at how you name things and the concepts you articulate in your code. The following are a couple of examples, and aren't meant to shame you or anything like that.

In this latest exercise, your core method is named #squareAt:, but your model's terms are chessboard and grains of sand. A chessboard is planar, so addressing its squares really should use cartesian coordinates (x & y, or row and column, or rank and file). Of course, that would make this exercise more complicated, since the exercise really isn't about a chessboard. So, a better name might use the word grains in some way. e.g. #grainsAt: or #numberOfGrainsAt:. [1]

Your previous exercise was to simulate a computer. You had methods like #at: and #at:put: (if I recall correctly), but they were defined on the computer itself. In modelling, the computer comprises a processor, memory, storage, input, and output. In your code, you referred to the memory as RAM, but that's a technology. Random Access Memory. It is true that the memory you modelled is random access, but is that a relevant factor in your program? In my opinion it isn't. I think memory would have made a better name. And that suggests the methods you had on the computer for accessing memory were misnamed, at least, if not misplaced. In that exercise, there was no need for the computer to expose memory access. So, I think expressions like "memory at: anAddress" and "memory at: anAddress put: aValue" would be appropriate. In your exercise, memory was used to hold only integer values, so "anInteger" could have been the name of the argument without being incorrect.

Also, using a stream to iterate through the program was an interesting approach. An alternative, which would better mimic computer design, would entail the use of a program counter (an index) for addressing into memory. That would allow you to write expressions like "self operand: 1" (implemented as e,g, "memory at: pc+anOffset"). Of course, using a stream, you could implement #nextOperand and #storeResult: to encapsulate the stream.

In your class method, you had a good concept with naming a method with a verb (patch) since it was an action concept. I liked that you distinguished an unusual event from normal processing, even though both did the same thing, namely writing to memory. But, a name like #patchRamAt:value: is less sentence-like than e.g. #patchMemoryAt:with:. A keyword such as "value" carries little semantic information. In general, be careful about using vague words. value, process, and many others are worthless for communicating what it does or means. When you name a method argument, you want to convey as much about type and purpose as you reasonably can. "aValue" and "anObject" both tell the reader that it can be any kind of object at all. Usually, that isn't true. Simple methods like setters can simply use type to name the argument, since the keyword identifies the purpose of the argument. More complex methods often cannot get away with just naming by type. If there are multiple arguments of one type, calling them aString1 and aString2 is poor, since you are emphasizing their anonymity. firstNameString and lastNameString could be much better alternatives in a method which does anything complex. e.g. a "setter" method #firstName:lastName: that simply stores both names could easily call the arguments aString and anotherString. But, if you are going to do anything more with them in the method, you want them well distinguished from each other. This is both to help you avoid making errors and to help future readers more easily understand what they see.


There is a lot more I could say, but I don't want to overwhelm you. There are a number of idioms in Smalltalk which you will want to learn and incorporate into your own writing, as doing so will make your code more Smalltalky. :-) But, more importantly, it will make it more readable to other Smalltalk developers when you ask for help or advice. There are families of methods that communicate a lot but with great economy. #at:/#at:put:/#at:ifAbsent: (and in some cases #at:ifPresent:), #detect/#detect:ifNone:, #anySatisfy:/#allSatisfy:/#noneSatisfy, #select:/#collect:/#detect:/#reject:, etc.

One of the greatest idioms involves the #ifAbsent: concept. I don't think there are many (if any!) other languages that have this or make it so easy. Avoid using it to yield a nil, as that's an anti-pattern. Use it to control flow and show what is expected versus what is not expected yet not forbidden. Remember the exercise with the rules for the distance calculations? #ifNone: would let you return that fallback value if no rule applied, and yet have the main code clearly show that a rule is expected and what would be done with the rule that's found. That exercise was quite simple, but when you start dealing with complex things like insurance policies, etc., having code that clearly explains what's intended is crucial. (and, #ifAbsent: and #ifNone: are merely two examples. Create your own variants when you can and when it makes your code better/clearer. I have in many cases written methods with names structured like #doSomethingWith:or:, where the argument to #or: is a Block to simplify when the invoked method cannot do whatever it was expected to do. It means "I want to have you do something, but it's acceptable if conditions don't make that possible because I can deal with it.")




[1] Some great advice I was given about naming things: (1) Explain to a friend what a given artefact does. Or imagine doing so, but that's an advanced skill. Start with a real person who will respond with "Huh?"or the like when you say something that isn't clear. (2) Distill the explanation into a single concise sentence. If you cannot do that, chances are your artefact isn't well factored. It's a good indicator you need to rethink how you are envisioning the decomposition of the solution. (3) Throw away every word which doesn't change the meaning if it is present or not. At this point, you are moving away from a grammatical sentence to a name of a concept, so grammar no longer matters. (4) You should end up with a name which cannot be simplified further, yet is no bigger than necessary.


Enough rambling! I'm glad you're working in Pharo (Smalltalk). I wish you every success with it and with learning programming. Keep these thoughts in mind when you are deciding on names, but do focus on learning the mechanics.


Roelof


Op 4-1-2020 om 20:33 schreef Richard Sargent:
On Sat, Jan 4, 2020 at 10:37 AM Roelof Wobben via Pharo-users <pharo-users@lists.pharo.org> wrote:
Oke,

So I can better not use recursion for this problem if I understand you well,  Richard.

That is oversimplifying. If the purpose of the *training* *exercise* is to learn how to use recursion, then using recursion is a necessary thing. If the purpose of the exercise is to solve a problem, understanding whether there are more efficient approaches to the solution is an essential skill.

This particular problem could have been solved using a recursive implementation, an iterative implementation, or a fundamental reframing of the problem to change it to an O(1) problem. Other problems are no so simply reframed.


One of the most important skills you will ever develop is to understand that a request for a feature may not be accurately describing the problem. A feature request is often a description of a problem from a single perspective. Learning to recognize whether it is one or the other will be crucial to your long-term success as a programmer.


Roelof



Op 4-1-2020 om 19:02 schreef Richard Sargent:
On Sat, Jan 4, 2020 at 9:47 AM Roelof Wobben via Pharo-users <pharo-users@lists.pharo.org> wrote:
Hello,

For a exercism challenge I need to calculate the total grains on a
chessboard.
So I did :

atSquare: anInteger
     self validateInput: anInteger.
     ^ anInteger = 1
         ifTrue: [ 1 ]
         ifFalse: [ 2 * (self atSquare: anInteger - 1) ]


but when I run the tests , the vm seems to be not responsive for some 4
- 5 seconds.

Is there a way I can use this code and take care that the vm stays
responsive.

What do you want the VM to do in addition to calculating that sum while it is calculating that sum?


The best way to keep the VM responsive is to take a page from Gauss' notebook and pay attention to the numbers[1]. Let's consider the first four squares and extrapolate from there.

In binary, the squares hold the following grains: 2r1, 2r10, r2100, and 2r1000. When we add them up, we get 2r1111. If we use Gauss' tricks, we can notice that 2r1111 is equal to 2r10000 - 1. So, the sum of the grains on the first 4 squares is 2^5 - 1. You can easily generalize that pattern, of course. Then your program can calculate the answer quickly.


[1] The story goes that Gauss' teacher was frustrated with his student's abilities and set him a challenge to occupy him for some time: sum the numbers from 1 through 100. Gauss immediately answered 5,050, much to his teacher's chagrin.


Regards,

Roelof






--- End Message ---

Reply via email to