smalltalk returning string from block in VisualWorks - block

I want to return the value, that was passed int to the block. If it's a number, everything works great, but If I put in a String or boolean value, I get a "Message not understand".
q := [ :a | a].
Transcript show: ((q value:'123') value) printString.
I thought everything is treated the same, so I'm confused. But I guess I'm just missing something.
edit: it seem to work under Pharo...

The message "value" isn't implemented for Object in VisualWorks. Some applications add it in but it's not in the base class library. In some versions of VisualWorks it slipped into the base class library and was later taken out.
If you write your code like this it will work:
q := [ :a | a].
Transcript show: (q value:'123') printString.

Remove the send of #value. It is not necessary for your example as you described it. #value: is sent to the Block, which returns the argument, as you wanted. You then send #value to the argument, which works in Pharo because it returns self and is essentially a non-op.
This fixes your error because, as I suspected and David verified, VisualWorks Strings DNU #value.
n.b. As Bob said, the key missing info in your question is "Which object DNU which message?" In general, the more specific you are about your errors, the better the answers can be.

Works fine for me.
| q |
q := [ :a | a].
Transcript show: ((q value: true) value) printString.
| q |
q := [ :a | a].
Transcript show: ((q value: 123) value) printString.
If you have a DNU exception you will be able to see which object is receiving the message that is not understood. Post that information.

Related

Confusing .fmt behavior with nested Lists

The docs say that fmt
Returns a string where each element in the list has been formatted according to $format [the first argument] and where each element is separated by $separator [the second argument].
Based on that description, I expected to be able to call .fmt on a List of Lists, and then pass a printf-style format string containing a % directive for each element in the inner list. But that doesn't work.
If you'd told me that I was wrong about ^^^^, I'd have expected that .fmt was auto-flattening its arguments and thus that each argument would be formatted and separated by the $separator. But that's also not what happens.
Instead, running this code
say (<a b c>, <1 2 3>, <X Y Z>).fmt('→%03s|', "\n=================\n");
produces this output:
→00a| →00b| →00c|
=================
→001| →002| →003|
=================
→00X| →00Y| →00Z|
That is, the format string is applied to each element in the inner lists, those lists are then stringified (without using the format string; note the between each | and → character), and then the separator is inserted between each outer list.
That leaves me with three questions:
Have I correctly described/understood the current behavior? [edit: nope. See below]
Is this behavior intentional or an odd bug? (I checked Roast, but didn't see anything either way)
Assuming this is intentional, why? Is there some way that this is consistent with Raku's general approach to handling lists that I'm missing? Or some other reason for this (imo) surprising behavior?
Edit:
After further investigation, I've realized that the behavior I observed above only occurs if the format string contains a width directive. Changing the →%03s| format string from above to →%s| produces the following output:
→a b c|
=================
→1 2 3|
=================
→X Y Z|
That is, without a width, the format string is applied after the list is stringified rather than before.
So I'm back to being confused/thinking at least some of this behavior must be buggy.
Ok, it looks like there were at least two bugs here. This should be fixed with https://github.com/rakudo/rakudo/commit/a86ec91e36 . Writing spectests for these situations, would be appreciated :-)

List of methods if their implementation has at least two occurences of a word 'assert' in Smalltalk

I wanted to get the list of methods of a class if their implementation has at least two occurrences of a word 'assert' in Smalltalk.
Can somebody help me with this? Thanks in advance!
I'm not sure about the details of gnu-Smalltalk, but in Pharo, you can do something like this:
YourClass methods select: [ :method |
method sourceCode matchesRegex: '.*assert.*assert.*'. ]
Here I use a trivial regex to see if I can match two "assert" words in the source code.
However, with Smalltalk, it's easy to do more precise searches. Image, you want to see if a method sends at least two assert: messages. You can find such methods this way:
YourClass methods select: [ :method |
| numAsserts |
numAsserts := method ast allChildren count: [ :node |
node isMessage and: [ node selector = #assert: ] ].
numAsserts >= 2
]
In the example above, for each method, we simply count the number of AST nodes that are message sends, and have the assert: selector. Then we check if the number of these nodes is greater or equal to 2.

What does the type in the formatting types syntax do?

What does the ‘type’ in the formatting types syntax of format! do?
Of this, that is:
[[fill]align][sign]['#']['0'][width]['.' precision][type]
The rest appears to be well documented, but that particular one seems to have some information left out. Under its explanation it says:
type := identifier | ''
But what on Earth is it used for?
Edits
1.
Someone suggested that they be for named parameters, and that feels reasonable to assume. However, should the following code not work had that been the case?
println!("{:.2test}", test=32.432);
This generates me a rather depressing error:
error: unknown format trait `test`
--> src\main.rs:12:29
|
12 | println!("{:.2test}", test=32.432);
| ^^^^^^
What must be noted here is that the syntax above is for format_spec, which always follows a colon.
format := '{' [ argument ] [ ':' format_spec ] '}'
format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
With that in mind, the type part is used to specify formatting traits, which are documented as thus:
When requesting that an argument be formatted with a particular type, you are actually requesting that an argument ascribes to a particular trait. This allows multiple actual types to be formatted via {:x} (like i8 as well as isize).
[...]
If no format is specified (as in {} or {:6}), then the format trait used is the Display trait.
Here's an example (Playground):
println!("{:b}", 31); // prints 11111
println!("{:08b}", 31); // prints 00011111
Type formatting works for any data type that implements the corresponding formatting type, such as Binary or LowerHex.
At first I guessed it would be named parameters, but those actually go before the colon. Just for the record, this also works (Playground):
format!("{a:08b}", a = 31)

Print a SortedCollection to screen using keysAndValueDo (smalltalk)

Hello i'm learning and am new to smalltalk and I'm trying to print my SortedCollection to screen trying to use keysAndValueDo but im not sure how its done, if anyone could give me a general example that would be great
Part 1 - Displaying to the screen
The most straight forward way to print to the screen in a GUI-based Smalltalk is to use the message:
Transcript show: 'some text'
(The Transcript is a system object that displays into a scrollable window).
To make sure there is a newline before each line of display text, we send the message cr to the Transcript
Transcript cr.
Transcript show: 'some text'.
A shorthand method, that saves us re-typing Transcript over and over, is to send Transcript a series of messages one after another. This is called a message cascade. Each time we end a message in ; it means send to the same receiver as the last message was sent to.
We can then shorten this again, as Smalltalk pays no attention to newlines in expressions.
The final display message cascade becomes:
Transcript cr; show: 'some text'.
Part 2: Enumerating aSortedCollection using keysAndValuesDo:
This keyword message is SequencableCollectionand its method header is:
keysAndValuesDo: aBlock
"Enumerate the receiver with all the keys (aka indices) and values."
(It works the same way in Dolphin, and in Squeak and its derivatives, Pharo and Cuis).
The keyword message keysAndValuesDo: takes a block argument.
A block is an anonymous object, with one method. Its method is defined between a matched pair of square brackets - a [ ... ] pair.
In this case, we need a local variable in the block for the key of each element of the collection, and another local variable for the value of each element.
We can call them anything we like, and in this case, it is the order that they appear in that is important. keysAndValuesDo: will put the element's key into the first local variable in the block, and will put the element's value into the second local variable in the block.
Local variables in a block are declared at the start of the block, and each variable name is identified by prefixing it with :. The local variable declarations are ended with a |.
The block then looks like
[:local1 :local2 |
"do something for each element, with the key in local1 and the value in local2"
]
I prefer meaningful local variable names, so I'll use eachKey and eachValue.
Part 3: Putting it all together
To enumerate through mySortedCollection
"Declare the mySortedCollection variable"
|mySortedCollection|
"Initialise the collection"
mySortedCollection := SortedCollection new.
"add in some data to the collection"
mySortedCollection add: ('First') ;
add: ('Second') ;
add: ('Third').
"Enumerate through the collection, displaying to the Transcript window"
mySortedCollection keysAndValuesDo:
[:eachKey :eachValue |
Transcript cr; show: eachKey; show: ' '; show: eachValue
] .
Paste the code into a Workspace (known as a Playground in Pharo, from version 4.0 onwards). Select the text. Once selected, right-click (on a two or three button mouse) and select "Do it" from the menu. Or use Ctrl-d as a keyboard shortcut. (The exact chording key may vary on your platform)
Final notes
In a SortedCollection or an OrderedCollection, the key is the index. The value is what is stored at element[index].
In a Dictionary, the key of the element is the key, and the value of the element is the value.
SortedCollections are sorted in order of the element values, according to the definition of the collections sort block. In the absence of a custom sort block, they will be added in ascending order. 'First', 'Second' and 'Third' are, coincidentally, in alphabetical order. It happens to work out nicely in this example.
The following example works with Pharo Smalltalk, other Smalltalk implementation might work similar.
First, look at existing print methods as examples. In case of SortedCollection, you find them in the printing protocol of its superclass Collection.
You will find that the printing of elements is defined in printElementsOn:. So you could overwrite this method in SortedCollection.
Here is a printElementsOn: method that will use keysAndValuesDo:, as you were asking for:
printElementsOn: aStream
aStream nextPut: $(.
self keysAndValuesDo: [:key :value |
aStream
nextPut: $(;
print: key;
nextPut: $:;
space;
print: value;
nextPut: $)].
aStream nextPut: $)
Now a collection that before printed:
"a SortedCollection(1 2 3 3 5 10)"
will print:
"a SortedCollection((1: 1)(2: 2)(3: 3)(4: 3)(5: 5)(6: 10))"

Working with Seaside continuations

How do I get a BlockClosure in Squeak (I want to use BlockClosure>>callCC)?
When I write [#foo] that is a BlockContext, what's the deal?
Update: I have worked out that BlockClosure is a thing mainly of new compiler.
Instead how do I work with seaside Continuations? I'm having problems, and any examples would be appreciated.
Further update: The purpose of this is not to use seaside (at least not directly) but rather to write traversals and other such things in a way that is easier than rolling my own state-tracking iterators.
Normally, with Seaside, you never have to deal with Continuations yourself at all.
You just use #call: and #answer: from within your components.
If you're trying to do something else with Continuation other than writing a Seaside application, take a look at WAComponent>>call: for an example of usage.
Or try this. Open a Transcript window. Now, in a Workspace, select all of this code at once and Do-it:
continuation := nil.
result := Continuation currentDo: [:cc |
"store the continuation, cc, somewhere for later use"
continuation := cc.
1 ].
Transcript show: result.
You should see 1 displayed in the Transcript window. Now, in the workspace, do:
continuation value: 2
and then:
continuation value: 3
You should see each value you pass to continuation displayed in the Transcript because each value you pass to #value: causes the context of the continuation to be restored and the new value assigned to result.
Hopefully that helps...