I have a class called ThreadTesting, and within that class I have an instance variable called 'col' (which is an array). My goal is to populate it through a thread, wait for the thread to finish and then output its contents.
ThreadTesting new callThread.
ThreadTesting class:
initialize
super initialize.
semaphore := Semaphore new.
col := Array new: 10.
callThread method:
callThread
self runThread.
semaphore wait.
Transcript show: 'Thread finished';cr.
col do:
[ :each | Transcript show: each ; cr].
runThread method:
runThread
|pr|
pr := [
[ 1 to: 10 do: [ :i |
col at: i put: i
]].
semaphore signal.
] fork.
Output:
It is all set to nil and I don't know why.
Your problem is simply that you're defining a block that will populate your array, but you're not actually doing anything with it, i.e. it never gets called.
I think what you want is to simply remove the extra [ and ] around that block, then it will actually be a piece of code that gets executed. You also don't need to assign your outer block to a temporary variable (and if you do want to keep it, please honour the spirit of Smalltalk and call it process, not pr - AAAAB... abbreviations are almost always bad. Similarly, I'd never call an Array something like col - that's misleading and abbreviated...). So your runThread method should look like this:
runThread
[
1 to: 10 do: [ :eachIndex |
numbers at: eachIndex put: eachIndex
].
semaphore signal
] fork
So you're now declaring a block that populates your array and signals your semaphore, and forking it as a new process, whereas previously you were declaring an outer block that declared an inner block (but never did anything with it, it just sat there) and signalled your semaphore, and then forked it as a new process.
Related
I am new to the programming language Smalltalk and I can't seem to figure out how to call a method with arguments. I've been playing around with some code and created some methods, like for example (in GNU Smalltalk):
bin: n num: k [
| i |
i := 1.
1 to:k do:[:j|
i := i * 2.
].
^i
]
I would now like to call this function and actually get an answer, like for example: bin: 4 num: 2 (don't know how to do this). How can I do that? Is it even right to write 'bin: n num: k' when creating a method like I have done?
Thanks in advance!
First, you need a receiver object, on which you want to invoke that method. You did not indicate in which class you have created your method, so I will just assume that you called it MyClass.
| myObject |
myObject := MyClass new.
Then you can send that message to (invoke that method on) myObject like this:
myObject bin: 4 num: 2
So you just write the message send (which will invoke the method) after the receiver.
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
Transcript show: 'Derp'.
printSomething: 'Derpy'.
"The method above produced this error:"
"prog.st:3: expected expression"
printSomething: what
10 timesRepeat: [
Transcript show:what.
Transcript cr.
].
I'm trying to teach myself Smalltalk now, and I still haven't figured out how to call a function that I've written. I tried to call the function printSomething with the parameter 'Derpy' using the statement printSomething: 'Derpy'., but instead of calling the function, it produced the following error: prog.st:3: expected expression.
What am I doing wrong here, and what is the correct way to call functions with parameters in Smalltalk? None of the tutorials that I've read have answered my question so far, and I'm still a bit confused.
I suspect that your errors are twofold:
Object class: #Example [
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Smalltalk Examples'
]
Example class extend [
printSomething: what
10 timesRepeat: [
Transcript show:what.
]
]
Eval [
Transcript show: 'Derp'.
(Example new) printSomething: 'Derpy'.
]
Note the Eval [] block, and that you create an instance of Example, not NameOfSubclass.
Smalltalk is a purely object-oriented language. You can only send messages to objects, which invokes a method defined on their class.
On which class did you define printSomething? If you defined it as an instance method, you need to invoke it on an instance of that class. E.g.:
MyClass new printSomething: 'Derpy'
If you defined it as a class method, you can send it directly to the class itself.
In which class did you define the method? You're not specifying to which class you're sending the message (telling it to execute the method).
In the case of Transcript show: 'Derp'., you're sending a message to the global variable Transcript (an instance of the Stream class), and show: is a class method implemented on Transcript or one of its superclasses.
If the method is defined on the same class that you're sending from, self is the keyword to use, so it would be self printSomething: 'Derpy'.
When trying to learn smalltalk, use a smalltalk environment. Don't use a command line interface, don't use an on-line web tool. Both are very useful, but not to learn smalltalk. They don't provide the feedback you need to learn smalltalk good and fast.
If it doesn't allow you to write most of your code in the debugger, you won't learn smalltalk.
The book and environment developed to learn smalltalk is Pharo By Example. Use the image and vm from there. Pharo is developing fast, using a more recent version would be confusing.
In gnu-smalltalk 3.2.5.
Object subclass: Example [
printSomething: what
[
10 timesRepeat: [
Transcript show:what.
]
]
]
Eval [
Transcript show: 'Derp'.
(Example new) printSomething: 'Derpy'.
]
Any idea why the following doesn't work? (R3)
o: make object! [
foo: does [do "bar"]
bar: does [print "hello from bar"]
]
o/foo
** Script error: bar has no value
** Where: catch either -apply- do foo
** Near: catch/quit either var [[do/next data var]] [data]
Try this:
o: make object! [
foo: does [do get bind load "bar" self]
bar: does [print "hello from bar"]
]
o/foo ;this will work
You need that BINDing because your "bar" lives in the object, not in global scope.
Check this out as well:
my-func: does [print "ok"]
o: make object! [
foo: does [do "my-func"]
bar: does [print "hello from bar"]
]
o/foo ;this will work too
You need to LOAD it because it is a string, but it has to be a word to be BINDed.
So these will work too (put them in your object):
do get bind to-word "bar" self
or
do get bind 'bar self
No Scope!!!?
The reason do "self/bar" cannot know where to find 'BAR is because there is no scope in Rebol (not in the traditional CS meaning at least).
Words in Rebol only have meaning once they have been statically bound to a context. This automagically occurs when you 'MAKE an object, so many people don't even realize it even after years of use.
Here are the steps (loosely) when an object (a.k.a. context) is created.
It picks up all the root set words in its spec (in this case [FOO: BAR:] )
Adds them to its current internal words (SELF: by default, more if you are using an object as basis)
Then binds all the words in the block (hierarchicaly) to those set-words it added to its spec.
Executes the block.
So you see, once you execute the block its too late, the words already got assigned their meaning, which allows the interpreter to ask for their values (which could trigger an expression evaluation, hence the E in REBOL).
Global, cause that all there really is once executing.
DO and LOAD cannot automatically bind to anything but the global context... because there is no such thing as the "current context" like you'd have in traditional OOP and imperative languages (remember, no scope). Really, once its executing, that information doesn't exist anymore, unless you bound the "current" context to a word... which is what 'SELF does, but to be bound it has to already be loaded, which, when executing a string, never occured.
clueless functions
I'll finish by adding that it may not be obvious at first sight, but while it was binding the Object spec block, it still didn't know what FOO and BAR really were. in fact, the only way FOO and BAR could access the 'O object, is because their function block, when it was run thru 'MAKE, got bound to the object... yep, before it even knew it was a function. then if the function defined its own locals, it would re-bind its body block to those new locals.. because you guessed it... a function creates its own inner context, which gets the same MAKE treatment (but without the internal SELF word).
I hope this helps clear things in a more obvious light.
here is a proof that code isn't scoped:
a: make object! [
data: "HAHAHAAAAA!!!"
action: does [print self/data]
]
b: make object! [
data: "BUMBLING BEHEMOT"
action: does [print self/data]
]
b/action: get in a 'action
; this will print HAHAHAAAAA!!!
b/action
To explain moliad's answer a bit more, see the following explanation:
REBOL words carry a reference to their context with them. It’s not
where a word is evaluated that makes the difference, but where it’s
declared.
from http://blog.revolucent.net/2009/07/deep-rebol-bindology.html
Here is a very good example:
x: 0
b: [] loop 3 [use [x] [x: random 100 append b 'x]]
;== [x x x] <-- there are three X which looks same words (and they are same actually)
reduce b
;== [95 52 80] <-- but they have different values in their contexts
probe x
;== 0 <-- in global context, it has another value as well
This looks weird at first look, but actually it is not. USE creates a new context each time in the LOOP, we set X (in the context the USE created) to a value, then APPEND the WORD (not the value!) to a block.
All the words that we append to the block carries their own contexts with them, but they look same word.
When we REDUCE (or PRINT etc.), when we GET their values in their own contexts, we see that they all have different values!
I was going through (using Squeak) the Discovering Better Code: Bowling for Smalltalk Series by Ron Jeffries and I can't get pass through the third article.
A new class (called Frame) is being created which takes an array as an argument in the constructor.
Frame class>>new: anArray
^self new setRolls: anArray
Frame>>setRolls: anArray
rolls := anArray
When I try to run this in a simple test:
testFrame
| frame rolls |
rolls := Array with: 5 with: 4.
frame := Frame new: rolls.
I get the following error:
alt text http://files.getdropbox.com/u/120566/junk/error.png
How should I modify the #new message to be able to initialize Frame object with an array?
I guess you failed adding the method new: correctly to Frame class. Are you sure you put it on the class side (Frame class) and not on the instance side (Frame)? To do it, click on the 'class' button, before adding your method new:.
You really don't want to override new: here. new: is traditionally reserved for "Create an item of this integer size", and it doesn't surprise me that it's blowing up on you.
A more traditional name for the kind of constructor you want is fromArray:, or perhaps even fromCollection: which would probably have worked as you wished.