Hi,

Time to time I hear people like Richard saying “Dolphin is the dialect most 
beautiful Smalltalk he used” and others praising it in different levels. 
As Pharo “architect” (or whatever I am, but at least I’m sure I have to pay 
attention to the IDE :P), I’m interested to know what elements of Dolphin 
dialect you find “beautiful”, “enjoyable” and productive. 
What it is?

- the MVP?
- integration with Windows? The way this integration is done? (If so… how is it 
done?)
…

I am very interested on knowing this with some detail level. That doesn’t mean 
I will react and do something, but I want to have a better understanding and 
put it in my radar to take inspiration to enhance the Pharo experience :P

Esteban

> On 10 Apr 2019, at 03:09, Richard O'Keefe <rao...@gmail.com> wrote:
> 
> On this laptop I have
>  - Squeak
>  - Pharo
>  - GNU Smalltalk
>  - VisualAge Smalltalk
>  - VisualWorks Smalltalk
>  - Smalltalk/X
> plus some oddballs like susie, amber, and CSOM.
> On another laptop I have
>  - Strongtalk
>  - Dolphin
> And of course I have my own 'astc' Smalltalk-via-C compiler.
> I have to say that Dolphin is easily the most *beautiful* Smalltalk
> environment I've used.  (Yes, I'm the kind of person who has four
> different C compilers on the same machine and uses them all.  You
> don't want to know how many Javascript implementations...)
> 
> The important thing here is that there are at least two aspects to
> "Smalltalk".  There is Smalltalk-the-approach-to-OO and there is
> Smalltalk-the-many-related-but-different-IDEs.  When it comes to
> productivity, the IDE is important.  Really important.  But when
> it comes to thinking about programming and solving tasks like
> exercism ones, it's the approach that matters.  And that approach
> pays off in languages like Javascript and Ruby and Python as well.
> 
> I used to be a University lecturer.  Now I'm a (sub)contractor.
> I used to see a LOT of student code that
>  - had way too many classes
>  - did not use existing well-known classes when it should
>  - failed to encapsulate private state
>  - put responsibilities in the wrong places
> and that was Java code.  What prepared me to see such issues in Java?
> 
> Lots and lots of practice in Smalltalk.
> 
> And lots of reading Smalltalk, and figuring out what made it easy or
> hard to read.
> 
> I do not know how much time you have on your hands,
> but you might find it profitable to look at
> http://rosettacode.org/wiki/Rosetta_Code 
> <http://rosettacode.org/wiki/Rosetta_Code>
> specifically
> http://rosettacode.org/wiki/Category:Smalltalk 
> <http://rosettacode.org/wiki/Category:Smalltalk>
> 
> Look at the bottom of that page for a list of 258
> problems solved in Smalltalk.
> 
> 
> On Tue, 9 Apr 2019 at 03:20, Roelof Wobben <r.wob...@home.nl 
> <mailto:r.wob...@home.nl>> wrote:
> Thanks, 
> 
> for the discusson and lessons. 
> 
> I will think about it and also think if smalltalk is for me. 
> I did the pharo Mooc and still have a lot of problems making the smalltalk 
> way click in my head so I can solve little problems like this.
> 
> Out of coriousy what dialect do you use?
> 
> 
> Op 8-4-2019 om 17:11 schreef Richard O'Keefe:
>> You are expected to use my code fragments for *ideas*,
>> not to incorporate them *literally* in your code.  As
>> I explained, *without seeing the specification*, I have
>> no way to tell whether the specification uses a left-handed
>> or right-handed coordinate system.
>> 
>> For what it's worth, here's a complete program in my
>> Smalltalk dialect.  It doesn't plug into the exercism
>> testing framework because I can do not know what it
>> looks like.  But if it makes the code more complicated
>> that this, it's doing it wrong.
>> 
>> require: 'geometry.st <http://geometry.st/>'  "Point"
>> require: 'print.st <http://print.st/>'     "OutputStream>>print:"
>>     
>> Object subclass: #Robot
>>   instanceVariableNames: 'position direction'
>>   poolDirectionaries:    'FileStream'
>> 
>>   methods for: 'initialising'
>>     pvtPostNew
>>       position  := 0@0.
>>       direction := 1@0.
>> 
>>   methods for: 'accessing'
>>     direction
>>       ^direction copy
>> 
>>     location
>>       ^location copy
>> 
>>     obey: commands
>>       commands do: [:each |
>>         each caseOf: {
>>           [$A] -> [position  := position  + direction].
>>           [$L] -> [direction := direction leftRotated].
>>           [$R] -> [direction := direction rightRotated]
>>         }].
>> 
>>   class methods for: 'main'
>>     start
>>       [StdIn atEnd] whileFalse: [
>>          |robot|
>>          robot := Robot new.
>>          Robot obey: StdIn nextLine.
>>          StdOut print: Robot location; cr].
>> 
>> On Tue, 9 Apr 2019 at 02:58, Roelof Wobben <r.wob...@home.nl 
>> <mailto:r.wob...@home.nl>> wrote:
>> yes,  this is a real  tests from the pharo track on exercism.io 
>> <http://exercism.io/>
>> 
>> I understand what you mean but maybe I overthinking things. 
>> But if we have a robot facing north and the robot turns to the left  , im my 
>> oponion it faces now to the east. 
>> 
>> like this test is saying : 
>> 
>> test04_RotatesTheRobotsDirection90DegreesClockwiseChangesTheDirectionFromEastToSouth
>>     | result |
>>     result := robotSimulatorCalculator
>>         moveDirection: 'east'
>>         position:
>>             (Dictionary new
>>                 add: 'x' -> 0;
>>                 add: 'y' -> 0;
>>                 yourself)
>>         instructions: 'R'.
>>     self
>>         assert: result
>>         equals:
>>             (Dictionary new
>>                 add: 'direction' -> 'south';
>>                 add:
>>                     'position'
>>                         ->
>>                             (Dictionary new
>>                                 add: 'x' -> 0;
>>                                 add: 'y' -> 0;
>>                                 yourself);
>>                 yourself)
>> 
>> 
>> but I cannot come to the same outcome with this code : 
>> 
>> 
>> pointToName: aPoint
>>   ^aPoint x isZero
>>      ifTrue:  [aPoint y > 0 ifTrue: [#north] ifFalse: [#south]]
>>      ifFalse: [aPoint x > 0 ifTrue: [#west ] ifFalse: [#east ]]
>> 
>> 
>> maybe exercism.io <http://exercism.io/> is not a good way to practice and 
>> learn smalltalk but I found not a better one. or smalltalk is not for me. 
>> 
>> Roelof
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> Op 8-4-2019 om 16:44 schreef Richard O'Keefe:
>>> The basic issue here is abstraction.
>>> An instance of "Robot" in your program is not a
>>> physical object.  How could it possibly point North,
>>> South, or Nor-nor-west?  It cannot.
>>> Its location and direction are abstract values
>>> *metaphorically* related to real world notions
>>> like position vectors and velocity vectors.
>>> "North" in this program is not a real thing,
>>> it is an *idea* which could be represented by
>>> 'North', 'north', #North, #north, $N, $n,
>>> 'Raki',  'raki',  #Raki,  #raki,  $R, $r,
>>> 137, (0@ -1), a picture of the star Polaris,
>>> the colour red (the conventional colour for
>>> that end of a compass needle which points north),
>>> a sound recording of a lecture by Alfred North
>>> Whitehead, or anything you please, as long as,
>>> inside the program, it *acts* the way *you* want
>>> "north" to act (which is not necessarily the way
>>> the physical direction North acts, and in fact in
>>> this case it most certainly is not).
>>> 
>>> Locations and movements in a 2D space are, in Smalltalk,
>>> commonly represented by Points.  "Represented by."
>>> 
>>> As for this method:
>>> 
>>> test11_MovesTheRobotForward1SpaceInTheDirectionItIsPointingIncreasesTheYCoordinateOneWhenFacingNorth
>>>     | result |
>>>     result := robotSimulatorCalculator
>>>         moveDirection: 'north'
>>>         position:
>>>             (Dictionary new
>>>                 add: 'x' -> 0;
>>>                 add: 'y' -> 0;
>>>                 yourself)
>>>         instructions: 'A'.
>>>     self
>>>         assert: result
>>>         equals:
>>>             (Dictionary new
>>>                 add: 'direction' -> 'north';
>>>                 add:
>>>                     'position'
>>>                         ->
>>>                             (Dictionary new
>>>                                 add: 'x' -> 0;
>>>                                 add: 'y' -> 1;
>>>                                 yourself);
>>>                 yourself)
>>> 
>>> PLEASE tell me that is not what they are actually using.
>>> Let's start with
>>>   (Dictionary new)
>>>      add: k1 -> v1;
>>>      ...
>>>      add: kn -> vn;
>>>      yourself
>>> Did you know that sending #add: to a dictionary is not
>>> portable?  Storing actual Association objects inside
>>> Dictionaries was originally an encapsulation error and
>>> remains a performance error, so there are Smalltalks
>>> that do not make that mistake.  The *portable* way to
>>> make a Dictionary is
>>>     (Dictionary new)
>>>        at: k1 put: v1;
>>>        ...
>>>        at: kn put: vn;
>>>        yourself.
>>> 
>>> And why in the name of sanity are the keys *strings*
>>> instead of *symbols*?  This is not Smalltalk.  It is
>>> Javascript in drag.
>>> 
>>> Now exercism.io <http://exercism.io/> has a habit of insisting on particular
>>> implementations.  For example, I completed the SML track,
>>> and found that the test code ONLY worked with Poly and
>>> not with any of the three SML implementations I already
>>> had on my machine.  Since you are doing this in Pharo,
>>> I take it that exercism.io <http://exercism.io/> will insist on the 
>>> Smalltalk
>>> track being done in Pharo, and in that case it is
>>> *nauseating* to use a Dictionary when you could use a
>>> Point.  Old-fashioned Smalltalk style would have been
>>> to return something like
>>>    #(<direction> <x> <y>)
>>> e.g. #(north 1 0), and I still prefer that.
>>> 
>>> In fact *good* Smalltalk style for something like this
>>> would be
>>> test11_MovesTheRobotForward1SpaceInTheDirectionItIsPointingIncreasesTheYCoordinateOneWhenFacingNorth
>>>   robotSimulatorCalculator
>>>     moveTo: 0@0;
>>>     head: #north;
>>>     obey: 'A'.
>>>   self assert: robotSimulatorCalculator heading equals: #north.
>>>   self assert: robotSimulatorCalculator location equals: 0@1.
>>> 
>>> -- We're starting to get the idea that identifiers like
>>> robotSimulatorCalculator are not a very good idea when
>>> simulatedRobot would do the job as well or better.
>>> 
>>> (This is also pointing us towards Betrand Meyer's
>>> Command/Query Separation principle, but we shan't
>>> go there today.)
>>> 
>>> This is important feedback to give to the exercism.io <http://exercism.io/>
>>> people.  The test code should use a SMALLTALK interface,
>>> not a warmed-over JAVASCRIPT interface.
>>> 
>>> Now, how do we map between direction *names* and
>>> direction *points*?  Well, we have to start by
>>> laying down clearly what we *mean* by the directions.
>>> 
>>> To move North one step is to add 1 to y and 0 to x.
>>> (We know that from the appalling test case above.)
>>> To move South one step is to add -1 to y and 0 to x.
>>> (South is the opposite of North.)
>>> To move East one step, oh we have a problem.
>>> THIS NEEDS SPELLING OUT.  And one of the things the
>>> exercism.io <http://exercism.io/> exercises are HORRIBLY BAD AT is 
>>> specifying
>>> the problem.  Nearly every single exercise I have tried,
>>> I have been unable to tell what the problem is without
>>> examining the test cases, and that is not the way
>>> exercises are supposed to work.  (Yeah, that's why I'm
>>> screaming about it.  I've taught a class using exercises
>>> like this that were not of my writing and vague specifications
>>> really upset the students.  People who had taken the class
>>> under someone else several years before were still angry
>>> about it.)
>>> 
>>> The geometric classes in Smalltalk were written to support
>>> graphic user interfaces.  And in user interfaces, the y
>>> coordinate increases DOWN.  So if we take the compass rose
>>> and rotate it so that North is DOWN, it follows that
>>> West is right and East is left.  So
>>> 
>>> To move East one step is to add -1 to x and 0 to y.
>>> To move West one step is to add 1 to x and 0 to y.
>>> 
>>> The chances are excellent that the problem specification
>>> is inconsistent with this.  Sigh.  Let's proceed, though.
>>> 
>>> North  0@1
>>> South  0@ -1
>>> East   -1@0
>>> West   1@0
>>> 
>>> 
>>> pointToName: aPoint
>>>   ^aPoint x isZero
>>>      ifTrue:  [aPoint y > 0 ifTrue: [#north] ifFalse: [#south]]
>>>      ifFalse: [aPoint x > 0 ifTrue: [#west ] ifFalse: [#east ]]
>>> 
>>> nameToPoint: aSymbol
>>>   aSymbol = #north ifTrue: [^0 @ 1].
>>>   aSymbol = #south ifTrue: [^0 @ -1].
>>>   aSymbol = #west  ifTrue: [^1 @ 0].
>>>   aSymbol = #east  ifTrue: [^-1 @ 0].
>>>   aSymbol error: 'not a compass direction in lower case'.
>>> 
>>> Another problem I had with exercism was a "Space-Age"
>>> exercise where the README.md capitalised the planet names
>>> but test_Space-Age.<whatever> insisted on lower case.
>>> That might well happen here.
>>> 
>>> Just for grins,
>>> Dictionary>>
>>> asPoint
>>>   ^(self at: 'x') @ (self at: 'y')
>>> 
>>> Point>>
>>> asDictionary
>>>   ^(Dictionary new)
>>>      at: 'x' put: self x;
>>>      at: 'y' put: self y;
>>>      yourself
>>> 
>>> 
>>> 
>>> 
>>> On Mon, 8 Apr 2019 at 22:15, Roelof Wobben <r.wob...@home.nl 
>>> <mailto:r.wob...@home.nl>> wrote:
>>> Richard thanks. 
>>> 
>>> One thing I do not see direct. 
>>> 
>>> you said : 
>>> 
>>> 
>>> A direction could be represented by a pair of integers
>>> dx, dy such that |dx|+|dy| = 1.  It could also be
>>> represented by a Point with integer components.
>>> 
>>> for me a direction is the direction the robot is facing so something like 
>>> north or east. 
>>> 
>>> the challenge also wants a output like this : 
>>> 
>>> test11_MovesTheRobotForward1SpaceInTheDirectionItIsPointingIncreasesTheYCoordinateOneWhenFacingNorth
>>>     | result |
>>>     result := robotSimulatorCalculator
>>>         moveDirection: 'north'
>>>         position:
>>>             (Dictionary new
>>>                 add: 'x' -> 0;
>>>                 add: 'y' -> 0;
>>>                 yourself)
>>>         instructions: 'A'.
>>>     self
>>>         assert: result
>>>         equals:
>>>             (Dictionary new
>>>                 add: 'direction' -> 'north';
>>>                 add:
>>>                     'position'
>>>                         ->
>>>                             (Dictionary new
>>>                                 add: 'x' -> 0;
>>>                                 add: 'y' -> 1;
>>>                                 yourself);
>>>                 yourself)
>>> 
>>> so how do I "convert" the point you are using to the text. 
>>> 
>>> Or do I misunderstood you somewhere wrong. 
>>> 
>>> Roelof
>>> 
>>> 
>>> 
>>> 
>>> Op 8-4-2019 om 10:57 schreef Richard O'Keefe:
>>>> One thing I have often seen and lamented is students
>>>> writing excessively complicated code with way too many
>>>> classes.  There is a huge difference between
>>>>   "A Robot knows its position and direction."
>>>> and
>>>>   "A Robot has-a Position and has-a Direction."
>>>> The first is the important one.  The second is
>>>> an over-commitment to too many classses.  For a
>>>> problem like this, you really really do not want
>>>> a Direction class, and you certainly have no use
>>>> for double dispatch.
>>>> 
>>>> A position can be represented by a pair of integers
>>>> x, y.  It could also be represented by a Point with
>>>> integer components.
>>>> 
>>>> A direction could be represented by a pair of integers
>>>> dx, dy such that |dx|+|dy| = 1.  It could also be
>>>> represented by a Point with integer components.
>>>> 
>>>> For movement, you need to be able to add the direction
>>>> to the location, which could be simply
>>>> x := x + dx.  y := y + dy.
>>>> or it could be
>>>> position := position + direction.
>>>> For turning, you need to be able to rotate a direction
>>>> vector by ninety degrees.  Now it so happens that
>>>> Point has methods #leftRotated and #rightRotated.
>>>> 
>>>> So we can do the following:
>>>>    a Robot has position (a Point) and direction (aPoint)
>>>>    position := 0 @ 0.
>>>>    direction := 0 @ 1.
>>>> To move forward without turning:
>>>>    position := position + direction.
>>>> To turn left without moving:
>>>>    direction := direction leftRotated.
>>>> To turn right without moving:
>>>>    direction := direction rightRotated.
>>>> To obey a sequence of characters, commands:
>>>>    commands do: [:each |
>>>>       each caseOf: {
>>>>          [$A] -> [--move forward--].
>>>>          [$L] -> [--turn left--].
>>>>          [$R] -> [--turn right--]
>>>>       }].
>>>> 
>>>> 
>>>> One of the key ideas in extreme programming is
>>>> "You Ain't Gonna Need It", abbreviated to YAGNI!
>>>> The idea is *DON'T* generalise beyond your immediate
>>>> needs.  In this case, for example, the likelihood of
>>>> *this* program needing to deal with more general
>>>> kinds of movement is ZERO.  And the only reason for
>>>> using Point here instead of just using a few simple
>>>> assignment statements is that Point already exists,
>>>> so costs nothing to write, and as a familiar class,
>>>> code using it should be easy to read.
>>>> 
>>>> If someone challenges you to do something counter-productive,
>>>> refuse the challenge.
>>>> 
>>>> On Mon, 8 Apr 2019 at 17:21, Roelof Wobben <r.wob...@home.nl 
>>>> <mailto:r.wob...@home.nl>> wrote:
>>>> I can try to explain what I trying to solve. 
>>>> 
>>>> I have a Robot which can turn left,  turn right or moveForward. 
>>>> 
>>>> now I have a string like 'LAR'
>>>> 
>>>> that means the robot needs to turn left (l) , move forward one place (A) 
>>>> and turn left. 
>>>> and I have to keep track to which direction the robot is facing and on 
>>>> which coordinate it stands. 
>>>> 
>>>> so to summarize with the above string 
>>>> 
>>>> lets say the robot is facing north on coordinate (0,0) 
>>>> then it has to turn left , so its facing east and still on coordinate 
>>>> (0,0) 
>>>> then it has to move forward, so its still  facing east but are on 
>>>> coordinate(0,1) 
>>>> then it has to turn right, so its facing north and on coordinate (0,1) 
>>>> 
>>>> and TimMacKinnon has challenged me to do this with double dispatch. 
>>>> 
>>>> So I think now I need a object Direction, a sub object North and a sub - 
>>>> sub object TurnLeft, turnRight and moveForward. 
>>>> 
>>>> So I can use double dispath first the direction North, East, South, West 
>>>> and then use double dispatch to find the right move. 
>>>> 
>>>> Roelof
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> Op 8-4-2019 om 06:50 schreef Richard O'Keefe:
>>>>> It would really REALLY **REALLY** help if we knew what
>>>>> the heck you were trying to do.  There is an excellent
>>>>> chance that it is MUCH simpler than you think.  If you
>>>>> cannot show us the Smalltalk version of the problem,
>>>>> can you show us the version for some other language?
>>>>> 
>>>>> 
>>>>> On Sun, 7 Apr 2019 at 20:15, Roelof Wobben <r.wob...@home.nl 
>>>>> <mailto:r.wob...@home.nl>> wrote:
>>>>> Op 6-4-2019 om 15:15 schreef K K Subbu:
>>>>> > On 06/04/19 4:49 PM, Roelof Wobben wrote:
>>>>> >> Hello,
>>>>> >>
>>>>> >> I just learned double dispatch.
>>>>> >> And now for the Robot challenge of exercism Tim has pointed me to 
>>>>> >> this 
>>>>> >> article(https://blog.metaobject.com/2019/04/accessors-have-message-obsession.html
>>>>> >>  
>>>>> >> <https://blog.metaobject.com/2019/04/accessors-have-message-obsession.html>)
>>>>> >>  
>>>>> >>
>>>>> >> but I fail to see how the move method looks like in that article.
>>>>> >> I had a conversation with Tim in the exercism channel and the way he 
>>>>> >> explains it, it looks like double dispatch for me.
>>>>> >>
>>>>> >> Am I on the right track or do I oversee something here.
>>>>> > unary methods like moveRight perform specific ops and are not 
>>>>> > parametric, so only a single dispatch, depending on the receiver, is 
>>>>> > needed.
>>>>> >
>>>>> > If you change it to move: aDistanceOrAngle, then performing requests 
>>>>> > like "move: 3 cms" or "move: 30 degrees" will depend not only on the 
>>>>> > receiver but also on the class of the argument. This would need double 
>>>>> > dispatch (aka multiple polymorphism). The first dispatch would be 
>>>>> > based on the receiver and the receiver's method would then dispatch it 
>>>>> > based on the class of the argument (i.e. Distance>>move or Angle>>move )
>>>>> >
>>>>> > HTH .. Subbu
>>>>> >
>>>>> >
>>>>> 
>>>>> 
>>>>> hmm, still stuck
>>>>> 
>>>>> I have now a class Direction with as instance variables north, south, 
>>>>> east, west
>>>>> and made the accessors.
>>>>> 
>>>>> then I thought I need a initialize like this :
>>>>> 
>>>>> initialize
>>>>>     north = Direction( 0, -1).
>>>>>     east  = Direction( 1,  0).
>>>>>     south = Direction( 0,  1).
>>>>>     west  = Direction(-1,  0).
>>>>> 
>>>>> but the Direction (0,-1)  is a problem . the compiler does not like the 
>>>>> (0,-1) part
>>>>> 
>>>>> to give you the big picture. I have a Robot which can turnRight , 
>>>>> turnLeft and moveForward and I try to understand how the page would work 
>>>>> in my case.
>>>>> 
>>>>> So I have a object Direction as described above and a Object MoveForward 
>>>>> which is a subobject of Direction.
>>>>> MoveForward has only 1 method :
>>>>> 
>>>>> IsMove
>>>>>     ^  'A'
>>>>> 
>>>>> Roelof
>>>>> 
>>>>> 
>>>> 
>>> 
>> 
> 

Reply via email to