class
MAP[G]
create
make
feature --attributes
g_array: ARRAY[G]
size:INTEGER
feature{NONE}
make
do
g_array.make_empty
size:=0
end
class
MAP_TESTING
m: MAP[INTEGER]
create m.make
print(m.size)
The first class consist of an array and its size. When I tried to create an m object of ARRAY, nothing seems to be printing out when I put print(m.size). Am I instantiating the array correctly? Am I using the correct make function for ARRAY? Why isn't it printing anything?
---------------------------
class
MAP[G]
create
make
feature --attributes
g_array: ARRAY[G]
size:INTEGER
feature{NONE}
make
--I left this blank
end
class
MAP_TESTING
m: MAP[INTEGER]
create m.make
print(m.size)
This actually works when I left the make blank. It prints out 0. But this is no good because obviously if I call other functions using the array in MAP, it won't work. I actually tried using other functions from the class ARRAY, but I got a compile error.
The line to create the array in MAP should be:
create g_array.make_empty
And MAP_TESTING should be:
class
MAP_TESTING
creation
make
feature
m: MAP[INTEGER]
make
do
create m.make
print(m.size)
end
end
(Note that the print does not output a newline so the zero may easily be lost in the terminal.)
Related
Hi I'm trying to declare a simple array variable inside class ViewController. But when I try to append value to it, Xcode just keep giving me "Consecutive declarations on a line must be separated by ';' ... Invalid redeclaration of 'mylist()'"
var mylist = [String] ()
mylist.append("abc")
I copied it into the Playground and it works just fine. But somehow inside ViewController it just doesn't like it. I only have 1 line that declares mylist in the whole project.
Has any one experienced this? I can't see what's wrong with it.
I'm in XCode 11.5(11E608c)
Thx in advance.
Sorry I got it now.
The problem is inside class ViewController (or any class) you can declare the array variables but you can't append values into it until after the class is initialized.
So append will need to be done inside one of the class's func like func viewDidLoad().
Because at any other time the variable is NOT actually init yet and therefore can't be used.
And thus you can't execute its append function.
So I put the mylist.append("abc") inside func viewDidLoad now and it's all good.
Thank You.
Possibly very stupid question I cannot seem to find an answer for (I am beginning with code)
I want to create a simple loop which appends myArray with three objects, which are members of a custom class MyClass. The objects have the following names: "object1", "object2", "object3".
When I write the following code, there is no issue:
myArray.append(object1)
But I want to write a loop to add all three. Again, very dumb, but I can't figure out how to insert the number in the name of the object as a variable. E.g., here was something I tried
let x = 3
for i in 1...x {
myArray.append(object[i])
}
This gives an error. The reason I want to do it using a loop, and not simply write in the three objects manually, is that I won't always loop three times. Sometimes I'll just want the first two objects, sometimes just the first.
I assume there's some easy way to do this, but when I search it tends to turn up more complex questions
I am trying to make a CONTAINER class that maintains an array of CRITTER objects (that I have already created and tested. Note, there are various CRITTER subspecies, that are inheriting from the CRITTER super class). The aim is to add and remove CRITTER objects from this array. This is what the CONTAINER class looks like:
class
CONTAINER
create
make
feature
num: detachable INTEGER
list: ARRAY[CRITTER]
make
local
do
create list.make_empty
num := 0
end
addCritter(critter: CRITTER)
do
list.put(animal, num)
num := num + 1
end
removeCritter(critter: CRITTER)
do
list.put (list.at (num), ???) -- put last element in position of element to be removed
list.remove_tail (num) -- remove tail
num := num - 1
end
end
Two issues:
Firstly, I can instantiate the CONTAINER class inside APPLICATION, but when I call
create container.make
container.addCritter(myCritter)
I get a precondition, invalid index violation error on the second line. This may be because I have not set the upper and lower bounds of the array. However, when I try to do so, I get syntax errors. Which is the way to solve this issue?
Secondly, in order to remove an object from the array, it would help if I could get hold of the index value, but I can't see any function that does this, unless I am missing something.
ARRAYs are usually used for fixed-length containers. In your case, with lots of dynamic changes, it's better to use more dynamic structures, for example, ARRAYED_LIST. Similar to ARRAY it provides features to access items by their index, but there are also more convenient ones. New elements can be added by using feature extend. Old elements can be removed by using feature prune if only one element matching a given one needs to be removed, or prune_all, if all matching elements need to be removed. The word "matching" denotes either reference or object equality, depending on which comparison criteria is required: = or ~. The comparison criteria is changed using feature compare_objects.
Some general observations:
There is no need to track number of elements yourself, usually there is a feature count that provides this number.
Indexes in Eiffel usually start with 1, not 0.
The declaration detachable INTEGER is equivalent to INTEGER because INTEGER is expanded and all expanded types are attached regardless of any attachment marks.
The following discussion might also be useful:
How to initialise an array of objects in Eiffel?
I have a class of objects known as blocks. Currently, I am creating an array of blocks using a for loop by simply tacking them unto an empty array
blockArray=[];
for ii=1:Size
blockArray=[blockArray block(....)];
end
In order to preallocate memory, how do I initialize an object array of blocks with dummy values?
For instance if instead of using block objects I used numbers, I could easily preallocate by using zeros(1,Size). Is there something similar that I could do?
The matlab documentation describes
To preallocate the object array, assign the last element of the array first. MATLABĀ® fills the first to penultimate array elements with default DocArrayExample objects.
So, to do this, instead of iterating over from 1:size, it is simpler to do...
blockArray = []
blockArray(size) = block(...)
The language does not really support this, there exists multiple solutions (or workarounds).
Replicating the first instance
When pushing the first element into the array, you can fill the whole array with this element to achieve a preallocation. This might look very bad, but it is actually the fastest possibility known to me.
for ii=1:S
%assumption e is a scalar, otherwise the code is totally screwed
e=block(....)
if ii==1
%to do preallocation, fill it with your first element
blockArray(1:S)=e
else
blockArray(ii)=e
end
end
Use cell arrays
Obvious simple solution, you can put any class into the fields
blockArray=cell(S,1);
for ii=1:S
%assumption e is a scalar, otherwise the code is totally screwed
e=block(....)
blockArray{ii}=e
end
This solution is very simple but slower than the first. You also lose some functionality which is not available for cell arras
Let your class implement array functionality
classdef A
properties
arg1
out
end
methods
function obj = A(varargin)
if nargin==0
%null object constructor
elseif strcmpi(varargin{1},'createarray')
sz=varargin(2:end);
%preallocate
obj(sz{:})=A;
else
%standard constructor
obj.arg1=varargin{1};
obj.out=[1 2 3;];
end
end
end
end
Constructor with no input argument creates an "empty" or "null" object, this is used to preallocate so it should be empty.
Constructor with first parameter makearray creates an array
Otherwise your constructor should be called.
Usage:
%create an empty object
A
%create an array of size 2,3,4
A('createarray',2,3,4)
%use the standard constructor
A(2)
Biggest downside is you have to modify your classes. Never tested this solution, but it should be close to the first in performance.
I am trying to implement a solution to the Producer-Consumer problem using Eiffel. I have an array p of class PRODUCER and an array c of class CONSUMER declared and initialized as following:
local
p : attached ARRAY[PRODUCER]
c : attached ARRAY[CONSUMER]
do
!!p.make(1, 5)
!!c.make(1, 5)
But when I try to access a feature in one of the components of the array (like p.at(i).somefeature()), it gives a runtime exception saying Feature call on void target.
Any ideas on how to solve this? Is it because I am not calling a creation procedure for individual components of the array? Or is there a basic flaw in the approach to create the arrays? Thanks.
I figured the problem occurs because the individual components of the arrays (in this case, a producer or a consumer), being a reference type is initialized to void. The solution suggested is to use make_filled(default_value:T;low,high:INTEGER;), where T is the complex type. An example is given for string arrays as
string_list : ARRAY[STRING]
string_list.make_filled(" ", low, high)
causing each element of string_list to be initialized to a string that is a blank space. Any help on how to give a default value for the class PRODUCER? Thanks
I think I figured out the solution to the problem. I just had to create an instance of PRODUCER and CONSUMER and use those in the default value in make_filled. Then I can manipulate p[i] and c[i].
This is not a super efficient way, so if there is a better solution, please do share it. Thanks.
{ARRAY}.make_filled is normally used when all the elements of the array should be the same. If the elements are different, the array can be filled one by one:
create p.make_empty
p.force (create {PRODUCER}.make ("producer 1"), 1) -- Use appropriate code to
p.force (create {PRODUCER}.make ("producer 2"), 2) -- create PRODUCER objects.
...
There is also a somewhat obsolete syntax to create arrays, so it has to be used with care:
p := <<
create {PRODUCER}.make ("producer 1"), -- Or some other code
create {PRODUCER}.make ("producer 2") -- to create producers.
>>