it seems very difficult to get a proper source of information about Squeak.
I have a few basic questions about it:
does '=' check for equality by refrence?
does '==' check for equality of values?
collection - linked list - if I do something like:
list := LinkedList new.
element := list first.
does it mean that element and 'list first' are both references to the same place in memory (the first place in thr linked list?)
why do I need to override the operator = for linked list? and how do I do it?
By default == is equality by reference. In Object = is defined as
= anObject
^ self == anObject
But other classes usually override it. For example in Character = is defined as
= aCharacter
^ self == aCharacter or:[
aCharacter isCharacter and: [
self asciiValue = aCharacter asciiValue]]
You can get all implementors of = by executing #= implementors.
In your case element and list first are referencing the same object. This is because first is implemented as
first
^ self at: 1
And at returns the element on position 1. But if first would be implemented as
first
^ (self at: 1) copy
then it would return a copy of an element (or if you use element := list first copy) and then they will return false when compared with ==, but if = is implemented in a smart way it should return true in most cases.
Also be sure that you want to use LinkedList because in pharo which is a fork of squeak it is used mostly for process scheduling and I think that there was a discussion that LinkedList is more of a utility collection. The most used collection with random access features is OrderedCollection
Related
Have noticed a strange behavior when comparing a result of CharSequence.reversed() method.
val s = "a"
val subSequence = s.subSequence(0, 1)
println("$subSequence == ${subSequence.reversed()}: ${subSequence == subSequence.reversed()}")
Results in:
a == a: false
Moreover subSequence.reversed() == subSequence.reversed() is also false.
Can someone explain this unexpected behavior?
CharSequence is actually an interface which classes like String and StringBuilder implements. The reason why the result of subSequence(0, 1) isn't equal to subSequence.reversed() is because of the actual types they return.
The subSequence(0, 1) call returns a String, while reversed() returns a StringBuilder. The equals-method will therefore return false because the types are different.
It will work as you would expect if you call toString() on the result of reversed():
val reversed = subSequence.reversed().toString()
println("$subSequence == $reversed: ${subSequence == reversed}") // Prints a == a: true
Converting back to a String fixes the issue because then the correct (expected) eqauals is applied:
val s = "a"
val subSequence = s.subSequence(0, 1)
println(subSequence.reversed() == subSequence.reversed()) //false
println(subSequence.reversed().toString() == subSequence.reversed().toString()) //true
Note that you are probably confused by what is shown by toString and how equality (equals) behaves.
What you see is the output of toString(). Any type can decide how it's object's string representation might look like by overriding that method. This however has no influence on how objects of that type are compared against each other. That is where equals (in some cases also compare) comes in.
Others wrote something about that the underlying type of the objects to compare isn't equal (one side StringBuilder and the other String). The actual problem however is that of the equals-method. It could be (usually it isn't done so for various reasons), that equals for a certain type supports equality of different types of objects (such a behaviour (would) should be mentioned in the interface at least). If nothing is specified one can assume that the default equality from Object.equals holds.
In this case however the CharSequence-javadoc already states the following about equality (emphasis mine):
This interface does not refine the general contracts of the equals and hashCode methods. The result of testing two objects that implement CharSequence for equality is therefore, in general, undefined. Each object may be implemented by a different class, and thereis no guarantee that each class will be capable of testing its instancesfor equality with those of the other. It is therefore inappropriate to usearbitrary CharSequence instances as elements in a set or as keys ina map.
So summarizing: forget that you got a String or StringBuilder from subSequence and reversed. The method contract specifies CharSequence and as such you must handle it as CharSequence. There is no guarantee that those functions will still return a String or StringBuilder in future.
Is there a clang flag to warn when you use e.g. an object in an if statement instead of a boolean expression?
I googled for this but couldn't find anything. This would help prevent mistakes like this, especially when using editor generated Core Data classes:
NSNumber *n = #(YES)
if (n) { // should be n.boolValue instead of n
...
}
I found an "Implicit Boolean Conversions" option in Xcode but that doesn't seem to be it (I double checked).
No, there is no short-hander for this and there cannot be.
A.
if comes from classical C. In classical C there is no boolean type. (They extended C in 99, but did not touch if.) Basically everything !=0 is true, everything ==0 is false.
B.
n is no object. It is an object reference. You need expressions like you have to check, whether the object reference points to nil. With your suggestion there would be no difference between "no object" and "an object containing NO".
I am interested in creating my own Stream subclass and I'm wondering what methods I should override (deploying on pharo and Gemstone). I have a collection with various types of things in it and I want to be able to stream over a subset of it, containing elements of a class. I don't want to copy the collection or use a collect: block because the collection may be large. My first use case is something like this:
stream := self mailBox streamOf: QTurnMessage.
stream size > 1
ifTrue: [ ^ stream at: 2 ]
ifFalse: [ ^ nil ]
Any pointers on what methods to override?
In Smalltalk, when we say Stream we refer to objects that respond to a basic protocol given by some few methods such as #next, #nextPut:, #contents, etc. So, before going into further detail I would say that stream at: 2, as you put in your example, is not a very appropriate expression. More appropriate expressions for a Stream would be
stream position: 2.
^stream next
So, the first thing you have to consider is whether you are looking for a Stream or a Collection. This basic decision depends on the behavior your objects will have to implement.
Use a subclass of Stream in case you decide that you want to enumerate the elements using #next, i.e. mostly in sequential order. However, if you want to access your elements via at: index, model your objects with a subclass of SequenceableCollection.
In case you choose streams, you will have to decide whether you will be only accessing them for reading operations or will also want to modify their contents. Your description of the problem seems to indicate that you will just read them. Therefore the basic protocol you have to implement first is
#next "retrieve the object at the following position and advance the position"
#atEnd "answer with true if there are no more objects left"
#position "answer the current position of the implicit index"
#position: "change the implicit index to a new value"
Also, if your streams will be read only, make your class a subclass of ReadStream.
There are some few other additional messages you will have to implement if you want to inherit fancier methods. An example would be #next: which retrives a subcollection of several consecutive elements (its size being given by the argument.)
If you instead think that it would be better to model your objects as collections, then the basic protocol you will have to implement consists of the following three methods
#at: index "retrieve the element at the given index"
#size "retrieve the total number of elements"
#do: aBlock "evaluate aBlock for every element of the receiver"
(I don't think your collections have to support at:put:.)
Very recently we had the same problem you are describing and decided to model our objects as collections (rather than streams.) However, regardless of which approach you will finally follow I think that you should try both and see which one is better. Nobody will give you better advice than your Smalltalk system.
Incidentally, note also that if you have a (sequenceable) Collection, you will get a Stream for free: just send #readStream to your collection!
I needed to override next and atEnd. My Stream subclass takes a block and a collection, and iterates over all elements of the collection for which block evaluates to true.
Example usage:
e := Array with: 1 with: 2 with: 3.
a := QStream collection: e block: [ :i| i odd ].
a next. "1"
a next. "3"
Here is the core of it:
Stream subclass: #QStream
instanceVariableNames: 'collection block index found'
classVariableNames: ''
poolDictionaries: ''
category: 'QDialog-Core'
initialize
super initialize.
index := 1.
self search.
next
| result |
result := found.
self search.
^result.
search
[ index < collection size and: [ (block value: (collection at: index)) not ] ]
whileTrue: [ index := index + 1 ].
self atEnd
ifTrue: [ ^ found := nil ]
ifFalse: [
found := collection at: index.
index := index + 1 ]
atEnd
^ index > collection size
According to the Go reference there are two ways of declaring a variable
Variable_declarations (in the format of var count = 0 or var count int)
and
Short_variable_declarations (in the format of count := 0)
I found it's very confusing to decide which one to use.
The differences I know (till now) are that:
I can only using a count := 0 format when in the scope of a function.
count := 0 can be redeclared in a multi-variable short declaration.
But they do behave the same as far as I know. And in the reference it also says:
It (the count:=0way) is shorthand for a regular variable declaration with initializer expressions but no types
My confusions are:
If one is just the shorthand way of the other, why do they behave differently?
In what concern does the author of Go make two ways of declaring a variable (why are they not merged into one way)? Just to confuse us?
Is there any other aspect that I should keep my eyes open on when using them, in case I fall into a pit?
The Variable declarations make it clear that variables are declared. The var keyword is required, it is short and expresses what is done (at the file level everything excluding comments has to start with a keyword, e.g. package, import, const, type, var, func). Like any other block, variable declarations can be grouped like this:
var (
count int
sum float64
)
You can't do that with Short variable declarations. Also you can use Variable declarations without specifying the initial value in which case each variable will have the zero value of its type. The Short variable declaration does not allow this, you have to specify the initial value.
One of Go's guiding design principle was to make the syntax clean. Many statements require or it is handy that they allow declaring local variables which will be only available in the body of the statement such as for, if, switch etc. To make the syntax cleaner and shorter, Short variable declaration is justified in these cases and it is unambigous what they do.
for idx, value := range array {
// Do something with index and value
}
if num := runtime.NumCPU(); num > 1 {
fmt.Println("Multicore CPU, cores:", num)
}
Another difference: Redeclaration
Quoting from the Language specification:
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
This one is also handy. Suppose you want to do proper error handling, you can reuse an err variable because most likely you only need it to check if there were any errors during the last function call:
var name = "myfile.txt"
fi, err := os.Stat(name) // fi and err both first declared
if err != nil {
log.Fatal(err)
}
fmt.Println(name, fi.Size(), "bytes")
data, err := ioutil.ReadFile(name) // data is new but err already exists
// so just a new value is assigned to err
if err != nil {
log.Fatal(err)
}
// Do something with data
I'm new to smalltalk and I'm impressed with the fact that there are only just 6 keywords in the language (self, super, true, false, nil & thisContext), and how pure it is in having almost everything as message passing, eg. looping using whileTrue, if/else using ifTrue, etc ... which are way different from what I'm used to in other languages.
Yet, there are cases where I just cannot make sense of how message passing really fit in, these include:
the assignment operator :=
the cascading operator ;
the period operator .
the way to create a set #( ... )
These aren't message passing, right?
As you've discovered, there's still some actual Smalltalk syntax. Block construction, literal strings/symbols/comments, local variable declaration (|...|), and returning (^) are a few things you didn't mention which are also syntax.
Some extensions (e.g. #(...), which typically creates an Array, not a set) are certainly expressible otherwise, for example #(1 2 3) is equivalent to Array with: 1 with: 2 with: 3; they're just there to make the code easier to read and write.
One thing that might help clarify : self, super, true, false, nil & thisContext are data primitives, rather than keywords.
They are the only 6 data primitives. These 6 are also known as pseudo-variables. Absolutely every other thing is an instance of Class Object or its subclasses.
There are very few pre-defined keywords in Smalltalk. They can be written in a very condensed form.
A famous example is Smalltalk Syntax on a Postcard (link)
exampleWithNumber: x
| y |
true & false not & (nil isNil) ifFalse: [self halt].
y := self size + super size.
#($a #a "a" 1 1.0)
do: [ :each |
Transcript show: (each class name);
show: ' '].
^x < y
Here's the comment for this method - which is larger than the method itself:
"A method that illustrates every part of Smalltalk method syntax
except primitives. It has unary, binary, and keyboard messages,
declares arguments and temporaries, accesses a global variable
(but not an instance variable), uses literals (array, character,
symbol, string, integer, float), uses the pseudo variables
true, false, nil, self, and super, and has sequence, assignment,
return and cascade. It has both zero argument and one argument blocks."