Good day. I bring to your attention the second article from the cycle on Low Level Smalltalk (LLST). Who does not know what is at stake, I recommend reading the previous review article , which tells about what llst is and why it was created.
Programming languages ​​are different. Some have a rather low entry threshold. Others scare off the potential adept at further approaches, terrifying him by the bizarre and alien syntax, excessive verbosity of the narrative, or complexity of the concepts. There are languages ​​that require the programmer to literally turn the brain inside out in order to learn how to think as it is necessary for successful programming in such a language. Some languages ​​only look simple, but really demanding the candidate to have a strong baggage of knowledge from the field of mathematics, lambda calculus and category theory ...name subclassOf instanceOf Object MetaObject nil Class MetaClass Object MetaObject Class Class MetaClass Class MetaObject
It tells us that:
Like real living creatures, objects are born and die. They live in the image - the memory area of ​​the computer in which the objects of the virtual machine are stored. This image can be saved to disk and loaded later. Having loaded from a disk, we will receive exactly the same representation that was at the time of recording. This applies to all objects without exception, from numbers and strings to user interface elements. To take any special measures to preserve the state of the system is not required - it provides an image. In this sense, the user interfaces of programs written in the Smalltalk language, I think, would have liked Jeff Raskin in terms of his persistence.
->2 + 3 5 2 and sent him a message + with parameter 3 . The result of the message is the amount object that was returned to the outside and displayed by the shell. This is an example of a binary message in which two objects are involved.2 which class corresponds to it. This is done by sending a class message: ->2 class SmallInt Fine. Two was an object of class SmallInt .SmallInt ? Let's ask: ->SmallInt listMethods * + - / < = asInteger asSmallInt bitAnd: bitOr: bitShift: hash quo: rem: truncSmallInt SmallInt listMethods message to the listMethods class. This was possible because the SmallInt class SmallInt also an object to which messages can also be sent. And all thanks to the above-described "psychedelic" tricks with inheritance. It is important to note that sending messages to classes and objects is implemented in the same way, that is, it is the same mechanism (without crutches). Classes and objects really coexist alongside and in no way interfere with each other.True and False respectively. That is, there is only one true object in the whole image. All places where it is supposed to return or store a Boolean value are used, either explicitly or implicitly.null pointer and null from the Java world, nil is a complete object. -> 1 isNil false -> nil isNil true -> nil class Undefined ->'hello' = 'hello' true ->'hello' == 'hello' false -> 'hello' + 'World' = 'helloWorld' true -> 'hello' + 'World' == 'helloWorld' false = used to formally compare the values ​​of two strings, whereas the operator == checks objects for identity . The == operator returns true only if the object and the passed parameter are the same object. In the case described above, this is not the case, since two instances of the String class, which are created one after the other but are not the same object, are checked for identity. -> #helloWorld = #helloWorld true -> #helloWorld == #helloWorld true -> ('hello' + 'World') asSymbol == #helloWorld true 
-> Array parent Collection -> Object parent nil -> Array parent isNil false -> Object parent isNil true -> 12 12 -> 12 class SmallInt -> 12 class methods Dictionary (* -> Method, + -> Method, - -> Method, / -> Method, < -> Method, = -> Method, asInteger -> Method, asSmallInt -> Method, bitAnd: -> Method, bitOr: -> Method, bitShift: -> Method, hash -> Method, quo: -> Method, rem: -> Method, truncSmallInt -> Method) -> 12 class methods keys OrderedArray (* + - / < = asInteger asSmallInt bitAnd: bitOr: bitShift: hash quo: rem: truncSmallInt) -> 12 class methods keys size 15 
-> SmallInt methods keys at: 7 asInteger #at: message to the keys object with parameter 7. The indices in Smalltalk are counted from 1, so the first element has the index 1 and the last element is the size of the container. -> (Array new: 5) at: 1 put: 42 Array (42 nil nil nil nil) #new: message to the Array object with a parameter of 5, meaning the number of elements. Then we placed 42 in the newly created array at index 1. The resulting array was displayed on the screen. Notice that the remaining 4 cells are filled with nil values.at: 1 put: 42 is one parameterized message #at:put: and not two, as you might think. In the style of keys->atPut(1, 42) , but in such a record the correspondence of the passed parameters and their purpose is lost.Rectangle , representing a rectangle on some plane. In C ++ code, we encountered the following lines: Rectangle* rect1 = new Rectangle(200, 100); Rectangle* rect2 = new Rectangle(200, 100, 115, 120, 45); Rectangle class constructor. The second option looks even less readable. Of course, a good programmer would add comments to the code, and change the function's prototype so that it accepts “talking” types, like Point , but this is not the case now. rect1 <- Rectangle width: 200 height: 100. rect2 <- Rectangle new width: 200; height: 100; positionX: 115; positionY: 120; rotationDegrees: 45. #width:height: message to the Rectangle class, which created an instance of itself and set the value of the corresponding fields from its parameters. In the second case, we created the instance in the usual way, sending the message #new , and then cascaded the messages to set the values ​​one by one. Notice how visual the code becomes. We do not even need to add comments so that the reader will understand what is happening. " " rect1 <- Rectangle width: 200 height: 100. rect2 <- Rectangle new. " " rect2 width: 200. rect2 height: 100. rect2 positionX: 115. rect2 positionY: 120. rect2 rotationDegrees: 45. #keysAsArray: keysAsArray | index result | result <- Array new: keys size. 1 to: keys size do: [ :index | result at: index put: (keys at: index) ]. ^ result keys field. Here the message is transmitted to the unit #to:do: with two parameters. The first is the keys size , and the second is a piece of code that needs to be executed (the expression in square brackets). In Smalltalk, such pieces of code are called blocks . Of course, they are objects and can be stored in a variable. Here, the variable for the block is not created, but it is transmitted immediately at the place of use. In order to execute a block, it needs to send a #value message, or #value: if it takes a parameter. This is what the SmallInt class will do in the implementation of its #to:do: method.size once, each time it will be given an iteration number, which will be interpreted as an index for selecting values ​​from keys and adding them to result .
METHOD Collection sort ^ self sort: [ :x :y | x < y ] ! METHOD Collection sort: criteria | left right mediane | (self isEmpty) ifTrue: [^self]. mediane <- self popFirst. left <- List new. right <- List new. self do: [ :x | (criteria value: x value: mediane) ifTrue: [ left add: x ] ifFalse: [ right add: x ] ]. left <- left sort: criteria. right <- right sort: criteria. right add: mediane. ^ left appendList: right ! Collection class represents some abstract collection of elements. Collection does not know how to store data, it only provides general algorithms for operating with them. One of these algorithms is sorting. METHOD Collection sort ^ self sort: [ :x :y | x < y ] ! x someField < y someField .[ :x :y | describes the formal parameters of a block, the symbol ^ is the equivalent of return from the world of C. The self keyword is used to send a message to itself, super - to send to its ancestor. sort: criteria | left right mediane | (self isEmpty) ifTrue: [^self]. mediane <- self popFirst. criteria . Next are local variables, separated from the rest of the text by vertical bars. The style is allowed to write them in the same line, although you can transfer to the following: sort: criteria | left right mediane | (self isEmpty) ifTrue: [^self]. mediane <- self popFirst. (self isEmpty) ifTrue: [^self] essentially no different from any other similar one. Parentheses are not required here and are inserted exclusively for decorative purposes. First, we send the #isEmpty message to #isEmpty , and then the result of this action (one of the instances of the Boolean class) is to send the #ifTrue: message with the block parameter, which must be executed in case of truth.#popFirst message. I intentionally used the verb “bind” instead of “assign” in order to emphasize that no copying takes place here. All variables store only object references, not values. Collections also store links, so we don’t have to worry about the problems of copying large amounts of data. To explicitly create a copy of an object, separate messages are provided for full or shallow (non-recursive) copying. left <- List new. right <- List new. self do: [ :x | (criteria value: x value: mediane) ifTrue: [ left add: x ] ifFalse: [ right add: x ] ]. #do: , for each element ( x ) we call the comparison block with the median and decompose the elements into lists, based on the result of the comparison.#do: uses the variable mediane , whereas the block with #ifTrue: refers to both the variable x and left , declared even higher in the hierarchy. This is made possible by the fact that the blocks in Smalltalk are closures and are tied to the lexical context of their use. left <- left sort: criteria. right <- right sort: criteria. right add: mediane. ^ left appendList: right " " -> #(13 0 -6 221 64 7 -273 42 1024) sort Array (-273 -6 0 7 13 42 64 221 1024) " " -> #(13 0 -6 221 64 7 -273 42 1024) sort: [ :x :y | x > y ] Array (1024 221 64 42 13 7 0 -6 -273) " " -> #(13 0 -6 221 64 7 -273 42 1024) sort: [ :x :y | x asString < y asString ] Array (-273 -6 0 1024 13 221 42 64 7) " " -> #(13 0 -6 221 64 7 -273 42 1024) sort: [ :x :y | x asString size < y asString size ] Array (7 0 13 -6 42 64 221 1024 -273) " " ->' , !' words List ( , !) " " ->' , !' words sort: [ :x :y | x size < y size ] List ( ! , )
List, Collection , . , ( Link) . METHOD List add: anElement elements <- Link value: anElement next: elements. ^ anElement ! METHOD List addLast: anElement elements isNil ifTrue: [ self add: anElement ] ifFalse: [ elements addLast: anElement ]. ^ anElement ! METHOD Link addLast: anElement next notNil ifTrue: [ ^ next addLast: anElement ] ifFalse: [ next <- Link value: anElement ] ! : #add:, ++ #addLast: . METHOD List appendList: aList | element | (elements isNil) ifTrue: [ elements <- aList firstLink. ^self ]. element <- elements. [element next isNil] whileFalse: [element <- element next]. element next: aList firstLink. ^self ! Source: https://habr.com/ru/post/164769/
All Articles