Did some experiments and found a working solution, I think. First some explanation:
How lists/selections are being stored and accessed:
Imagine lists as being stored in a table and being accessed by their index. For example, the various select()-functions expect a list index so they know where to store the selection. If you assign a variable to a selection like with E.MyList := GetFreeSel(), you don't really store a selection object in that variable, but rather only its index. Unlike other event variables, this variable won't even really go out of scope outside this event's rule: the list will still exist after that rule has finished - only the stored index won't be accessible anymore.
Lists are also being stored per ruleset - each MACHINE has its own independent table storing these lists. If you created a selection with index 1 in one MACHINE and try to access the same index in another MACHINE, the selection will appear empty. The most basic ruleset - the RULES section of the mission outside any of your MACHINES - has its own list table as well.
Why returning lists or passing lists as parameters doesn't work as expected:
If you write a function creating a list and return that list using return() or pass it as a parameter to another event, you don't really pass along the list itself, but only its table index. The rule will create a list, store it in its local table and pass along the index to the receiving RULE. If that RULE is in a different ruleset (e.g. a different MACHINE), it'll use that index to access its own local table - where there will be no list at that index or at least not the expected list.
How to overcome the problem:
Both the RULE creating your list and the RULEs accessing the list afterwards need to agree on what table to store the list in, so they know where to save to and load their lists from. I can think of two approaches:
a) store each list in the mission's table outside of any of your MACHINEs and access it using the M-prefix:
e.g. M:Dump(E.MyListIndex);
b) store the list locally in the machine of the calling RULE. The list-creation RULE will need to know the machine, so pass it as argument to the event.
I did a test implementation of both, which seemed to work just fine:
// this rule handles ReturnList events by storing lists in machine-specific tables
RULE event ReturnList
condition E.Machine!=0
:action
Debug("ReturnList was called for machine", E.Machine);
E.Blarg := E.Machine:GetFreeSel();
E.Machine:Select(E.Blarg, s.ship);
return(E.Blarg);
:end
END
// this rule handles ReturnList events by storing them in the mission's list table
RULE event ReturnList
condition E.Machine=0
:action
Debug("ReturnList was called, no machine");
E.List := GetFreeSel();
Select(E.List, s.ship);
return(E.List);
:end
END
MACHINE "foo"
STATE default
RULE event Cheat1
:action
// initialize the E.Machine argument by storing the current machine in it
E.MyList := MEvent(ReturnList, E.Machine := M:GetMachine("foo"));
Debug("In-MACHINE list:", E.MyList);
Dump(E.MyList);
:end
END
RULE event Cheat2
:action
// initialize the E.Machine to 0 - store list in mission's table
E.MyList := MEvent(ReturnList, 0);
M:Debug("Mission list:", E.MyList);
M:Dump(E.MyList);
:end
END
END
END
If your MACHINE happens to be nested in another MACHINE, you'd initialize the E.Machine argument like this:
E.Machine := M:GetMachine("parentMachine"):GetMachine("childMachine");