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 >>>>> >>>>> >>>> >>> >> >