Why is assigning many variables seem to mutate my variable? - smalltalk

I'm new to Smalltalk so I don't know if I'm doing something wrong but this seems very weird and buggy.
dict := Dictionary new.
dict at: 1 put: 1.
dict at: 2 put: 2.
dict at: 3 put: 3.
dict at: 4 put: 4.
1 to: 4 do: [:j |
key := j.
value := dict at: key.
value print.
value printNl.
].
This code works fine and correctly print
11
22
33
44
But then, if I add enough assignments to other variables the result of the script change:
dict := Dictionary new.
dict at: 1 put: 1.
dict at: 2 put: 2.
dict at: 3 put: 3.
dict at: 4 put: 4.
1 to: 4 do: [:j |
key := j.
value := dict at: key.
value print.
unrelated := 1.
unrelated2 := 1.
unrelated3 := 1.
unrelated4 := 1.
unrelated5 := 1.
unrelated6 := 1.
unrelated7 := 1.
unrelated8 := 1.
unrelated9 := 1.
unrelated10 := 1.
value printNl.
].
This code now prints
11
21
31
41
If I remove the line assigning unrelated10 it works again... Am I missing something or is GNU Smalltalk buggy ?
I am using GNU Smalltalk version 3.2.5.

I believe that this is a bug in GNU Smalltalk. It appears that the system allows you to reference variables that have not been defined (this "feature" is not standard) and the system's attempt to define the variables and their scope is having problems.
The work-around is to define your own variables and give them as narrow a scope as possible (this is good practice in any language). So, try the following (validated at here):
| dict |
dict := Dictionary new.
dict at: 1 put: 1.
dict at: 2 put: 2.
dict at: 3 put: 3.
dict at: 4 put: 4.
1 to: 4 do: [:j |
"The following is a list of variables used in this code block"
| key value
unrelated unrelated2 unrelated3 unrelated4 unrelated5
unrelated6 unrelated7 unrelated8 unrelated9 unrelated10 |
key := j.
value := dict at: key.
value print.
unrelated := 1.
unrelated2 := 1.
unrelated3 := 1.
unrelated4 := 1.
unrelated5 := 1.
unrelated6 := 1.
unrelated7 := 1.
unrelated8 := 1.
unrelated9 := 1.
unrelated10 := 1.
value printNl.
].

Related

FIle handling in Eiffel

Given a file input.txt, which consists of a number of elements in arrays and elements in the arrays, I should read the data and copy it to arrays in Eiffel. For example, for
3
3 4 5
2 3 1
I should get len = 3, a1 = {3,4,5}, a2 = {2,3,1}.
I have tried the following but it was not successful
take_input
-- Read user's input.
local
input: PLAIN_TEXT_FILE
output: PLAIN_TEXT_FILE
itr: INTEGER
do
create input.make_open_read ("input.txt")
input.read_integer
len := input.last_integer
create output.make_open_write ("output.txt")
create num.make_filled (0, 1, len)
create rem.make_filled (0, 1, len)
from
input.start
input.read_integer
itr := 0
until
input.off
loop
itr := itr + 1
if itr <= len then
num [itr] := input.last_integer
input.read_integer
else
rem [itr - len] := input.last_integer
input.read_integer
end
end
input.close
end
Here Is there any way I can continously read the inputs rather than again starting from the Begginning of the file?
There is no need to go to the beginning of the file after reading the number of elements. Therefore, removing input.start right after from will do the trick.
As a sanity check (in case it matters for your program), it makes sense to test whether len is positive before starting the loop.

How to add new line character in DBMS_OUTPUT.put_line in LINUX

In UNIX, in a SQL script, i have following code:
LOOP
DBMS_OUTPUT.put_line (p_key||'|'||p_loc||'\n');
END LOOP
Output is:
5482004|Dir/3-30-2017/file:47923.xml
5482009|Dir/3-30-2017/file:49288.xml
However in Linux, since "\n" doesn't work, i am replacing the above code with following code:
LOOP
DBMS_OUTPUT.put_line (p_key||'|'||p_loc);
DBMS_OUTPUT.new_line;
END LOOP
Output is:
20 5482004|Dir/3-30-2017/file:447923.xml 5482009|Dir/3-30-2017/file:449288.xml 5482010|Dir/3-30-2017/file:449739.xml 5482012|Dir/3-30-2017/file:45015.xml
The output in this format is without the new line after each line. Please suggest what is in correct in the loop.
P.S. I have also tried DBMS_OUTPUT.put_line (p_key||'|'||p_loc||chr(10)) but the output is still without the new line.
Please refer below SO answer for this question.
New Line Character in dbms_output
You can use chr(10)
My code in which i was trying to swap numbers ,where i need new line so i used chr(10)
DECLARE
A NUMBER;
B NUMBER;
TEMP NUMBER;
BEGIN
A:=&A;
B:=&B;
DBMS_OUTPUT.PUT_LINE(chr(10)||'BEFORE SWAP A is : '||A||' AND B is : '||B);
TEMP:=B;
B:=A;
A:=TEMP;
DBMS_OUTPUT.PUT_LINE(' AFTER SWAP A is : '||A||' AND B is : '||B);
END;
/
Output:
Enter value for a: 1
old 6: A:=&A;
new 6: A:=1;
Enter value for b: 2
old 7: B:=&B;
new 7: B:=2;
-- here i got new line
BEFORE SWAP A is : 1 AND B is : 2
AFTER SWAP A is : 2 AND B is : 1
PL/SQL procedure successfully completed.
So before line(i.e BEFORE SWAP A is : 1 AND B is : 2) in output i got new line.

How to use a multiple line input to create my game?

So, i have one method that will create all of the instance variables for my other methods that will create the game, i know how to do them separately but finding how to do it from one method is really hard.
I need to be reading data from a String where each line must be treated separately.
Am using Pharo.
Class Game, everything is within one Game class.
Game: instance variables: 'rol col'. Using instance methods.
readFrom: 'Board 3 4
Dice 2 1 1 1
Players 1'
board
[my actual code that creates a board]
row for loop[
Transcript show: 'creating board'.
col for loop[
Transcript show: 'creating board'.
]
]
dice
[dice code..]
players
[players code]
Your model is not clearly defined yet. However, by helping you with some coding I will try to give you some insights on how to fill the gaps still remaining.
So, let's say you have a class Game. This class defines (at least) 4 instance variables: rows, columns, dice and players.
Now you want to create an instance of Game by reading some String that conforms to a certain format, such in:
'Board 3 4
Dice 2 1 1 1
Players 1'
To do this create a class side method in Game on the lines of
readFrom: aString
^self new readFrom: aString
and then an instance method
readFrom: aString
aString lines do: [:line | | data key |
data := line substrings.
key := data at: 1.
key = 'Board'
ifTrue: [
rows := data at: 2.
columns := data at: 3].
key = 'Dice'
ifTrue: [
dice := data allButFirst collect: [:s | s asInteger]].
key = 'Players'
ifTrue: [
players := (data at: 2) asInteger]]
Again, this won't solve all problems, but should help you get started. Otherwise, ask again.

Invalid Input Exception Handling - SmallTalk

Let a smalltalk msg named "sum" return the sum of elements in an array.
Eg: #(1 2 3 4 5) sum ----> 15
When the input is #(1 2 'a' 3 5) sum. The execution terminates and shows a big exception box.
Instead of that how can we gracefully exit the execution by just showing a message. I don't want the big exception window to be shown.
sum
|sum|
sum := 0
self do: [:a | sum := sum + a]
^sum
I tried to handle the exception the below way. However, I notice that the execution doesn't terminate in case of invalid input.
sum
|sum|
sum := 0
self do: [:a |
(a isInteger) ifFalse:[
^[Error signal] on: Exception
do: [:ex | Transcript show: 'Entered values are non-numeric. Hence comparison is not possible.']
]
sum := sum + a
]
^sum
If the below code is placed in the workspace, I expected the execution to be terminated at line 2. However, line 3 is also getting executed.
|temp|
temp := #(1 2 3 'as' 4 5) sum.
temp := temp*5.
Changing the sum method to ignore the wrong types in the input Array does not make sense. Furthermore by replacing it with a UI message you completely loose control over what kind of input is acceptable. Rather deal with these exception at the place you use sum:
[ ^ self readInput sum ]
on: Error do: [ :error| Transcript show: 'Invalid input provided for sum' ].

How to manage 2d array in Smalltalk?

I have a list of point and have to do erosion/dilation operations. I need a kind of 2d-array but can't find how to do in VisualWorks (I know there is a Array2d class in Squeak, but I must use VW).
Many Smalltalk implementation will have some kind of Matrix class, sometimes optimized, that will have methods such as #rowAt:columnAt: (or for brevity #at:at:).
In GNU Smalltalk this is in package DhbNumericalMethods. Right now it is not optimized though.
Use simply a generic way: array of arrays:
(Array new: xSize)
at: 1 put: ((Array new: ySize) at: 1 put: aValue; at: 2 put: aValue; ...);
at: 2 put: ((Array new: ySize) at: 1 put: aValue; at: 2 put: aValue; ...);
...
If you want to the operations to be efficient, study the VisualWorks Image class, protocol "image processing" and "bit processing". Build your own erosion/dilation operations based on primitives there.
Here is another way to deal with a two dimensional array in Squeak (I'm using version 4.2).
test := Matrix new: 3. "this defines a 3 x 3 array"
test at: 1 at: 1 put: 5.
test at: 1 at: 2 put: 6.
test at: 1 at: 3 put: 7.
etc, etc. AFAIK you can only do 2D arrays this way, and they must be a square matrix. This worked well for a project that my son and I are working on to make a Sudoku game, ymmv. CHEERS!
Array subclass: Array2D
instanceVariableNames: 'myRows myColumns'
classVariableNames: ''
poolDictionaries: ''
category: 'Basic Data Structures'
"I am a two-dimensional array of arbitrary objects.
[Privately, I am really a linear (one-dimensional) array.
I locate my elements internally by index arithmetic on their
(two-dimensional) coordinates.]"
Instance creation (class)
-------------------------
new: nRows by: nColumns
"Create a new instance of me with nRows rows and nColumns
columns."
^(super new: (nRows * nColumns))
withRows: nRows withColumns: nColumns
"exampleArray := Array2D new: 10 by: 5"
Initialization
--------------
withRows: nRows withColumns: nColumns
"Set my number of rows and columns to nRows and nColumns,
respectively.
"
myRows := nRows.
myColumns := nColumns
Properties
----------
rows
"My number of rows."
^myRows
columns
"My number of columns."
^myColumns
Element access
--------------
atRow: whichRow atColumn: whichColumn
"My element at row whichRow and column whichColumn."
^super at: (self indexAtRow: whichRow
atColumn: whichColumn)
"exampleValue := exampleArray atRow: 6 atColumn: 4"
atRow: whichRow atColumn: whichColumn put: newValue
"Store value newValue as my element at row whichRow and
column whichColumn."
super at: (self indexAtRow: whichRow
atColumn: whichColumn)
put: newValue
"exampleArray atRow: 6 atColumn: 4 put: exampleValue"
Private
-------
indexAtRow: whichRow atColumn: whichColumn
"The internal index at which I store my element at row
whichRow and column whichColumn.
"
^((whichRow - 1) * myColumns) + whichColumn