|   |  | 
| Line 4: | Line 4: | 
|  |  |  |  | 
|  | I think we need to see some examples (well, I do for one). |  | I think we need to see some examples (well, I do for one). | 
| − | 
 |  | 
| − | == Examples ==
 |  | 
| − | The main thing to remember is that the proposal states that all features calls are asynchronous.
 |  | 
| − | 
 |  | 
| − | Transactions are assured with transactional memory, probably implemented as software transactional memory.
 |  | 
| − | ----------------
 |  | 
| − | Example of transaction:<br/>
 |  | 
| − | feature<br/>
 |  | 
| − | correct_removal(container: DISPENSER) is<br/>
 |  | 
| − |  transaction  --  This is a transaction so it is assured to be atomic and isolated<br/>
 |  | 
| − |   if<br/>
 |  | 
| − |    not(container.is_empty)<br/>
 |  | 
| − |   then<br/>
 |  | 
| − |    container.remove<br/>
 |  | 
| − |   end<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | 
 |  | 
| − | This feature is assured to be correct because is is isolated and atomic with respect to the system.  If the container has been modified between the call to is_empty and remove, the feature would be aborted and retried.
 |  | 
| − | -----------------
 |  | 
| − | 
 |  | 
| − | feature<br/>
 |  | 
| − | incorrect_removal(container: DISPENSER) is<br/>
 |  | 
| − |  do<br/>
 |  | 
| − |   if<br/>
 |  | 
| − |    not(container.is_empty)<br/>
 |  | 
| − |   then<br/>
 |  | 
| − |    container.remove<br/>
 |  | 
| − |   end<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | 
 |  | 
| − | This is the standard example of concurrency issues with preconditions.  The container can change between the call to is_empty and remove.  Using transactions avoids this.
 |  | 
| − | ----------------
 |  | 
| − | 
 |  | 
| − | Example of concurrency:<br/>
 |  | 
| − | feature<br/>
 |  | 
| − | write_all_files is<br/>
 |  | 
| − |  do<br/>
 |  | 
| − |   write_file_1<br/>
 |  | 
| − |   write_file_2<br/>
 |  | 
| − |   write_file_3<br/>
 |  | 
| − |   write_file_4<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | 
 |  | 
| − | Since all feature calls would be asynchronous, the four write_file features could be executed in parallel if the runtime decides to do so.  This is not a transaction so isolation across these calls is not assured.
 |  | 
| − | ----------------
 |  | 
| − | 
 |  | 
| − | feature<br/>
 |  | 
| − | write_file is<br/>
 |  | 
| − |  external<br/>
 |  | 
| − |   "operating_system_write"<br/>
 |  | 
| − |  abort<br/>
 |  | 
| − |   "operating_system_abort"<br/>
 |  | 
| − |  commit<br/>
 |  | 
| − |   "operating_system_commit"<br/>
 |  | 
| − | 
 |  | 
| − | This is how transactional features can be mapped on to external function calls that support transactional operations
 |  | 
| − | ----------------
 |  | 
| − | 
 |  | 
| − | feature<br/>
 |  | 
| − | source: DISPENSER[ANY] --Where items are taken from<br/>
 |  | 
| − | destination: DISPENSER[ANY] -- where items are put after processing<br/>
 |  | 
| − | running: BOOLEAN -- Flag to stop processing<br/>
 |  | 
| − | 
 |  | 
| − | consumer is<br/>
 |  | 
| − |  do<br/>
 |  | 
| − |   from<br/>
 |  | 
| − |   until<br/>
 |  | 
| − |    not (running)<br/>
 |  | 
| − |   loop --This loop will spawn multiple threads, microthreads, hyperthreads, or whatever the implementation is and runtime chooses, all processing a single item.<br/>
 |  | 
| − |    process_single_item<br/>
 |  | 
| − |   end<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | <br/>
 |  | 
| − | process_single_item is<br/>
 |  | 
| − |  local<br/>
 |  | 
| − |   item: ANY<br/>
 |  | 
| − |  transaction --Since this is a transaction,  accessing the container is safe even when run concurrently.<br/>
 |  | 
| − |   if<br/>
 |  | 
| − |    not source.is_empty<br/>
 |  | 
| − |   then<br/>
 |  | 
| − |    item := source.item<br/>
 |  | 
| − |    source.remove<br/>
 |  | 
| − |    io.put_string(item.to_string)<br/>
 |  | 
| − |    destination.put(item)<br/>
 |  | 
| − |   end<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | <br/>
 |  | 
| − | ---------------
 |  | 
| − | Legacy externals example
 |  | 
| − | 
 |  | 
| − | feature<br/>
 |  | 
| − | use_legacy_external(item: LEGACY_ITEM) is<br/>
 |  | 
| − |  do<br/>
 |  | 
| − |   print_item(item)<br/>
 |  | 
| − |   log_item(item)<br/>
 |  | 
| − |   --At this point the runtime will block until print_item and log_item have both committed, it will ensure nothing is running in the system and then run the external item serially.  This is the non-concurrent way to ensure something executes as a transaction, isolated and atomic.<br/>
 |  | 
| − |   use_item(item)<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | <br/>
 |  | 
| − | use_item(item: LEGACY_ITEM) is<br/>
 |  | 
| − |  external<br/>
 |  | 
| − |   "..."<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | <br/>
 |  | 
| − | print_item(item: LEGACY_ITEM) is<br/>
 |  | 
| − |  do<br/>
 |  | 
| − |   ...<br/>
 |  | 
| − |  end<br/>
 |  | 
| − | <br/>
 |  | 
| − | log_item(item: LEGACY_ITEM) is<br/>
 |  | 
| − |  do<br/>
 |  | 
| − |   ...<br/>
 |  | 
| − |  end<br/>
 |  | 
Discussion of the feasibility and desirability of implementing transactional concurrency in Eiffel.
I think we need to see some examples (well, I do for one).