On 24/10/2007, Jason Johnson jason.johnson.081@gmail.com wrote:
On 10/24/07, Igor Stasenko siguctua@gmail.com wrote:
This having a perspective, only if you have unlimited memory resources and zero cost memory allocation.
I don't understand.
Lets look more precise on this. I will write only in ST(i don't know Erlang), and assuming that i understood well your concept , by having following ST code:
SomeClass>>setVars self setVar1: value1. self setVar2: value2. ... ^ self
here at each message send , instead of writing to receiver memory, we do copy-on-write cloning.
No, this is exactly what we *do not* do. As I have mentioned several times, I want message passing to be explicit. I had hoped the Erlang code would be clear, since it wasn't here is the same thing again in proposed Smalltalk code:
SomeProcess>>run "arbitrary name, doesn't have to be run or anything like that" self breakupStructureWith: 10000. self buildNewStrucureFrom: 10000. ^ structure
SomeProcess>>breakupStructureWith: aProcessCount |rest| rest := structure.
1 to: aProcessCount do: [ rest := splitAndSend: rest ].
SomeProcess>>buildNewStructureFrom: aProcessCount 1 to: aProcessCount do: [ |data| data := self process receive. self addDataToStructure: data.
Ok. Not optimal code in either case, but this Smalltalk code is the equivalent of what the Erlang code above did. Note that in ST I'm not passing the structure around or doing recursion because in ST I can modify variables. Also Note that in the Erlang example and this example the actual send was not shown. The function (split_and_send and splitAndSend respectively) were not shown because I didn't want to write a bunch of code breaking up some imaginary structure.
These are all just normal message sends. The only interprocess stuff is the unshown send (I had planned to use the binary message #!) and the receive method.
So, each time we modifying object we got a modified copy instead modifying original.
Why? Inside a given process I don't see a reason to disallow regular mutability.
Aha, now i get it. So, your approach is to establish a fence between different processes, so they can't share objects. Or maybe more correct to say, that any callee process can have read-only access to any objects which belongs to caller process?
Its unclear how you would determine to which process object belongs to? This is at minimum would require an additional slot per object (ok, this is doable easily).
Also, unclear how you would persist state (or results of computation). Since all you can do now is to send a message to process, which will return an object in answer. Now, since returned object most probably will belong to callee process you must copy it to caller process. But in real you should care of copying a whole subgraph of objects (since you can return a collection of newly created objects (and they , in own turn can be a collections e.t.c.)- and all belonging to callee process). Then , after you done merging a graph, you can simply wipe all memory which was allocated by callee process. This part is easy.
Now, the most interesting part: mutating an objects in caller process. Suppose my starting process calls two different processes. And they came to the point, that they are willing to update a state of some object(s) in caller process (to be clear: process A contains object a, it calls processes B and C in parallel, and now B and C wanting to change state of object a). This could be done by detecting that active process tries to perform a write to an object which is not belongs to current process - so you could transform this attempt into implicit message which will be sent to caller process, like: callerProcess setInstVarOf: object index: x value: y or callerProcess setIndexVarOf: object index: x value: y (the number of cases is not very interesting here)
Now, if that _is_ allowed, we having a race condition, when two or more processes trying to update a state of same object(s) in parent process. And there is no ways instead of !! locking !! semantics to solve this. Or maybe i'm wrong here? ;)
If this is not allowed, then you must follow by two ways: - do copy-on-write , at any attempt of updating 'foreign' object. This arises new problem - how to merge a copied and modified state of object with previous one? How to propagate these changes to other processes? (If you not propagate them, then you actually breaking semantics).
- generate an exception on write attempt. Basta. This option diverges your implementation from any current implementation of smalltalk. And its impossible to adopt old code to new VM with such limitations.