{"action":"created","issue":{"url":"https://api.github.com/repos/radix/effect/issues/41","labels_url":"https://api.github.com/repos/radix/effect/issues/41/labels{/name}","comments_url":"https://api.github.com/repos/radix/effect/issues/41/comments","events_url":"https://api.github.com/repos/radix/effect/issues/41/events","html_url":"https://github.com/radix/effect/pull/41","id":59733439,"number":41,"title":"add an ERef object, like Haskell's IORef.","user":{"login":"radix","id":227068,"avatar_url":"https://avatars.githubusercontent.com/u/227068?v=3","gravatar_id":"","url":"https://api.github.com/users/radix","html_url":"https://github.com/radix","followers_url":"https://api.github.com/users/radix/followers","following_url":"https://api.github.com/users/radix/following{/other_user}","gists_url":"https://api.github.com/users/radix/gists{/gist_id}","starred_url":"https://api.github.com/users/radix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/radix/subscriptions","organizations_url":"https://api.github.com/users/radix/orgs","repos_url":"https://api.github.com/users/radix/repos","events_url":"https://api.github.com/users/radix/events{/privacy}","received_events_url":"https://api.github.com/users/radix/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-03-04T00:51:34Z","updated_at":"2015-03-06T06:01:46Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/radix/effect/pulls/41","html_url":"https://github.com/radix/effect/pull/41","diff_url":"https://github.com/radix/effect/pull/41.diff","patch_url":"https://github.com/radix/effect/pull/41.patch"},"body":"It only exposes `read` and `modify` operations for now, and doesn't implement the cool STM-style in-place updates, but the interface allows for it."},"comment":{"url":"https://api.github.com/repos/radix/effect/issues/comments/77511320","html_url":"https://github.com/radix/effect/pull/41#issuecomment-77511320","issue_url":"https://api.github.com/repos/radix/effect/issues/41","id":77511320,"user":{"login":"glyph","id":716529,"avatar_url":"https://avatars.githubusercontent.com/u/716529?v=3","gravatar_id":"","url":"https://api.github.com/users/glyph","html_url":"https://github.com/glyph","followers_url":"https://api.github.com/users/glyph/followers","following_url":"https://api.github.com/users/glyph/following{/other_user}","gists_url":"https://api.github.com/users/glyph/gists{/gist_id}","starred_url":"https://api.github.com/users/glyph/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyph/subscriptions","organizations_url":"https://api.github.com/users/glyph/orgs","repos_url":"https://api.github.com/users/glyph/repos","events_url":"https://api.github.com/users/glyph/events{/privacy}","received_events_url":"https://api.github.com/users/glyph/received_events","type":"User","site_admin":false},"created_at":"2015-03-06T06:01:46Z","updated_at":"2015-03-06T06:01:46Z","body":"> To clarify the \"cool STM-style in-place updates\": the simplest way to implement strong consistency in updates is by adding an atomic check-and-set on a version number associated with the ERef (in Python, we'd likely implement this with a lock, \r\n\r\nDo you mean \"In CPython\"?\r\n\r\n> but maybe PyPy could expose some lower-level primitives).\r\n\r\n[PyPy's primitives for STM are \"add to transaction\" and \"run transaction\"](http://pypy.readthedocs.org/en/latest/stm.html#atomic-sections-transactions-etc-a-better-way-to-write-parallel-programs); you don't need to implement revertable cells or write barriers yourself.  The whole point of its STM layer is that most application code doesn't need to know that parallelism is happening.\r\n\r\n> And this leads to \"why ModifyERef and not SetAttribute\" -- It's ModifyERef and not SetAttribute because it takes a callable instead of a new value. Implementing it this way means that you can implement those atomic updates by repeatedly calling the transformation function if the version number mismatches, until you are able to write to the expected version and it succeeds.\r\n\r\n`ModifyAttribute`, then; I suppose I shouldn't have been talking about a separate \"set\" in the context of an atomic-ish test-and-set.\r\n\r\n> So, ERef in that scenario would also carry a version number along with it.\r\n\r\nIn what scenario?  The \"with a lock\" scenario or the \"special new pypy primitives\" scenario?  I browsed some docs on IORef and I didn't see anything related to version numbers or retries so I don't see how this would work.\r\n\r\nIt seems like this design is optimized for some parallel-universe future where `ERef` is somehow part of the PyPy runtime…\r\n\r\n> Your MutableObject idea may have some merit, though I think it encourages a proliferation of mutable variables instead of isolating them to just what you need.\r\n\r\nIt's Python.  You already *have* plenty of mutable variables; they're everywhere. The stdlib is full of them, the runtime is full of them, they're not going away.  My contention here is that to facilitate adoption of Effect where it makes sense, ease of integration with those attributes is more important than an API which makes it more tedious to do so because rewriting all of that code in a different style would be more pure.\r\n\r\n> And my current use case, in Otter, matches up with ERef.\r\n\r\nIt seems to line up just as well with a `MutableAttribute` though; just store the PSet directly on the instance where you're putting the `ERef` and then wrap a `MutableReference` around it.\r\n\r\n> Also: I don't care about performance on CPython. :-)\r\n\r\nFair enough.  Otter is deployed on PyPy, I guess?\r\n\r\n> Ideally, what you put in an ERef is something that can be updated efficiently, like a persistent data structure that is implemented as a (H)AMT (e.g. something from the pyrsistent module). So you don't need to worry about actually mutating sub-components of your mutable object -- you just replace the whole object entirely, and do it efficiently, with something like a pyrsistent.PSet (or PRecord or PVec or whatever).\r\n\r\nIf you're going to say \"I don't care about performance\" you can't turn around and say \"efficiently\" ;-).  pyrsistent is definitely not as efficient as just using a mutable built-in, especially in pypy, where mutable dicts are magical unicorns that have [CPU-cache-optimized algorithms](http://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html) :).  Even according to its own documentation, its performance ranges from \"nearly on par\" to \"slower\" than built-ins.\r\n\r\nIf you have a side-effect-ful cell though, using a plain set vs. using a PSet is an irrelevant implementation detail to an outside observer of your object; they still get an Effect which manipulates some internal state they shouldn't need to see."}}