Scoop Noob

123 views
Skip to first unread message

Gachoud Philippe

unread,
Feb 11, 2020, 7:23:38 AM2/11/20
to Eiffel Users
Hi Folks,

I'm trying to jump into scoop and have an old rusty sr background. 

It's difficult for me to understand the way to start processes. I read the docs, saw a youtube tutorial (maybe there are more I didn't found)

My background most simple example was with a horse run I'm trying to reproduce and seems pretty simple (for me...) here is my code I'm unable to make work in parallel, the execution goes sequencial. What am I missing?

Screenshot_20200210_012646.png

HORSE
note
description: "horses_run application root class"
date: "$Date$"
revision: "$Revision$"

class
APPLICATION

inherit
ARGUMENTS_32

create
make

feature {NONE} -- Initialization

make
local
l_horses: LINKED_LIST[separate HORSE]
do
io.put_string ("*********** HORSES RUN START **********************")
-- All horses in the field
create l_horses.make
across
1 |..| 5 is l_horse_id
loop
l_horses.extend (create {HORSE}.make (l_horse_id))
end
-- RUN
across
l_horses is l_horse
loop
horse_run (l_horse)
end
io.put_string ("*********** HORSES RUN END **********************")
end

horse_run (a_horse: separate HORSE)
do
a_horse.run
end

end




APPLICATION

note
description: "Summary description for {HORSE}."
author: ""
date: "$Date$"
revision: "$Revision$"

class
HORSE

create
make

feature {NONE} -- Initialization

make (an_id: like id)
do
id := an_id
end

feature -- Access

id: INTEGER

Max_run_count: INTEGER = 20

is_running: BOOLEAN

feature -- Element change

run
local
l_i: INTEGER
l_track: STRING
do
from
is_running := True
l_i := 0
l_track := ""
until
l_i = Max_run_count
loop
l_track.append ("*")
io.put_string ("id: " + id.out + "--->" + l_track + "%N")
delay (500)

l_i := l_i + 1
end
is_running := False
end

feature {NONE} -- Timing

delay (milliseconds: INTEGER_64)
-- Delay execution by `milliseconds'.
do
(create {EXECUTION_ENVIRONMENT}).sleep (milliseconds * 1_000_000)
end

end







Jocelyn Fiat

unread,
Feb 11, 2020, 8:24:47 AM2/11/20
to Eiffel Users
Quickly, I guess the missing key is  when you instantiate the HORSE, it should be as separate
for instance

create {separate HORSE}.make (l_horse_id)

I would recommend you to look at current examples in
$ISE_EIFFEL/examples/scoop/  for instance the dining_philosophers, or the producer_consumer



--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/08f6cc67-4aa4-4536-b883-5be6e173b3e9%40googlegroups.com.


--
Jocelyn
------------------------------------------------------------------------
Eiffel Software
https://www.eiffel.com
Customer support: https://support.eiffel.com
User group: https://groups.google.com/forum/#!forum/eiffel-users
------------------------------------------------------------------------

Gachoud Philippe

unread,
Feb 11, 2020, 8:47:01 AM2/11/20
to Eiffel Users
Thx Jocelyn, it worked, I took a look at the examples but were too complex for the beginning for me to infer what was missing in my sample. Maybe a trivial example as the one I did could help others
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel...@googlegroups.com.

Karsten...@gmx.de

unread,
Feb 12, 2020, 9:42:21 AM2/12/20
to eiffel...@googlegroups.com
Dear Philippe,
 
thank you very much for the example.
I am a scoop novice, too.
I modified your code a little bit in order to verify
that a slower horse (id 3) is really the last one to finish the run.
 
You may find the code in scoop_horses.zip
 
Best,
Karsten

Gachoud Philippe

unread,
Feb 12, 2020, 9:55:55 AM2/12/20
to Eiffel Users
Nice!! Happy to know it could help,

1) could be nice to have a github or better (as not proprietary and not from microsoft ;-)) sourceforge git repository with this example
2) actually maybe somebody could help too so that the horse-run is more nice to view as now. The ideal would be to have it in a terminal with overriding the current line with the race, but don't know how to do that (didn't dedicate the time either)

someting like:

1) --------*------------
2) ----------*----------
3) --*------------------
4) ----------------*----

refreshed

Anybody an idea??

Gachoud Philippe

unread,
Feb 12, 2020, 10:23:16 AM2/12/20
to Eiffel Users
You'll find your example here


From there we can work if you agree

Gachoud Philippe

unread,
Feb 13, 2020, 9:51:23 AM2/13/20
to Eiffel Users
Sry need some more feedback for understanding of scoop and abstract notions

did a bit more extended test and in the above case, 

1) do I have to understand that before a separate `horse.run` is not finished, the following separate horse to display its status is waiting (waiting for l_hors.run to finish?) as I saw in the logs its the case...
2) The goal for me was to have a loop that shows the status of all horses at a time, but don't see how I could afford it

-- Make all horses run.
across
horses is l_horse_item
loop
separate l_horse_item as l_horse_sep do
l_horse_sep.run -- 1) till this call is not finished, the following separate instruction will be blocked???
end
end
io.put_string (" ---------> All horses started%N")

-- Show status of run
across 1 |..| 15 is l_status_show_runs loop
io.put_string ("------------ Race status ---------------------------------%N")
-- Show status of the horses
across
horses is l_horse_item
loop
separate l_horse_item as l_horse_sep do -- 1) question is it blocked till the l_horse_sep.run finishes?
io.put_string ("Getting horse (" + l_horse_sep.id.out + ") out %N")
create l_s.make_from_separate (l_horse_sep.out)
io.put_string (l_s + "%N")
end
end
io.put_string ("------------------End race status ---------------------------%N")
wait (300)
end


Thx!

Karsten...@gmx.de

unread,
Feb 13, 2020, 10:18:38 AM2/13/20
to eiffel...@googlegroups.com
Dear Philippe,
 
please find a new and simpler version at http://t1p.de/b64o .
 
You are struggling with the resynchronization issue.
Therefore, I added comments in APPLICATION
regarding asynchrony and resynchronization.
 
Moreover, `speed' has been replaced by `slowness',
thus, `struggle' is easier to understand.
And the program works without any timer module.
 
Bye,
Karsten

Gachoud Philippe

unread,
Feb 13, 2020, 10:27:41 AM2/13/20
to eiffel...@googlegroups.com
Thx, actually no, I'm struggling more with how to attain all the horses while they are running so I can display their status in a t instant.... that was the purpose of what is following `-- Show status of run`

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/trinity-389118f7-10b1-49ce-a3e1-9f7e16945cd0-1581607116656%403c-app-gmx-bap11.


--
**********************************************
Philippe Gachoud
Puerto Williams 6657
Las Condes
Santiago de Chile
+56 934022210
ph.ga...@gmail.com
**********************************************

Karsten...@gmx.de

unread,
Feb 13, 2020, 11:12:49 AM2/13/20
to eiffel...@googlegroups.com
Dear Philippe,
 
you made all horses run asynchronously
in the across horses loop.
 
In the across 1 |..| 15 loop
you try to query horses, e.g. l_horse_sep.id.out.
This causes waiting until the horse in question
has finished the run, i.e. resynchronization.
 
To avoid the behaviour make HORSE.run show the status.
See http://t1p.de/b64o (scoop_horses.zip).
 
Best,
Karsten

Gachoud Philippe

unread,
Feb 13, 2020, 12:05:21 PM2/13/20
to Eiffel Users
Thx Karsten, 

actually that was what I did in the first version (shown above)

What I intend to do is to have lines of the status of all running horses (and at the same time dealing with accessing currently running processors)

something like repeatedly

***** STATUS START ****************
1) speed (35) pos (3) -->__*_____________<---
2) speed (69) pos (8) -->______*_________<---
3) speed (64) pos (14) -->______________*<---
4) speed (21) pos (13) -->_____________*_<---
5) speed (99) pos (9) -->_________*_____<---
***** STATUS END ****************

which is more beautiful than ununderstandable position changes

for the philosopher dinner it could be something like

***** STATUS START ****************
Philosopher 1: eating
Philosopher 2: thinking
Philosopher 3: eating
Philosopher 4: thinking
Philosopher 5: thinking
***** STATUS END ****************


Karsten...@gmx.de

unread,
Feb 15, 2020, 12:25:35 PM2/15/20
to eiffel...@googlegroups.com
Does anybody know how to send the escape sequences
that are listed at
https://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html
to the console? I think this would help Philippe.

@Philippe: Your first version worked
because APPLICATION did NOT query the horses' states
while they were running.
THEY reported their status by themselves, instead.

As I am also new to SCOOP I do not know
if there is a kind of shared memory
where the horses could leave their status messages,
which then could be queried and displayed by APPLICATION
without waiting for the horses to finish their runs.

Best,
Karsten

Alexander Kogtenkov

unread,
Feb 15, 2020, 4:08:47 PM2/15/20
to eiffel...@googlegroups.com
A question about using terminal control sequences was answered on StackOverflow: https://stackoverflow.com/questions/52859429/eiffel-is-there-a-way-to-print-colorized-characters-into-a-terminal-console It talks about colored text, but the technique should be similar for positioning a terminal cursor.
 
As to the other question, about shared memory, in SCOOP shared objects could be used instead. If every horse object keeps a reference to such a common object, it could be updated by every horse when needed. If there is any change, the object could refresh current picture on the terminal (it’s also possible to use Vision, and draw the progress there, in a GUI application). Alternatively, the object that records the state can send the state snapshot to the «printer» object that would actually perform the «drawing». This way horses would not wait for the drawing to be complete on every update. Finally, the printer could be an active object. Then, it would retrieve the state with a specified «frame rate» frequency, independent of the rate of updates initiated by horses. This would make the behavior most scalable. Here are the client relationship diagrams for all 3 variants:
 
  1. horse1, horse2, … horseN ===> state keeper and printer
  2. horse1, horse2, … horseN ===> state of all horses ===> printer
  3. horse1, horse2, … horseN ===> state of all horses <=== printer
The differences are as follows:
  1. Every update from a horse could trigger an update on the screen, affecting real horse speed, and delaying updates from other horses.
  2. Updates on the screen do not affect horses speed, but could be redundant.
  3. Frequencies of updates from horses and screen updates are decoupled, the latter could be a parameter of the application to improve user experience and reduce CPU usage.
Regards,
Alexander Kogtenkov
 
 
karsten...@gmx.de:
 
--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Karsten...@gmx.de

unread,
Feb 16, 2020, 2:29:24 AM2/16/20
to eiffel...@googlegroups.com
Dear Alexander,

I really appreciate your effort to try and help us.

The idea was to grasp SCOOP stepwise.
Your proposed alternatives come in handy.
We wanted to start with a 'minimal example'
consisting of only 2 or 3 classes, i.e. no GUI.

APPLICATION's `make' calls `prepare_console':

prepare_console
-- Initialize the console to handle ANSI escape sequences!
do
-- Make sure the console is allocated in a non-console application.
io.output.end_of_file.do_nothing -- {BOOLEAN}.do_nothing?
-- Set console to terminal mode.
initialize_terminal
end

initialize_terminal
-- See `prepare_console'!
external "C inline"
alias "[
#ifdef EIF_WINDOWS
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) return;
DWORD dwMode = 0;
if (!GetConsoleMode(hOut, &dwMode)) return;
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
}
#endif
]"
end

Unfortunately, C compilation (Windows 7, 64 bits, GCC) seems to fail:

In file included from big_file_C1_c.c:3:
ap2.c: In function 'inline_F2_4744':
ap2.c:44: error: 'ENABLE_VIRTUAL_TERMINAL_PROCESSING'
undeclared (first use in this function)
ap2.c:44: error: (Each undeclared identifier is reported only once
ap2.c:44: error: for each function it appears in.)

Any help?

Best regards,
Karsten

(Classes at http://t1p.de/b64o in scoop_horses.zip.)

Alexander Kogtenkov

unread,
Feb 16, 2020, 3:15:39 AM2/16/20
to eiffel...@googlegroups.com
The terminal functionality is available only starting from Windows 10. It is not there for Windows 7. As a result, it would be difficult to use the same cursor positioning code on Windows (before Windows 10) and Linux. However, it should be possible to abstract away the details in a dedicated class with different implementations on different platforms. Windows version would use a specific API to work with console, such as SetConsoleCursorPosition (https://docs.microsoft.com/en-us/windows/console/setconsolecursorposition). Linux version could use terminal escape sequences.
 
Less visually pleasing behavior but without resorting to any specific console functions could be achieved if printing current race state on a single line is an option, something like
 
 |--*---| |-*----| |---*--| |--*---|
 
Then, using a carriage return instead of a new line after updating the line would do. Here is an example of how this works to print integers from 1 to 30 every second without scrolling the console window:
 
        local
            line, blank: STRING
        do
                -- Initialize a blank line with a trailing carriage return.
            create blank.make_filled (' ', 80)
            blank.append_character ('%R')
                -- Make the line to be printed of the same length.
            create line.make (blank.count)
                -- Print integers from 1 to 30 without scrolling.
            across
                1 |..| 30 as i
            loop
                line.wipe_out
                line.append_integer (i.item)
                line.append_substring (blank, line.count, blank.count)
                io.put_string (line)
                {EXECUTION_ENVIRONMENT}.sleep (1_000_000_000)
            end
            io.put_new_line
        end
 
Regards,
Alexander Kogtenkov
 
 
Воскресенье, 16 февраля 2020, 10:29 +03:00 от karsten...@gmx.de:
 
--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Finnian Reilly

unread,
Feb 16, 2020, 8:35:58 AM2/16/20
to eiffel...@googlegroups.com

Karsten...@gmx.de

unread,
Feb 16, 2020, 12:48:19 PM2/16/20
to eiffel...@googlegroups.com
Dear Alexander,

thanks for the suggestions.
I will try the single-line-approach
for the lightweight example.

Dear Finnian,

I guess using your classes
would make the small example too bulky.
No harm meant!

Regards,
Karsten

Gachoud Philippe

unread,
Feb 16, 2020, 5:52:28 PM2/16/20
to eiffel...@googlegroups.com, karsten...@gmx.de
@karsten...@gmx.de
  I'm on it too.... we'll se which of both horses between you and me will get it ;-) maybe {NONE}

my current version is still on development on


the user_friendly_version branch





--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Gachoud Philippe

unread,
Feb 16, 2020, 7:38:22 PM2/16/20
to Eiffel Users
Into the current version I'm stuck, the displayer seems released only once all the horses finished their run. (reaching the first all_horses_reached_end -> horse.has_finished)

I'm unable to understand well what is a blocking call and a non blocking one. 

I tried with both horses: LINKED_LIST[separate HORSE] and horses: separate LINKDED_LIST[separate HORSE]. The rest of the code if needed is on 




class
APPLICATION

inherit
FACILITY_USER

create
make

feature {NONE} -- Initialization

make
local
l_finished: BOOLEAN
l_horse: like horses.item
l_s: STRING
l_displayer: separate STATUS_DISPLAYER[like horses.item]
do
io.put_string ("************** Race start ****************** %N")
set_random

-- Put all horses in the turf.
create horses.make
create l_displayer.make (horses)

separate
horses as l_horses_sep,
l_displayer as l_displayer_sep
do
across 1 |..| 5 is l_horse_id loop
random.forth
create l_horse.make (l_horse_id, random.item \\ {HORSE}.Max_speed + 1)
l_horses_sep.extend (l_horse)
end

l_displayer_sep.set_show_status (True)

io.put_string (" ---------> Starting all horses%N")
-- Make all horses run.

across
l_horses_sep is l_horse_item
loop
separate l_horse_item as l_horse_sep do
l_horse_sep.run
end
end
io.put_string (" ---------> All horses started%N")

-- wait for finish
from
until
all_horses_reached_end
loop
wait (1_000)
end
l_displayer_sep.set_show_status (False)
end

io.put_string ("************** Race end ****************** %N%N")
end

feature -- Access

horses: separate LINKED_LIST[separate HORSE]

random: RANDOM

feature {NONE} -- Implementation


set_random
local
l_random: RANDOM
l_time: TIME
do
create l_time.make_now
create random.make
random.set_seed (l_time.milli_second \\ 100)
random.forth
end

all_horses_reached_end: BOOLEAN
local
l_s: STRING
do
Result := True
separate horses as l_horses_sep do
across
l_horses_sep is l_horse_item
until
not Result
loop
separate l_horse_item as l_horse_sep do
create l_s.make_from_separate (l_horse_sep.out)
io.put_string ("all_horses_reached_end:" + l_s + "%N")
Result := l_horse_sep.has_finished
end
end
end
end



On Sunday, February 16, 2020 at 10:52:28 PM UTC, Gachoud Philippe wrote:
@karsten...@gmx.de
  I'm on it too.... we'll se which of both horses between you and me will get it ;-) maybe {NONE}

my current version is still on development on


the user_friendly_version branch





On Sat, Feb 15, 2020 at 2:25 PM <Karsten...@gmx.de> wrote:
Does anybody know how to send the escape sequences
that are listed at
https://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html
to the console? I think this would help Philippe.

@Philippe: Your first version worked
because APPLICATION did NOT query the horses' states
while they were running.
THEY reported their status by themselves, instead.

As I am also new to SCOOP I do not know
if there is a kind of shared memory
where the horses could leave their status messages,
which then could be queried and displayed by APPLICATION
without waiting for the horses to finish their runs.

Best,
Karsten

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

Karsten...@gmx.de

unread,
Feb 16, 2020, 11:05:18 PM2/16/20
to eiffel...@googlegroups.com
My gut says the blocker is l_horse_sep.out in all_horses_reached_end.
Unfortunately, I do not have the time to look into it this week.

Good luck,
Karsten

Alexander Kogtenkov

unread,
Feb 17, 2020, 3:17:53 AM2/17/20
to eiffel...@googlegroups.com
One issue is that the list of horses is locked by the application in the separate instruction. As a result, the displayer can access it only after the list is released, i.e. just before the end of APPLICATION.make, when all horses have finished.
 
Regards,
Alexander Kogtenkov
 
 
Gachoud Philippe <ph.ga...@gmail.com>:
 
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.


--
**********************************************
Philippe Gachoud
Puerto Williams 6657
Las Condes
Santiago de Chile
+56 934022210
ph.ga...@gmail.com
**********************************************
 

 

--

You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/428b83a2-b885-41f4-b479-807b37b58696%40googlegroups.com.
 

Karsten...@gmx.de

unread,
Feb 17, 2020, 12:26:45 PM2/17/20
to eiffel...@googlegroups.com
Dear Alexander,

I tried the single-line approach as you suggested.
However, the access to the `reporting_line',
which is shared between the application and all horses,
makes the application hang forever.

The issue is located in HORSE's `report_progress'.
Trying to control the access to `reporting_line'
I used the following separate instruction:

separate reporting_line as srl do
create l_string.make_from_separate (srl)
print (l_string)
end

Unfortunately, print (l_string) is never reached.

I would appreciate it if you could have a look
at the 2-classes system scoop_horses
at http://t1p.de/b64o .

Thank you very much again.
Best,
Karsten

Gachoud Philippe

unread,
Feb 17, 2020, 2:08:43 PM2/17/20
to Eiffel Users
In my version, If I comment out the waiting for finish the run is working (I let the pretty terminal output for another time) but when I uncomment it out the race is never starting :-(

and that in either version of taking separate each time I needed separatedly or globaly as Alexander told

The code is up to date into the sf repo


Globally for more concise writting

-- wait for finish, if enabled horses don't run :-(
-- from
-- until
-- all_horses_reached_end
-- loop
-- wait (1_000)
-- end
-- l_displayer_sep.set_show_status (False)
end

io.put_string ("************** Race end ****************** %N%N")
end


Separated for try
io.put_string ("************** Race start ****************** %N")
set_random

-- Put all horses in the turf.
create horses.make
create l_displayer.make (horses)

across 1 |..| 5 is l_horse_id loop
random.forth
create l_horse.make (l_horse_id, random.item \\ {HORSE}.Max_speed + 1)
separate
horses as l_horses_sep
do
l_horses_sep.extend (l_horse)
end
end

separate
l_displayer as l_displayer_sep
do
l_displayer_sep.set_show_status (True)
end

-- Make all horses run.
io.put_string (" ---------> Starting all horses%N")
-- separate_do_all (horses, agent (l_item: separate like horses.item) do separate l_item as l_item_sep do l_item_sep.run end end) -- not working
separate -- working
horses as l_horses_sep
do
across
l_horses_sep is l_horse_item
loop
separate l_horse_item as l_horse_sep do
l_horse_sep.run
end
end
end
io.put_string (" ---------> All horses started%N")

-- wait for finish
-- from
-- until
-- all_horses_reached_end
-- loop
-- wait (1_000)
-- end
-- separate
-- l_displayer as l_displayer_sep
-- do
-- l_displayer_sep.set_show_status (False)
-- end

io.put_string ("************** Race end ****************** %N%N")

Karsten...@gmx.de

unread,
Feb 18, 2020, 12:19:14 AM2/18/20
to eiffel...@googlegroups.com
`horses', i.e. the list containing all horses,
should not be separate, as Alexander suggested:
horses: LINKED_LIST [separate HORSE] instead of
horses: separate LINKED_LIST [separate HORSE].

Best,
Karsten

Alexander Kogtenkov

unread,
Feb 18, 2020, 2:54:05 AM2/18/20
to eiffel...@googlegroups.com
The issue is that although `reporting_line` is declared as separate, the object is associated with the region of APPLICATION:
 
            reporting_line := (create {STRING}.make_filled ('_', Reporting_line_length - 1)) + "%N"
 
Then, the call `has_horse_finished (horses.last)` waits for the last horse to reach the finish, whereas the horse attempts to access `reporting_line` in
 
            separate reporting_line as srl do
                create l_string.make_from_separate (srl)
                print (l_string)
            end

where you observed that the execution hangs. This is a classical deadlock involving regions of APPLICATION and HORSE.
 
Replacing the initialization of `reporting_line` with
 
            create reporting_line.make_filled ('_', Reporting_line_length - 1)
            separate reporting_line as s do
                s.append_character ('%N')
            end
 
resolves the issue.
 
As a side note, I would replace the busy wait in HORSE.stuggle
 
   across 0 |..| slowness as cur loop do_nothing end
 
with something more CPU-friendly and machine-speed-independent:
 
   {EXECUTION_ENVIRONMENT}.sleep ({INTEGER_64} 40_000 * slowness)
 
Regards,
Alexander Kogtenkov
 
 
Понедельник, 17 февраля 2020, 20:26 +03:00 от karsten...@gmx.de:
 
--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Gachoud Philippe

unread,
Feb 18, 2020, 4:04:02 AM2/18/20
to Eiffel Users
Actually its not possible to have the horses as non separate while the displayer: STATUS_DISPLAYER is separate. For me it makes sense as the displayer should be separate and giving it an access to horses list they both have to be in their respective region to guarantee mutual exclusion while horses are running and displayer is displaying statuses. But maybe I'm wrong in my thinking.

So what you suggest does a compilation error (Formal argument or tuple field of a separate call should be of a separate type if the actual argument or the source expression is of reference type) on create l_displayer.make (horses)

Gachoud Philippe

unread,
Feb 18, 2020, 4:33:21 AM2/18/20
to Eiffel Users
Non separate horses and displayer

making non separate horses and displayer into this current version reaches a dead lock too and I don't understand why :-( it seems that after `l_displayer.set_show_status (True)` the execution stops even if in my mind all horses are not holded anymore. Anybody can help me please? I really like to understand scoop to be able to implement it into my professional field applications.

make
local
l_all_finished: BOOLEAN
l_horse: like horses.item
l_s: STRING
l_displayer: STATUS_DISPLAYER[like horses.item]
do
set_random -- initializes random attribute
io.put_string ("************** Race start ********************************************** %N")

-- Put all horses in the turf.
create horses.make
across 1 |..| 5 is l_horse_id loop
random.forth
create l_horse.make (l_horse_id, random.item \\ {HORSE}.Max_speed + 1)
horses.extend (l_horse)
end

-- Make all horses run.
io.put_string (" ---------> Starting all horses%N")
across
horses is l_horse_item
loop
separate l_horse_item as l_horse_sep do
l_horse_sep.run
end
end
io.put_string (" ---------> All horses started%N")

-- displayer
create l_displayer.make (horses)
io.put_string (" ---------> after l_displayer make%N")
l_displayer.set_show_status (True)
io.put_string (" ---------> after l_displayer set_show_status%N") -- never reached
from
until
all_horses_reached_end
loop
wait (1_000)
end
io.put_string ("all_horses_reached_end after loop")
l_displayer.set_show_status (False)

io.put_string ("************** Race end ******************************************************* %N%N")
end

Finnian Reilly

unread,
Feb 19, 2020, 12:00:46 PM2/19/20
to eiffel...@googlegroups.com

Horse Race: Scoop Vs EL_PROCEDURE_DISTRIBUTER

Looking at this thread I get the impression that Scoop is not that intuitive or easy to understand. I present my own solution using the class EL_PROCEDURE_DISTRIBUTER from Eiffel-Loop. EL_PROCEDURE_DISTRIBUTER hides the trickly implementation details of distributing work across a pool of threads.

See classes HORSE_RACE_APP and HORSE.

Which do you think is the easiest to understand?

-- Finnian Reilly

Simulated
        horse race

Karsten...@gmx.de

unread,
Feb 19, 2020, 12:55:34 PM2/19/20
to eiffel...@googlegroups.com
@Alexander: Thank you very much for inspecting the code.
Your effort is highly appreciated!
Unfortunately, your suggestion did not prevent the deadlock.
The tricky parts are commented in boxes in
http://t1p.de/b64o > scoop_horses > horse.e.
I hope I will find the time to make
`reporting_line' independent of APPLICATION
and, thereby, circumvent the deadlock issue.
Your suggestion #1 will serve as guideline:
horse1, horse2, .. horseN ===> state keeper and printer

@Philippe: I am still struggling with SCOOP's basics.
I wish I could help you out. Maybe in the future ;-)

@Finnian: Good job! The result looks even better than
what we want to achieve using SCOOP with a minimal example.
 
Regards,
Karsten

Alexander Kogtenkov

unread,
Feb 19, 2020, 2:52:35 PM2/19/20
to eiffel...@googlegroups.com
Dear Karsten,
 
You must have missed the key point of my previous message: replacing initialization of `reporting_line` with the code in the messages fixes the deadlock. Looking in the link, the change was not applied (it would be just copy/paste from the message to the source, nothing else): the code at the link still creates a string associated with APPLICATION.
 
Regards,
Alexander Kogtenkov
 
 
--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Karsten...@gmx.de

unread,
Feb 20, 2020, 12:06:17 PM2/20/20
to eiffel...@googlegroups.com
Dear Alexander,

in fact, I did not realize that there is a difference
between two versions of instantiation
with sep_string declared as
sep_string: separate STRING.

(1) sep_string := create {STRING}.make_filled ('_', 10)
(2) create sep_string.make_filled ('_', 10)

Are the following assumptions correct?
(a) In case (1) the dynamic type of sep_string is STRING
instead of separate STRING.
(b) STRING conforms to separate STRING, therefore,
assignment (1) is allowed but not the other way around.
(c) If the dynamic type of a separate STRING is STRING
then this string is associated with the processor
that also handles the client of this string.
(d) (c) is the reason for the deadlock.

Are the following assumptions correct?
(e) In case (2) the dynamic type of sep_string is separate STRING.
(f) In case (2) sep_string is not regarded as
state-defining attribute of the client.
Otherwise, the deadlock would persist.

--

I changed the creation version from (1) to (2) as you suggested.
Unfortunately, C compilation (GCC) breaks off
complaining 'l_scoop_processor_id' undeclared.
Cleaning up (deleting EIFGENs) did not help.
Using only 1 of my machines 8 processors did not help.
I really would like to see this minimal example work
( http://t1p.de/b64o ).

Regards,
Karsten

Alexander Kogtenkov

unread,
Feb 20, 2020, 1:20:42 PM2/20/20
to eiffel...@googlegroups.com
Dear Karsten,
 
It’s great that you discovered the difference. Indeed, it matters whether the type used for creating an output string is separate or not.
 
(a) Yes, the dynamic type could be separate or not. So, if an explicit type is specified when initializing an entity of a separate type, the separateness status of the explicit type is used regardless of the type of the entity.
 
(b) Right, a type conforms to the separate version of the same type. But the separate version does not conform to the regular one.
 
(c) A declared (compile-time) type specifies only potential behavior of the corresponding object at run-time. If the declared type is non-separate, the object always belongs to the same region/processor as the object that was associated with Current during creation. However, if the declared type is separate, the run-time type could be either separate (handled by a different processor or belonging to a different region), or not. In the latter case its behavior is as if it had been declared as non-separate.
 
(d) Yes, that caused the deadlock: the string and the application were handled by the same processor (say, A). And while an application was waiting for a horse to obtain its status, the horse (running on another processor B) was waiting for the string. In other words, A was waiting for B and B was waiting for A.
 
(e) Yes, the type of the object created with `create x` is the declared type of `x`.
 
(f) I’m not sure what stands behind "state-defining attribute of the client", but in case (2), the type of the created object is separate, so it runs independently of the application. As a result, the application can safely wait for a horse to get its status, while the horse updates the line to be printed and prints it. Because the string and the application are operated by different processors, there is no deadlock anymore.
 
To summarize, your original code was absolutely correct except for initialization of the output string that despite being declared as separate, was created as non-separate.
 
Hope this helps,
Alexander Kogtenkov
 
 
karsten...@gmx.de:

Gachoud Philippe

unread,
Feb 21, 2020, 11:05:44 AM2/21/20
to Eiffel Users
Dear Finnian, 

your example is amazing!! Thx a lot for this.

Unfortunately what was intended for me and I think Karsten is to keep simple to understand scoop in its basics and in your example the underground things are hidden in your library. At first view, I'm unable to apply your example to my code to correct my error and being the goal for me of the horses_run to learn scoop I'm still stuck  in a dead-lock I don't understand. 

In all cases I'll review your code and details which are always for me a source of inspiration.

Many thx for the time you dedicated in helping us.

Alexander Kogtenkov

unread,
Feb 21, 2020, 11:12:42 AM2/21/20
to eiffel...@googlegroups.com
Last time, when I tried to compile and run your example, it seemed to be working as expected. I was using the code from the link mentioned in your email. So, I was sure, everything is fine. If this is not true, would it be possible to have the source code with the problem?
 
Alexander Kogtenkov
 
 
Gachoud Philippe <ph.ga...@gmail.com>:
 
--

You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Gachoud Philippe

unread,
Feb 21, 2020, 11:53:37 AM2/21/20
to Eiffel Users
Hi Alexander,

with great pleasure. 
I actually have different versions (branches) at this point which are all on sourceforge
  1. The master points to the simplest_version -> https://sourceforge.net/p/eiffel-scoop-horse-run/code/ci/master/tree/
  2. The simplest_version (the goal is the most simple version for news to scoop) -> https://sourceforge.net/p/eiffel-scoop-horse-run/code/ci/simplest_version/tree/
  3. The user_friendly_version (which is way from finnian's one but with status displayer) https://sourceforge.net/p/eiffel-scoop-horse-run/code/ci/user_friendly_version/tree/
  4. The dev which is my current tries and status version https://sourceforge.net/p/eiffel-scoop-horse-run/code/ci/dev/tree/
I think you tried the user_friendly_version which runs but never ends :-(((

into the dev version I tried to make it even simpler with only 2 horses into make->simple_horses_run without linked_list to avoid dead locks into the linked_list my current version and working / struggling with it

Most probably the user_friendly_version solved would help me tu understand my error probably dead lock

Many thx for your precious help Alexander, hope its easy for you to get the source from sourceforge actually a

git clone git://git.code.sf.net/p/eiffel-scoop-horse-run/code eiffel-scoop-horse-run-code
cd eiffel-scoop-horse-run-code/
git checkout user_friendly_version

Should do it



On Friday, February 21, 2020 at 1:12:42 PM UTC-3, Alexander Kogtenkov wrote:
Last time, when I tried to compile and run your example, it seemed to be working as expected. I was using the code from the link mentioned in your email. So, I was sure, everything is fine. If this is not true, would it be possible to have the source code with the problem?
 
Alexander Kogtenkov
 
 
Gachoud Philippe <ph.g...@gmail.com>:
 
Dear Finnian, 
 
your example is amazing!! Thx a lot for this.
 
Unfortunately what was intended for me and I think Karsten is to keep simple to understand scoop in its basics and in your example the underground things are hidden in your library. At first view, I'm unable to apply your example to my code to correct my error and being the goal for me of the horses_run to learn scoop I'm still stuck  in a dead-lock I don't understand. 
 
In all cases I'll review your code and details which are always for me a source of inspiration.
 
Many thx for the time you dedicated in helping us.

On Wednesday, February 19, 2020 at 2:00:46 PM UTC-3, Finnian Reilly wrote:

Horse Race: Scoop Vs EL_PROCEDURE_DISTRIBUTER

Looking at this thread I get the impression that Scoop is not that intuitive or easy to understand. I present my own solution using the class EL_PROCEDURE_DISTRIBUTER from Eiffel-Loop. EL_PROCEDURE_DISTRIBUTER hides the trickly implementation details of distributing work across a pool of threads.

See classes HORSE_RACE_APP and HORSE.

Which do you think is the easiest to understand?

-- Finnian Reilly

Simulated
        horse race

 

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

Gachoud Philippe

unread,
Feb 21, 2020, 6:44:56 PM2/21/20
to Eiffel Users
Working around and around, and trying to get any working strategy, 

I think or thought one error of mine is to try to get status of each horse while they are running...
as far as I understood 
1. a horse or process (or so called processor) cannot be reached by the displayer (processor.any_feature even if its a function) while its running (seems blocked on the separate statement of the displayer.io_show_status -> separate l_item as l_item_sep) while the l_item_sep.run procedure is running)
2. The displayer called after into the APPLICATION.make_simple waits for the horses to terminate their run
3. a) The l_displayer and horses are of APPLICATION processor (or region, as I don't know if there is a distinction between the two) as they are not declared as separate they belong to the APPLICATION instance processor
    b) The h1: separate HORSE belongs to a separate processor lets call it h1_processor
    c) The h2: separate HORSE belongs to a separate processor lets call it h2_processor
    so while h1 and h2 are not released (as far as I understood that the run procedure call terminates) l_displayer.items cannot access to h1 and h2 as they are locked because running or doing any process

So my question so far would be if I understood well and correct me please if I'm wrong would be: Is there a way to access h1 and h2 while they are running (i.e.: HORSE.run is not terminated)?

git clone https://git.code.sf.net/p/eiffel-scoop-horse-run/code eiffel-scoop-horse-run-code
git checkout dev





simple_horses_run
local
l_displayer: STATUS_DISPLAYER
h1, h2: separate HORSE
l_s: STRING
do
create horses.make -- for void Safety
io.put_string ("************** simple_horses_run start ********************************************** %N")
set_random

create h1.make (1, random.item \\ {HORSE}.Max_speed + 1)
create h2.make (2, random.item \\ {HORSE}.Max_speed + 1)
horses.extend (h1)
horses.extend (h2)
-- RUN
separate h1 as l_h do
io.put_string ("starting h1 run%N")
l_h.run
end
io.put_string ("after h1 run%N")
separate h2 as l_h do
io.put_string ("starting h2 run%N")
l_h.run
end
io.put_string ("after h2 run%N")


-- Displayer
io.put_string ("creating l_displayer%N")
create l_displayer.make (horses)
l_displayer.io_show_status -- reached only when h1.run and h2.run procedure are finished and h1 and h1 are released
io.put_string ("l_displayer after io_show_status%N")

io.put_string ("************** simple_horses_run end ********************************************** %N")
end


Many thx for your help

Alexander Kogtenkov

unread,
Feb 22, 2020, 4:58:01 AM2/22/20
to eiffel...@googlegroups.com
So far I was able to compile and run the application, and could see exactly the problem you are describing: if a horse is executing the feature "run", no other processor can reach it. It becomes accessible only when "run" terminates.
 
In some other message to the mailing list there was a discussion about different possibilities how to overcome the issue. In the particular example, I imagine the following approaches:
  1. Create a set of independent separate objects that will be used to store the state of a horse. The objects will be reachable from horses (one state object per one horse) and from the displayer (all state objects). The feature "run" will update the state on every step, and the displayer will retrieve it on every step. Because the state object is idle most of the time, the information will be accessible most of the time.
  2. Record the state in the displayer directly. The displayer will not have any active behavior, it will only render current state of all horses after every update from a horse. This is similar to the solution developed by Karsten.
The first approach follows the "pull" model: the displayer goes around all state objects and asks for the current horse position. The second approach follows the "push" model: the horses inform about their positions directly. In the first approach it’s much easier to have a notion of the update rate, similar to the frame rate used in games. The second approach is easier in terms of the number of classes, objects and their interaction.
 
Hope this helps,
Alexander Kogtenkov
 
 
Gachoud Philippe <ph.ga...@gmail.com>:
 
Gachoud Philippe <ph.g...@gmail.com>:
 
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
 

 

--

You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/f0991868-b972-481b-af17-e6e41bff5241%40googlegroups.com.
 
 

Finnian Reilly

unread,
Feb 22, 2020, 7:53:44 AM2/22/20
to eiffel...@googlegroups.com
Dear Gachoud,
thank you for the compliment. I know my example will not help you to understand Scoop, but really I just wanted to show that the classic thread model still has it's merits. The Scoop model is being presented as an easier way to reason about multi-threading, with all the difficult synchronization tasks handled for you behind the scenes by the compiler. But still I see people struggling with it, and when I looked at it myself, I found the details not easy to grasp with such concepts as regions etc.

The point of my example is to show that a well designed library using classic threads need not be difficult. Class EL_WORK_DISTRIBUTER (the parent of EL_PROCEDURE_DISTRIBUTER and EL_FUNCTION_DISTRIBUTER) is intended to solve for all scenarios the problem of distributing work across a pool of threads. So long as you follow the simple interface rules that govern it, it is not necessary to understand what is going on "beneath the hood". The only thing you have to anticipate are objects that might be simultaneously accessed by competing threads and protect them with a mutex. The other Eiffel-Loop classes for managing mutexs etc (EL_MUTEX_REFERENCE for example) are intended to make classic threads more amenable.

regards
Finnian

Karsten...@gmx.de

unread,
Feb 22, 2020, 11:23:41 AM2/22/20
to eiffel...@googlegroups.com
Dear SCOOPers,

after several nights of asynchronous dreams
I finally got it to work :-)
Thank you all for your help!
Alexander, you're simply the best!

Please find the example at http://t1p.de/b64o in scoop_horses.zip.

Alexander, EiffelStudio 18.07 (Win 64) seems to produce faulty C code
when using the separate instruction under some circumstances.
Please see the comments in HORSE's report_progress.
Am I the culprit?

Thanks again.
Best,
Karsten

Alexander Kogtenkov

unread,
Feb 22, 2020, 12:10:33 PM2/22/20
to eiffel...@googlegroups.com
I guess, the bug was fixed in EiffelStudio 19.05 (look for the entry bug#19507 in https://dev.eiffel.com/EiffelStudio_19.05_Releases). It’s one of the reasons why it’s recommended to use recent EiffelStudio whenever possible: there are fewer potential issues.
 
Alexander Kogtenkov
 
 
karsten...@gmx.de:
 
--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Gachoud Philippe

unread,
Feb 22, 2020, 1:21:16 PM2/22/20
to Eiffel Users
Dear Alexander,

Many thanks for your reply and review and precious help, actually you gave me the point that made me solve my problems and have finally a working "simple as possible" example. It's not easy to know what is the most simple example with eiffel for me as contract is always something I'm used to but adds more code... lets hope I kept as concise as possible, anybody feel free to give me any feedback.

I opted for your second option which seemed to keep the example as simple as possible (as I seem needed in my steps of learning). But was frustrated to having the sensation to go back to a procedural model which by instinct of object oriented model sent me to the no way path I was going before your explanation. But I think as an exercise to understand better the scoop model I'll add a branch to the project with the other model (option 1 of your explanation) which seems more object oriented as much as I conceive it.

Sourceforge version
I updated the sourceforge project and hope it will be useful for some others (don't pretend nothing but could be helpful in the ISE eiffel examples too, feel free to add it if it makes sense for the people in charge of that, and of course change/review it).
The current version of the sourceforge project is with master pointing on `user_friendly_version`.


As a result of my understanding at this step, I could say (correct me if I'm wrong) that a separate object instance can only run one feature at a time, the way to check the same instance status for example would be to use another object that keeps it. Reading the documentation on scoop and seing the tutorials I understood that attribute and function calling could have been done in parallel. 

Many thx again, hope this helps @karsten too.

Philippe
Gachoud Philippe <ph.ga...@gmail.com>:
 
Gachoud Philippe <ph.g...@gmail.com>:
 
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

 

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users+unsubscribe@googlegroups.com.

Bertrand Meyer

unread,
Feb 22, 2020, 2:30:38 PM2/22/20
to eiffel...@googlegroups.com, me...@inf.ethz.ch

It should have happened long ago but eventually I will publish a book on SCOOP programming; these discussions are very useful to reflect what goes in the mind who start with the approach. Thanks too for making your code public.

 

-- BM

Gachoud Philippe <ph.ga...@gmail.com>:
 

Gachoud Philippe <ph.g...@gmail.com>:
 

To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.

To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

 

 

--

You received this message because you are subscribed to the Google Groups "Eiffel Users" group.

To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/dcb0b320-08ec-4195-b324-48a9d18d5923%40googlegroups.com.

Eric Bezault

unread,
Feb 23, 2020, 6:36:23 PM2/23/20
to eiffel...@googlegroups.com, Bertrand Meyer, me...@inf.ethz.ch
On 22/02/2020 20:30, Bertrand Meyer wrote:
> It should have happened long ago but eventually I will publish a book on
> SCOOP programming; these discussions are very useful to reflect what
> goes in the mind who start with the approach. Thanks too for making your
> code public.

Did anyone tried to use agents in a SCOOP project? I'm struggling with
that. EiffelVision2 is driven by events through descendants of
ACTION_SEQUENCE. But ACTION_SEQUENCE contains PROCEDURE, not
'separate PROCEDURE'. So you cannot pass to EiffelVision's widgets
agents from another SCOOP region. I then tried to add an indirection:

my_button.select_actions.extend (agent on_click)

my_separate_action: separate PROCEDURE

on_click (...)
do
separate
my_separate_action as l_action
do
l_action.call ([...])
end
end

But that still does not work because the tuple passed as argument is
not separate (whereas the target of the call is). But if I pass a
hand-made separate TUPLE, then the compiler will say that it does not
conform to the type of the formal argument of `call` which is not
separate. And I assume that I cannot declare:

my_separate_action: separate PROCEDURE [separate TUPLE]

because 'separate TUPLE' does not conform to the generic constraint
which is not separate.

So far, my workaround is not to use agents in that case, but use
regular calls.

I'm glad to hear that there will be a book on SCOOP.
Any estimate on when it will be ready?

--
Eric Bezault
mailto:er...@gobosoft.com
http://www.gobosoft.com

Gachoud Philippe

unread,
Feb 24, 2020, 10:38:44 AM2/24/20
to Eiffel Users
Dear Eric,

in my sample of horse run I use an agent called at the end of the horse run with a displaying of the horse end, but think your case is more complex because as far as I understand (never used EiffelVision) you need to deal with separate agents which is not the case of my example.

Hope you'll get an answer if its doable to have EiffelVision separate agents as arguments without a complete refactor of EiffelVision.

Bertrand Meyer

unread,
Feb 24, 2020, 10:57:38 AM2/24/20
to Eric Bezault, eiffel...@googlegroups.com, me...@inf.ethz.ch
Dear Eric,

> I'm glad to hear that there will be a book on SCOOP.

Thanks.

> Any estimate on when it will be ready?

The prudent answer is no. Giving estimates takes less effort than writing the book, but one without the other is not useful. I am doing my best.

Thanks,

-- BM




Eric Bezault

unread,
Feb 24, 2020, 6:00:42 PM2/24/20
to eiffel...@googlegroups.com, Bertrand Meyer, me...@inf.ethz.ch
On 24/02/2020 0:36, Eric Bezault wrote:
> Did anyone tried to use agents in a SCOOP project? I'm struggling with
> that. EiffelVision2 is driven by events through descendants of
> ACTION_SEQUENCE. But ACTION_SEQUENCE contains PROCEDURE, not
> 'separate PROCEDURE'. So you cannot pass to EiffelVision's widgets
> agents from another SCOOP region. I then tried to add an indirection:
>
>    my_button.select_actions.extend (agent on_click)
>
>    my_separate_action: separate PROCEDURE
>
>    on_click (...)
>       do
>           separate
>                my_separate_action as l_action
>           do
>                l_action.call ([...])
>           end
>       end
>
> But that still does not work because the tuple passed as argument is
> not separate (whereas the target of the call is).

Today I realized that the formal argument of PROCEDURE.call is declared
as separate. So I tried to recompile from scratch (thanks a a nice
button in EiffelStudio :-)) and the compiler stopped complaining.

However I think I found a bug. If I have, in region R1:

my_separate_action: separate PROCEDURE [STRING]

set_my_separate_action (a_action: like my_separate_action)
do
my_separate_action := a_action
end

on_click (...)
local
l_my_string: STRING
do
separate
my_separate_action as l_action
do
create l_my_string.make_from_string ("scoop")
l_action.call ([l_my_string])
end
end

And then in region R2:

my_window: separate FOO

initialize
do
separate
my_window as l_window
do
l_window.set_my_separate_action (agent my_routine)
end
end

my_routine (a_string: STRING)
do
print (a_string)
end

The compiler accepts this code, even after recompiling from scratch.
But when `on_click` is called we end up calling `my_routine` in
region R2 with a non-separate formal argument whereas the actual
argument was created in region R1. I think that the compiler should
have forced me to declare `my_routine` as follows:

my_routine (a_string: separate STRING)
do
print (create {STRING}.make_from_separate (a_string))
end

Did I miss something?

Gachoud Philippe

unread,
Feb 24, 2020, 6:45:09 PM2/24/20
to Eiffel Users
Horse run with method 1 of Alexander recommendations

Now available on branch state_objects_example

git clone git://git.code.sf.net/p/eiffel-scoop-horse-run/code eiffel-scoop-horse-run-code;
git checkout
state_objects_example

I think I kept it simple if explained well for a beginner, any comment is welcome on the choices if this implementation. I documented within a README.md both models with illustrations and my words and current understanding, hope it helps, any correction is also welcome.

Separate agents?? How to deal with them...

Actually I'm encountering something similar implementing Alexander's first option with a given agent as parameter to a separate object, as the compiler requires. I don't know if its a syntax problem but declaring as parameter from make a 

separate PROCEDURE[separate TUPLE]

I'm unable to assign it on call as

create l_displayer.make (
status_keepers,
separate agent do io.put_string ("************** simple_horses_run end ****************** %N") end -- complaining here
)

1) Syntax error is given. Any workaround or solution for that? creating a PROCEDURE with set_rout_disp or set_rout_disp_final is for me too complicated...
2) I don't really understand the semantic reason of having to have separate arguments for a separate object creation, anybody can point me out any documentation or explanation about that? I guess it has to do with processors associations of object instances.


class STATUS_DISPLAYER

feature {NONE} -- Initialize

make (a_status_keepers: like status_keepers; a_all_horses_finished_agent: like all_horses_finished_agent)
do
create horses_ranking.make
status_keepers := a_status_keepers
all_horses_finished_agent := a_all_horses_finished_agent
ensure
status_keepers = a_status_keepers
end

feature -- Access

all_horses_finished_agent: separate PROCEDURE[separate TUPLE] -- agent called by set_horse_position once all horses have finished running

Alexander Kogtenkov

unread,
Feb 25, 2020, 6:31:30 AM2/25/20
to eiffel...@googlegroups.com
Dear Eric,
 
Your reasoning looks correct. There were debates related to agents in SCOOP, how to handle them, how to set separateness status of arguments, etc. As a result, there were some changes in the semantics and validity rules along the way. Probably, the bug slipped into during such a change. This is not an excuse, just a comment that making everything right and efficient in SCOOP takes some time.
 
Thank you for your feedback,
Alexander Kogtenkov
 
 
Eric Bezault <er...@gobosoft.com>:

Karsten...@gmx.de

unread,
Feb 25, 2020, 9:54:30 AM2/25/20
to eiffel...@googlegroups.com
Dear Alexander,

I successfully implemented your suggestion #3:
horse1, horse2, … horseN ===> state of all horses <=== printer
(see http://t1p.de/b64o folder scoop_horses.zip\2020-02-25).

Storage for exchange of the 'state of all horses'
between all horses and the reporter is currently declared
in 3! classes (APPLICATION, HORSE, and REPORTER) as
bus: separate ARRAY [INTEGER].

The application creates the bus and, then,
passes it to all horses and the reporter
while they are created by the application.
Thus, the bus is shared between them as expected.

Although the scheme works, it is not elegant.
A better solution would be to have a common ancester SHARED
with the following once function:

bus: separate ARRAY [INTEGER]
-- Shared storage for horses' states.
once ("SYSTEM")
create Result.make_filled (0, 1, Horse_count)
-- Example: 6 horses, slowest horse #3, fastest horse #6.
-- .-----------------------.
-- | 1 | 4 | 0 | 7 | 3 | 9 | Completed rounds
-- `-----------------------´
-- 1 2 3 4 5 6 Horse IDs
end

Unfortunately, the once key "SYSTEM" is not allowed.
Thus, every region gets its own bus :-(

What is the best way to instantiate a separate object
meant to be the communication bus between several/many
separate objects?

Thank you very much,
Karsten

Anders Persson

unread,
Feb 25, 2020, 11:39:37 AM2/25/20
to Eiffel Users
Hi

Try with

once ("PROCESS")

Vänligen

Anders Persson
+46 763 17 23 25





--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.

Gachoud Philippe

unread,
Feb 25, 2020, 12:10:58 PM2/25/20
to eiffel...@googlegroups.com
Actually as far as I understood SCOOP is implemented with THREADS so PROCESS is the keyword for "SYSTEM" which is the executable instance of your app, I also have a ONCE in my example within STATUS_KEEPER class



--
**********************************************
Philippe Gachoud
Puerto Williams 6657
Las Condes
Santiago de Chile
+56 934022210
ph.ga...@gmail.com
**********************************************

Karsten...@gmx.de

unread,
Feb 25, 2020, 12:42:43 PM2/25/20
to eiffel...@googlegroups.com
Thank you guys!
I did not expect PROCESS=SYSTEM in SCOOP applications,
as the first what SCOOP noobs have to learn
is that regions have their own processors :-)

Best,
Karsten

Karsten...@gmx.de

unread,
Feb 26, 2020, 6:49:44 AM2/26/20
to eiffel...@googlegroups.com
Dear Philippe,

I had a look at your design (and the cute horse images :)
and compared it with mine, see http://t1p.de/b64o
folder scoop_horses.zip\2020-02-26\Comparison.png).
@All: Please feel free to use the code in any way you want.

The main differences are:

1) In your system each horse has its own separate state keeper,
whereas in my system one single shared bus
(separate ARRAY [INTEGER]) takes this role.

2) In your system the number of rounds is defined in HORSE
and passed to the displayer during run time.
In my system constants are shared by inheriting from SHARED.

Thank you very much for your efforts and support.
@Alexander: The same to you!
I learned a lot!

Best,
Karsten

Gachoud Philippe

unread,
Feb 26, 2020, 7:06:00 AM2/26/20
to eiffel...@googlegroups.com
Hi Karsten,

thx for your sharing

On Wed, Feb 26, 2020 at 8:49 AM <Karsten...@gmx.de> wrote:
Dear Philippe,

I had a look at your design (and the cute horse images :)
and compared it with mine, see http://t1p.de/b64o
folder scoop_horses.zip\2020-02-26\Comparison.png).
@All: Please feel free to use the code in any way you want.

The main differences are:

1) In your system each horse has its own separate state keeper,
whereas in my system one single shared bus
(separate ARRAY [INTEGER]) takes this role.
Same for me in the user_friendly_version which takes this approach too

2) In your system the number of rounds is defined in HORSE
and passed to the displayer during run time.
In my system constants are shared by inheriting from SHARED.
The best way is that I think I wanted to avoid getting more complex for the example 

Thank you very much for your efforts and support.
Same for you, was a great share! 
@Alexander: The same to you!
I learned a lot!
I'm still struggling into implementations now... as integrating separates with non separates are not that easy for me, but keep going! 

Best,

Karsten

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages