Re: How to encapsulate local state in closures

2008-12-31 Thread Timothy Pratley

> On Dec 30, 2008, at 6:29 PM, Mark Engelberg wrote:
> Use Case #1: Implementing classic imperative algorithm (GDC)

I replaced your (atoms) using (with-local-vars) and the function runs
perfectly fine. The local vars are not closed over, so they cannot
leak, and the code is cleaner. So this example isn't a case for atom-
set in my opinion.


> Use Case #2: setting up mutually referential data structures

The visible choices are ref and atom.

Atoms are non transactional/coordinated. Atoms can only be set by
providing a modifying function. Lets look at an imaginary example if
you were able to set them:
(atom-set a (+ @a (* @a @a)))
The value of @a can actually change halfway through evaluating (+ @a
(* @a @a)) giving a misleading result. Consistency is maintained but
the semantics are deceptive. The atom could be set to any combination
of old value and new value run through that function. atom-set
encourages transactional style statements without their guarantees.
Instead there is swap! which reads the current value, applies the
function to it, and will only commit the result if the atom has not
changed. If another thread has changed the value, it will retry until
successful.

(swap! a + (* @a @a))
is just as deceptive. Because swap! is a function, (* @a @a) is
evaluated before swap! is called, resulting in the exact same race
condition described with atom-set. It is unnecessary to use @a with
swap! because the correct value of the atom to use is passed in to the
function you provide to swap! The correct way to write this particular
example would be:
(swap! a #(+ %1 (* %1 %1)))

It is very easy to define an efficient atom-set:
(defn atom-set [a val] (.set a val) val)
But there is no way to prevent users doing things like (atom-set a
(inc @)) which is incorrect. Neither can swap! prevent users from
dereferencing the target atom, however there is a clear distinction in
the access method which reminds and encourages correct usage.


> It would be entirely reasonable to want to, under certain conditions,
> to reset the counter to 0.  When you reset to 0, that's just a
> straight write.  Having to say (swap! counter (constantly 0)) feels
> convoluted, and somewhat obscures the fact that this change is not
> dependent on the previous state of the atom.  Furthermore, by having
> to represent this reset as a swap, the counter reset might not happen
> as quickly as one would like.  If there is a lot of contention and
> other threads are in the process of incrementing the counter, the
> reset might fail to go through for a while, because the value is
> frequently changed by other threads between the unnecessary read and
> the write of 0.  An atom-set would not only reflect the intentions of
> the code better, but would provide better performance for the times
> where a read is irrelevant to the value being written.

(.set a 0)
Provides precisely the behavior you describe.
Unfortunately It is not obvious that this is the case unless you look
up the java docs.
http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.html

Perhaps the swap! doc string should explicitly describe the danger:
"The function passed to swap should not enclose the current atom value
as this may create a race condition, instead it should always take the
atom value as an argument. There is no ref-set as it would likely
promote such usage. You can set atoms by calling the java .set method,
but remember that the current atom value should not be used to set a
new value."



On Dec 31 2008, 2:19 pm, Pinocchio  wrote:
> 1) It is possible to get "internally" mutable state using
> with-local-vars and var-set. The problem here is that the "internal"
> state cannot be operated on my multiple threads concurrently. Thus
> functions defined this way will not automatically scale on multi-cores.
> One may have to be careful while wrapping such state in a closure and
> accessing it from multiple threads. However, they *will* allow to
> "naturally" write certain algorithms containing local mutation.

(with-local-vars) has no multi-threading issues, as they are not
shared in any way. To make this true they are not retained in
closures:
user=> (def f (with-local-vars [a 2] #(+ 1 (var-get a
#=(var user/f)
user=> (f)
java.lang.IllegalStateException: Var null is unbound. (NO_SOURCE_FILE:
0)


> 2) It is possible to get "internally" mutable state using clojure arrays
> and recur style re-binding. The problem here is that recur style
> rebinding may not be expressive enough to "naturally" encode certain
> algorithms.

Clojure does require you to be explicit about state mutation, but in
my view that does not diminish the expressiveness. I'm yet to come
across a case where an algorithm can not be directly translated
retaining imperative style.


> 3) It is possible to get "internally" mutable state using atoms (along
> with atom-set for better readability and convenience)... which seems
> like a nice suggestion. The problem h

Re: How to encapsulate local state in closures

2008-12-31 Thread Luc Prefontaine
I have not yet written thousands of line of parallel code in Clojure (I
am in this learning curve as of now while experimenting with
Terracotta).
However I can compare with other frameworks I've used in the past: ASTs,
Event Flags,... on VMS, 
semaphores, condition variables, mutexes, ... in libthread on various
platforms, Java with its simplistic approach,...)
and I fully agree with Rich.

There are always "simple shareable states" in any parallel system and
you need an economical way
to share these without requiring the full blown thing (taking a mutex
before accessing/changing stuff, ).
Semaphores are a good example of state that can be shared and changed
atomically with simple calls.
Dig a bit and you will find them in many places.

Having worked with a lot of real time systems I can guarantee that there
are many spots where such mechanisms are
a necessity.

In java it's worse than in other language because many of these things
have been hidden with
"nice" keywords (synchronized, wait, ...). Other features have been
dropped because people were
killing their apps by lack of knowledge. Other features were not
considered because they were not seen as required... yet.
The implementation details in Java are so hidden to most people that
there is
seldom a discussion about the cost of using a specific feature and the
impacts it has on parallelism.

Parallel code is not mainstream yet in businesses aside from Swing code
(:)), I hope Clojure will change that a lot),
most coders do not deal with these issues very often or in a very
superficial way.

I expect this will have to change when parallel designs will become
common.
I would rather have more options than less to tune up my design and
increase throughput... so atoms are welcomed.

Luc

>From a guy who's been doing a lot of multi threaded apps for more than
twenty years (for those too young to remember,
that was BEFORE libthread came to life :))) and yes I have grey
hairs :)))


On Wed, 2008-12-31 at 10:56 -0800, Rich Hickey wrote:

> 
> 
> On Dec 31, 1:20 pm, "Mark Engelberg"  wrote:
> > On Wed, Dec 31, 2008 at 6:27 AM, Rich Hickey  wrote:
> > > I also think that your use cases for atoms for local mutation are a
> > > mismatch. atoms are about sharing. You really want something else for
> > > private/local mutable references, and I have some ideas for that.
> >
> > My impression so far of atoms is that they are "underpowered", and
> > suitable for a very small set of use cases, most of which you could
> > have already done with refs and commute (albeit with a slight
> > performance penalty).  Since atoms are side-effecting, their
> > composability with other transaction-based Clojure code is limited.
> 
> I wish you would stop repeating that. I've give you concrete use cases
> where atoms might be essential to good scalability in a transactional
> context, lest every transaction that uses a memoized function or ID
> generator have to serialize on it.
> 
> Their compatibility with transactions can be completely irrelevant for
> non-transactional subsystems where atoms can form a useful substrate
> for lock-free synchronous state.
> 
> And, in subsystems using transactions, all effort must be applied to
> keeping transactions small, and most code out of them. Using atoms can
> help enable that where refs are not necessary.
> 
> Rich
> 
> > 
> 

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-31 Thread Rich Hickey



On Dec 31, 1:20 pm, "Mark Engelberg"  wrote:
> On Wed, Dec 31, 2008 at 6:27 AM, Rich Hickey  wrote:
> > I also think that your use cases for atoms for local mutation are a
> > mismatch. atoms are about sharing. You really want something else for
> > private/local mutable references, and I have some ideas for that.
>
> My impression so far of atoms is that they are "underpowered", and
> suitable for a very small set of use cases, most of which you could
> have already done with refs and commute (albeit with a slight
> performance penalty).  Since atoms are side-effecting, their
> composability with other transaction-based Clojure code is limited.

I wish you would stop repeating that. I've give you concrete use cases
where atoms might be essential to good scalability in a transactional
context, lest every transaction that uses a memoized function or ID
generator have to serialize on it.

Their compatibility with transactions can be completely irrelevant for
non-transactional subsystems where atoms can form a useful substrate
for lock-free synchronous state.

And, in subsystems using transactions, all effort must be applied to
keeping transactions small, and most code out of them. Using atoms can
help enable that where refs are not necessary.

Rich

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-31 Thread Mark Engelberg

On Wed, Dec 31, 2008 at 6:27 AM, Rich Hickey  wrote:
> I also think that your use cases for atoms for local mutation are a
> mismatch. atoms are about sharing. You really want something else for
> private/local mutable references, and I have some ideas for that.

You're right that I'm basically asking for something that works well
for private/local mutable references.  It's possible right now to use
with-local-vars, or atoms, or refs, but none of them quite fill that
need perfectly (by design).

My impression so far of atoms is that they are "underpowered", and
suitable for a very small set of use cases, most of which you could
have already done with refs and commute (albeit with a slight
performance penalty).  Since atoms are side-effecting, their
composability with other transaction-based Clojure code is limited.
Yes, my feelings about this are entirely theoretical, and maybe in
practice, as more and more Clojure code is written, I'll get to see
more good uses for atoms.  That's part of the fun of working with a
new and vibrant language that is full of possibilities.

But this perception I have is why I like the idea of extending atom's
capabilities to cover the local mutable reference use cases.  I like
the idea of thinking of an atom as a simple box, with a cool bonus
feature of being able to atomically swap its contents, providing a
step up in safety without going as far as a ref.

Anyway, it's great to hear you have some more ideas on the subject,
and I look forward to seeing what you come up with.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-31 Thread Rich Hickey


On Dec 31, 2008, at 12:30 AM, Mark Engelberg wrote:

>
> On Tue, Dec 30, 2008 at 8:38 PM, Rich Hickey   
> wrote:
>> There's simply no value for Clojure to add to a simple mutable box.
>> Clojure does provide the tools for low-level mutation - access to
>> Java. You can wrap that in whatever functions/macros you like.
>>
>
> There's no way to use the @ dereferencing syntax for a custom mutable
> box, right?

Not true. Just implement clojure.lang.IRef and deref/@ will work.

> The sample I gave would be considerably harder to read if
> you had to use (box-ref u) instead of @u everywhere.
>
>> OTOH, atom-set just invites the read-modify-write race conditions
>> swap! was meant to avoid.
>
> Yes, but not every write to an atom is going to be a read-modify-write
> kind of change, which is why it feels odd to always be limited to
> swap!.
>

It doesn't matter that it's not a read-modify-write change, it matters  
that you think about other consumers of the atom. swap! makes you do  
that.

> Since my examples emphasized the "simple mutable box" benefits of
> having atom-set, and you didn't find that compelling, let's go back to
> the discussion earlier in this thread about using an atom to maintain
> a counter that increments to generate unique IDs.  You've already
> stated that this is one of the uses that is a good fit for atom.
>
> It would be entirely reasonable to want to, under certain conditions,
> to reset the counter to 0.  When you reset to 0, that's just a
> straight write.  Having to say (swap! counter (constantly 0)) feels
> convoluted, and somewhat obscures the fact that this change is not
> dependent on the previous state of the atom.  Furthermore, by having
> to represent this reset as a swap, the counter reset might not happen
> as quickly as one would like.  If there is a lot of contention and
> other threads are in the process of incrementing the counter, the
> reset might fail to go through for a while, because the value is
> frequently changed by other threads between the unnecessary read and
> the write of 0.  An atom-set would not only reflect the intentions of
> the code better, but would provide better performance for the times
> where a read is irrelevant to the value being written.
>

This is a theoretical argument again, and remains unconvincing. (swap!  
counter (constantly 0)) may feel bad, but it should - you're trashing  
a shared reference with no regard for its contents. And if you have  
code where the counter is so hot a one-time swapping reset is a perf  
issue, you have bigger problems.

One thing is certain, right now code like this is unlikely:

(let [val (inc @a)]
   (swap! a (constantly val)))

Whereas with atom-set in the API, code like this is likely:

(atom-set a (inc @a)) ;broken - race condition

after all, it looks just like its (correct) ref counterpart:

(ref-set r (inc @r))

> Yes, atom-set invites a certain potential for misuse, but atoms
> already require a certain degree of care.
>

This is not the kind of criteria I want to use when designing. With  
that logic Clojure could just be a free-for-all like Java, which also  
requires a 'certain degree of care'.

That said, I think a big part of the problem here lies in the name. If  
it was e.g. reinitialize-atom or reset-atom I might feel differently.

I also think that your use cases for atoms for local mutation are a  
mismatch. atoms are about sharing. You really want something else for  
private/local mutable references, and I have some ideas for that.

Rich


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-30 Thread Mark Engelberg

On Tue, Dec 30, 2008 at 8:38 PM, Rich Hickey  wrote:
> There's simply no value for Clojure to add to a simple mutable box.
> Clojure does provide the tools for low-level mutation - access to
> Java. You can wrap that in whatever functions/macros you like.
>

There's no way to use the @ dereferencing syntax for a custom mutable
box, right?  The sample I gave would be considerably harder to read if
you had to use (box-ref u) instead of @u everywhere.

> OTOH, atom-set just invites the read-modify-write race conditions
> swap! was meant to avoid.

Yes, but not every write to an atom is going to be a read-modify-write
kind of change, which is why it feels odd to always be limited to
swap!.

Since my examples emphasized the "simple mutable box" benefits of
having atom-set, and you didn't find that compelling, let's go back to
the discussion earlier in this thread about using an atom to maintain
a counter that increments to generate unique IDs.  You've already
stated that this is one of the uses that is a good fit for atom.

It would be entirely reasonable to want to, under certain conditions,
to reset the counter to 0.  When you reset to 0, that's just a
straight write.  Having to say (swap! counter (constantly 0)) feels
convoluted, and somewhat obscures the fact that this change is not
dependent on the previous state of the atom.  Furthermore, by having
to represent this reset as a swap, the counter reset might not happen
as quickly as one would like.  If there is a lot of contention and
other threads are in the process of incrementing the counter, the
reset might fail to go through for a while, because the value is
frequently changed by other threads between the unnecessary read and
the write of 0.  An atom-set would not only reflect the intentions of
the code better, but would provide better performance for the times
where a read is irrelevant to the value being written.

Yes, atom-set invites a certain potential for misuse, but atoms
already require a certain degree of care.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-30 Thread Rich Hickey


On Dec 30, 2008, at 6:29 PM, Mark Engelberg wrote:

> On Tue, Dec 30, 2008 at 5:53 AM, Rich Hickey   
> wrote:
>> Could you provide an example of when you would need/use that?
>>
>
> Sure.
>
> Use Case #1: Implementing classic imperative algorithms
>
> Consider the binary gcd algorithm on page 338 of The Art of Computer
> Programmiing, volume 2.  This is a very clever implementation of gcd
> using only bit shifting and parity checking.  Like many classic
> algorithms, it is written in a very imperative style.  The following
> is a direct translation to Clojure:
>
> (defn binary-gcd [a b]
>  (let [k (atom 0), u (atom a), v (atom b), t (atom 0),
>   algsteps {:B1 (fn [] (if (and (even? @u) (even? @v))
>  (do (atom-set k (inc @k))
>  (atom-set u (bit-shift-right @u 1))
>  (atom-set v (bit-shift-right @v 1))
>  :B1)
>  :B2)),
> :B2 (fn [] (if (odd? @u)
>  (do (atom-set t (- @v)) :B4)
>  (do (atom-set t @u) :B3))),
> :B3 (fn [] (atom-set t (bit-shift-right @t 1)) :B4),
> :B4 (fn [] (if (even? @t) :B3 :B5))
> :B5 (fn [] (if (> @t 0)
>  (atom-set u @t)
>  (atom-set v (- @t)))
>   :B6),
> :B6 (fn [] (atom-set t (- @u @v))
>   (if (not (zero? @t)) :B3 (bit-shift-left @u @k)))}]
>(loop [step :B1]
>  (let [next ((algsteps step))]
>   (if (number? next) next (recur next))
>
> To test this code, I used the following implementation of atom-set:
> (defn atom-set [a val]
>  (swap! a (constantly val)))
>
> Now, the code would certainly be cleaner if Clojure had tail-call
> optimization and letrec, because you could set each algorithmic step
> up as a mutually recursive function, rather than storing the steps in
> a hash table, and setting up a driver loop to handle the state changes
> as in a state machine.  Or if Clojure just had letrec, this could be
> expressed using the new trampoline construct.
>
> But that's not really the point.  The point here is that this code
> took me no effort to translate from the Knuth book, it worked on the
> first run with no debugging needed, and anyone can easily compare this
> code against the Knuth pseudocode, and see at a glance that this is a
> correct implementation of that algorithm.  There may be ways to
> convert this to a functional style (and I encourage others to try it
> as an interesting exercise), but with any such transformation, it will
> be significantly more difficult to confirm that the program correctly
> implements the algorithm.
>
> About half of the atom-sets are updates that could use the swap!
> function, but many of these are replacing the atom's contents with
> something completely unrelated to its existing contents.
>
> Use Case #2: setting up mutually referential data structures
>
> A common way to set up mutually referential data structures is to
> start them off with links that are set to nil, and then use imperative
> setting to direct the links at the right things.  As a quick example,
> consider the cyclic-linked-list solution to the classic Josephus
> problem.  Here is one way to set up a cyclic ring of people:
>
> (defn make-person [n]
>  {:id n, :link (atom nil)})
>
> (defn link-people [p1 p2]
>  (atom-set (p1 :link) p2))
>
> (defn ring-people [n]
>  (let [vec-people (vec (map make-person (range n)))]
>(dotimes [i (dec n)] (link-people (vec-people i) (vec-people (inc  
> i
>(link-people (vec-people (dec n)) (vec-people 0))
>(vec-people 0)))
>
> Now depending on how this is going to be used, you could argue that
> maybe you're better served by refs.  But if the whole point of atoms
> is to give power-users another, faster choice when no coordination is
> needed, why not give the programmer a choice here?  If I know for sure
> that I'm just going to use this ring within a single thread, or use it
> internally in a function that generates and uses the ring without ever
> exposing the ring outside that function, then an atom may be the right
> tool for the job.
>
>

I don't see these as being compelling arguments for atom-set. You can  
do these things with Java arrays or other Java things like  
clojure.lang.Box.

OTOH, atom-set just invites the read-modify-write race conditions  
swap! was meant to avoid.

There's simply no value for Clojure to add to a simple mutable box.  
Clojure does provide the tools for low-level mutation - access to  
Java. You can wrap that in whatever functions/macros you like.

Rich


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this 

Re: How to encapsulate local state in closures

2008-12-30 Thread Pinocchio
Timothy Pratley wrote:
>> I think if Clojure could do something like this (enforce a certain
>> kind of referentially transparent mutable local), that would be neat,
>> 
>
> It is possible to achieve this behavior explicitly:
> (defn create-add-2 []
>   (with-local-vars [x 1]
> (do
>   (var-set x 2)
>   (let [z @x]
> (fn [y] (+ y z))
> (def myc (create-add-2))
> user=> (myc 1)
> 3
> user=> (myc 2)
> 4
>
> A bit verbose, but also very clear about what is really mutable and
> what isn't.
>
>
>   
I am trying to understand the arguments here... so here is a summary. 
Please let me know if I missed something:

1) It is possible to get "internally" mutable state using 
with-local-vars and var-set. The problem here is that the "internal" 
state cannot be operated on my multiple threads concurrently. Thus 
functions defined this way will not automatically scale on multi-cores. 
One may have to be careful while wrapping such state in a closure and 
accessing it from multiple threads. However, they *will* allow to 
"naturally" write certain algorithms containing local mutation.
2) It is possible to get "internally" mutable state using clojure arrays 
and recur style re-binding. The problem here is that recur style 
rebinding may not be expressive enough to "naturally" encode certain 
algorithms.
3) It is possible to get "internally" mutable state using atoms (along 
with atom-set for better readability and convenience)... which seems 
like a nice suggestion. The problem here is the generic problem with 
atoms which should be used carefully under do-sync. Particularly, if an 
atom is indeed an "internal" state in a function's closure, and the 
closure itself is used in a transaction then we have problems due to 
transaction retries. So, we either use atoms assuming that the function 
closures *will* be retried in transactions which limits the situations 
in which atoms can be used or we make sure we document such function 
closures so that they are not used in do-sync (may be clojure can print 
a warning if it sees an atom being used inside a do-sync).

However, this problem occurs only if there is a closure. If the function 
is retried and the internal state is created afresh then do we still 
have a problem? Is this a valid way to handle "internal" mutable state 
which is not encapsulated in closures?

So can we conclude that atoms with atom-set can be freely used in 
functions which don't return closures around them and if we really need 
to do that, we should use refs instead (or use one of the first two 
options given in the beginning)?

Pinocchio


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-30 Thread Mark Engelberg
On Tue, Dec 30, 2008 at 5:53 AM, Rich Hickey  wrote:
> Could you provide an example of when you would need/use that?
>

Sure.

Use Case #1: Implementing classic imperative algorithms

Consider the binary gcd algorithm on page 338 of The Art of Computer
Programmiing, volume 2.  This is a very clever implementation of gcd
using only bit shifting and parity checking.  Like many classic
algorithms, it is written in a very imperative style.  The following
is a direct translation to Clojure:

(defn binary-gcd [a b]
  (let [k (atom 0), u (atom a), v (atom b), t (atom 0),
algsteps {:B1 (fn [] (if (and (even? @u) (even? @v))
   (do (atom-set k (inc @k))
   (atom-set u (bit-shift-right @u 1))
   (atom-set v (bit-shift-right @v 1))
   :B1)
   :B2)),
  :B2 (fn [] (if (odd? @u)
   (do (atom-set t (- @v)) :B4)
   (do (atom-set t @u) :B3))),
  :B3 (fn [] (atom-set t (bit-shift-right @t 1)) :B4),
  :B4 (fn [] (if (even? @t) :B3 :B5))
  :B5 (fn [] (if (> @t 0)
   (atom-set u @t)
   (atom-set v (- @t)))
:B6),
  :B6 (fn [] (atom-set t (- @u @v))
(if (not (zero? @t)) :B3 (bit-shift-left @u @k)))}]
(loop [step :B1]
  (let [next ((algsteps step))]
(if (number? next) next (recur next))

To test this code, I used the following implementation of atom-set:
(defn atom-set [a val]
  (swap! a (constantly val)))

Now, the code would certainly be cleaner if Clojure had tail-call
optimization and letrec, because you could set each algorithmic step
up as a mutually recursive function, rather than storing the steps in
a hash table, and setting up a driver loop to handle the state changes
as in a state machine.  Or if Clojure just had letrec, this could be
expressed using the new trampoline construct.

But that's not really the point.  The point here is that this code
took me no effort to translate from the Knuth book, it worked on the
first run with no debugging needed, and anyone can easily compare this
code against the Knuth pseudocode, and see at a glance that this is a
correct implementation of that algorithm.  There may be ways to
convert this to a functional style (and I encourage others to try it
as an interesting exercise), but with any such transformation, it will
be significantly more difficult to confirm that the program correctly
implements the algorithm.

About half of the atom-sets are updates that could use the swap!
function, but many of these are replacing the atom's contents with
something completely unrelated to its existing contents.

Use Case #2: setting up mutually referential data structures

A common way to set up mutually referential data structures is to
start them off with links that are set to nil, and then use imperative
setting to direct the links at the right things.  As a quick example,
consider the cyclic-linked-list solution to the classic Josephus
problem.  Here is one way to set up a cyclic ring of people:

(defn make-person [n]
  {:id n, :link (atom nil)})

(defn link-people [p1 p2]
  (atom-set (p1 :link) p2))

(defn ring-people [n]
  (let [vec-people (vec (map make-person (range n)))]
(dotimes [i (dec n)] (link-people (vec-people i) (vec-people (inc i
(link-people (vec-people (dec n)) (vec-people 0))
(vec-people 0)))

Now depending on how this is going to be used, you could argue that
maybe you're better served by refs.  But if the whole point of atoms
is to give power-users another, faster choice when no coordination is
needed, why not give the programmer a choice here?  If I know for sure
that I'm just going to use this ring within a single thread, or use it
internally in a function that generates and uses the ring without ever
exposing the ring outside that function, then an atom may be the right
tool for the job.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



binarygcd.clj
Description: Binary data


josephus.clj
Description: Binary data


Re: How to encapsulate local state in closures

2008-12-30 Thread Rich Hickey



On Dec 29, 8:08 pm, "Mark Engelberg"  wrote:
> On Mon, Dec 29, 2008 at 12:40 PM, Rich Hickey  wrote:
> > People who know what they are doing can do these things right now with
> > Clojure's array support. There really isn't any more value for Clojure
> > to add to that, so no special primitives. I fully accept the necessity
> > of doing that at times, and the correctness of internally mutating,
> > but externally referentially transparent functions, and Clojure has
> > several of them. That's one of the reasons Clojure isn't 'pure'. OTOH
> > it's not a good argument for mutable local vars. What other "unsafe
> > things" are you looking for?
>
> After giving this some more thought, I think the absolutely simplest
> way to further improve Clojure's mutability support would be to add an
> atom-set function for the cases where you really want to clobber the
> contents of atom and don't care what the contents already are.  This
> takes the "variable which needs no synchronization" thing one step
> further, allowing for fastest speed in those situations.
>
> The semantics would be like this:
> (defn atom-set [a val]
>   (swap! a (constantly val)))
>
> But presumably it could be implemented in the Clojure core in a way
> that is even faster than the above implementation, since it doesn't
> need to do the check that the contents haven't changed before setting.
>  I think this is consistent with the idea of atom as a power-user's
> tool for getting the best possible performance when synchronization is
> not required.

Could you provide an example of when you would need/use that?

Rich

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Timothy Pratley

> I think if Clojure could do something like this (enforce a certain
> kind of referentially transparent mutable local), that would be neat,

It is possible to achieve this behavior explicitly:
(defn create-add-2 []
  (with-local-vars [x 1]
(do
  (var-set x 2)
  (let [z @x]
(fn [y] (+ y z))
(def myc (create-add-2))
user=> (myc 1)
3
user=> (myc 2)
4

A bit verbose, but also very clear about what is really mutable and
what isn't.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Mark Engelberg

On Mon, Dec 29, 2008 at 2:57 PM, Dave Griffith
 wrote:
>
> It looks like the mutable locals use case is covered by the "with-
> local-vars" binding form.

Not really.  with-local-vars has somewhat surprising semantics.

For example, you'd expect this (contrived) function to generate an
"add 2" function:
(defn create-add-2 []
  (with-local-vars [x 1]
(do
  (var-set x 2)
  (fn [y] (+ y (var-get x))

But in fact, it just generates a function which errors.

If Clojure had some sort of "mutable local" binding construct, I would
expect this to work:
(defn create-add-2 []
  (mutable [x 1]
 (do
   (set! x 2)
   (fn [y] (+ x y)
because you should be able to refer to a mutable local inside of a closure.

But any attempt to *set* the local in the closure would generate an
error, because you really should be using refs for something like
this:
(defn create-growing-adder []
  (mutable [x 1]
 (do
   (set! x 2)
   (fn [y] (do (set! x (inc x)) (+ x y))


I think if Clojure could do something like this (enforce a certain
kind of referentially transparent mutable local), that would be neat,
but just extending the interface for atoms with atom-set (as I
proposed in my previous post) is probably a perfectly fine and more
realistic solution.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Mark Engelberg

On Mon, Dec 29, 2008 at 12:40 PM, Rich Hickey  wrote:
> People who know what they are doing can do these things right now with
> Clojure's array support. There really isn't any more value for Clojure
> to add to that, so no special primitives. I fully accept the necessity
> of doing that at times, and the correctness of internally mutating,
> but externally referentially transparent functions, and Clojure has
> several of them. That's one of the reasons Clojure isn't 'pure'. OTOH
> it's not a good argument for mutable local vars. What other "unsafe
> things" are you looking for?

After giving this some more thought, I think the absolutely simplest
way to further improve Clojure's mutability support would be to add an
atom-set function for the cases where you really want to clobber the
contents of atom and don't care what the contents already are.  This
takes the "variable which needs no synchronization" thing one step
further, allowing for fastest speed in those situations.

The semantics would be like this:
(defn atom-set [a val]
  (swap! a (constantly val)))

But presumably it could be implemented in the Clojure core in a way
that is even faster than the above implementation, since it doesn't
need to do the check that the contents haven't changed before setting.
 I think this is consistent with the idea of atom as a power-user's
tool for getting the best possible performance when synchronization is
not required.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Dave Griffith

It looks like the mutable locals use case is covered by the "with-
local-vars" binding form.  That said, I'm not sure how useful this
would be.  Even in Java 5, 95% of my local vars are immutable, i.e
annotated as final and never have any mutating methods called on
them.  Most of the rest are simple accumulators:  StringBuffers,
collections which are filled then used then tossed, or summations.  In
Clojure these would be replaced by some sort of reduction, requiring
no .  The only time I could see myself using with-local-vars is in
some complex graph-theoretic code, of the sort I write maybe once a .

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Rich Hickey



On Dec 29, 2:29 pm, "Mark Engelberg"  wrote:
> On Mon, Dec 29, 2008 at 8:05 AM, Rich Hickey  wrote:
> > It is certainly not the whole point of Clojure to make as much code as
> > possible safe for its software transactional memory. Clojure is a set
> > of tools. They are designed to allow for robust programs to be built,
> > including multithreaded programs. STM is one of those tools, but is
> > not a universal answer.
>
> It's good to hear you say this, because I agree.  I was "dispensing
> advice" based on my perception of your philosophy (and because I sense
> from discussions that most people are assuming atoms are safe in ways
> they really aren't).  But in fact, I think that Clojure's tools for
> mutability don't yet go far enough, and I'd prefer to have a few more
> "unsafe" things in the toolbox for experienced programmers.
>
> For example, mutability is extremely useful for
> constructing/initializing complex data structures, especially ones
> that have cyclic references.  (Or think about how StringBuffer is used
> to set up a string with mutability, and then it is delivered as an
> immutable String).  Also, mutability of local variables can be handy
> when implementing a complex "classic" algorithm that is described as a
> sequence of imperative steps, in order to keep the form of the code as
> close as possible to the source.
>
> This sort of local mutability has no impact on referential
> transparency, and is really quite safe when used properly.  But none
> of the existing types of mutability seem like a good fit for this
> need.  It seems like overkill to have to use a ref or atom with their
> transaction or swapping syntaxes in order to mutate something that
> will never be observed as mutable by the outside world.

People who know what they are doing can do these things right now with
Clojure's array support. There really isn't any more value for Clojure
to add to that, so no special primitives. I fully accept the necessity
of doing that at times, and the correctness of internally mutating,
but externally referentially transparent functions, and Clojure has
several of them. That's one of the reasons Clojure isn't 'pure'. OTOH
it's not a good argument for mutable local vars. What other "unsafe
things" are you looking for?

People could have used j.u.c.atomic also, but atom provides a unified
interface consistent with the other reference types, and using swap!
encourages a race-free discipline most people wouldn't pursue with
plain mutable locals and often get wrong with CAS.

Rich

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Mark Engelberg

On Mon, Dec 29, 2008 at 8:05 AM, Rich Hickey  wrote:
> It is certainly not the whole point of Clojure to make as much code as
> possible safe for its software transactional memory. Clojure is a set
> of tools. They are designed to allow for robust programs to be built,
> including multithreaded programs. STM is one of those tools, but is
> not a universal answer.

It's good to hear you say this, because I agree.  I was "dispensing
advice" based on my perception of your philosophy (and because I sense
from discussions that most people are assuming atoms are safe in ways
they really aren't).  But in fact, I think that Clojure's tools for
mutability don't yet go far enough, and I'd prefer to have a few more
"unsafe" things in the toolbox for experienced programmers.

For example, mutability is extremely useful for
constructing/initializing complex data structures, especially ones
that have cyclic references.  (Or think about how StringBuffer is used
to set up a string with mutability, and then it is delivered as an
immutable String).  Also, mutability of local variables can be handy
when implementing a complex "classic" algorithm that is described as a
sequence of imperative steps, in order to keep the form of the code as
close as possible to the source.

This sort of local mutability has no impact on referential
transparency, and is really quite safe when used properly.  But none
of the existing types of mutability seem like a good fit for this
need.  It seems like overkill to have to use a ref or atom with their
transaction or swapping syntaxes in order to mutate something that
will never be observed as mutable by the outside world.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-29 Thread Rich Hickey

On Sat, Dec 27, 2008 at 12:03 AM, Mark Engelberg
 wrote:
>
> On Fri, Dec 26, 2008 at 8:35 PM, Adrian Cuthbertson
>  wrote:
>> It's important to distinguish between updating atoms within
>> transactions and outside transactions. In the former case, one has to
>> ensure the update function can be retried without ill-effects.
>> However, outside a transaction, atoms are just mutable values, that
>> can safely be shared between threads, provided that their updating
>> does not need to be coordinated with other updates (to other atoms,
>> refs or agents).
>
> Yes, but when you write your atom-based code, you have no way to know
> whether you or others who want to reuse it will want to use it as part
> of a transaction.  atom-based code is not generally safe for
> transactions, which is why I suggested it should be avoided.  In your
> example, if incserid is used in a transaction, it is possible that
> certain serids will be skipped.  This may be acceptable, in which
> case, go ahead and use an atom, but often programs rely on subtle
> assumptions (like the serids will be issued consecutively), and your
> program can become brittle if there's a chance your code won't follow
> these assumptions.  Probably better off not to take the chance.  Stick
> with something like refs which will yield more predictable behavior,
> and thus be easier to test.  Memoization is a very special exception,
> because it really doesn't matter if something gets cached more than
> once.
>
> The whole point of Clojure seems to make as much code as possible safe
> for its software transactional memory.  Thus the persistent data
> structures, and other design details.  Although interoperating with
> Java also produces risk within transaction, generally speaking, if you
> stay within the "Clojure core", you're safe for transactions.  Except
> atoms.
>

It is certainly not the whole point of Clojure to make as much code as
possible safe for its software transactional memory. Clojure is a set
of tools. They are designed to allow for robust programs to be built,
including multithreaded programs. STM is one of those tools, but is
not a universal answer.

I think it would be wise to avoid sweeping generalizations - sweeping
generalizations are always wrong :)

There are many things that will never be safe inside transactions -
I/O in particular, and you can look at many forms of mutation (e.g.
all the Java OO mutation) as I/O of a sort. That doesn't mean that
these things aren't useful, or should be avoided. Good practice
programming with STM involves segregating the I/O portion of your code
from the transactional portion, and minimizing the footprint of your
transactions in general.

I think many people look at the facilities provided by Clojure and
hope there's also some magic recipe for good multithreaded designs.
There isn't. Even with Clojure's (or any language's) tools, you have
to think.

I don't disagree that refs should be your first choice, and that atoms
are special purpose tools for more experienced users. But they are not
just for memoization caches.

Taking the case at hand, ID generation. A modern multithreaded program
would try to avoid monotonically increasing consecutive IDs, as any
implementation of that would be a severe concurrency bottleneck. If
you were to use a ref as an ID source, every transaction would have to
line up for access to that ref. Yes, it will be predictable - with
predictably bad scalability. Using an atom for this can seriously
improve the throughput of transactions, by removing what might be the
only ref they share.

I think everyone should try to avoid dispensing advice from
theoretical arguments. You need to understand your tools, the
tradeoffs they involve, the use case at hand, and make good decisions.

Rich

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-26 Thread Mark Engelberg

On Fri, Dec 26, 2008 at 8:35 PM, Adrian Cuthbertson
 wrote:
> It's important to distinguish between updating atoms within
> transactions and outside transactions. In the former case, one has to
> ensure the update function can be retried without ill-effects.
> However, outside a transaction, atoms are just mutable values, that
> can safely be shared between threads, provided that their updating
> does not need to be coordinated with other updates (to other atoms,
> refs or agents).

Yes, but when you write your atom-based code, you have no way to know
whether you or others who want to reuse it will want to use it as part
of a transaction.  atom-based code is not generally safe for
transactions, which is why I suggested it should be avoided.  In your
example, if incserid is used in a transaction, it is possible that
certain serids will be skipped.  This may be acceptable, in which
case, go ahead and use an atom, but often programs rely on subtle
assumptions (like the serids will be issued consecutively), and your
program can become brittle if there's a chance your code won't follow
these assumptions.  Probably better off not to take the chance.  Stick
with something like refs which will yield more predictable behavior,
and thus be easier to test.  Memoization is a very special exception,
because it really doesn't matter if something gets cached more than
once.

The whole point of Clojure seems to make as much code as possible safe
for its software transactional memory.  Thus the persistent data
structures, and other design details.  Although interoperating with
Java also produces risk within transaction, generally speaking, if you
stay within the "Clojure core", you're safe for transactions.  Except
atoms.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-26 Thread Adrian Cuthbertson


On Dec 22, 2:34 pm, "Mark Engelberg"  wrote:
> On Mon, Dec 22, 2008 at 4:23 AM, Parth Malwankar
>
>  wrote:
> > If I get it right, atoms are quite useful to maintain state
> > in the context of a single thread with memoization and
> > counter (within a thread) being two examples.
>
> No, RH said that atoms were definitely intended for multiple threads,
> not just single threads.  But their use is highly specific.  With
> memoization, it doesn't matter if things get retried, as long as
> things don't get "lost".  atombasically guarantees that the ref and
> the set occur atomically (via swap), so you don't have to worry about
> two threads losing something from the cache as follows:
> Current cache {:a 1 :b 2}
> One thread tries to add :c 3, and another tries to add :d 4.
> Without atomic swap, one thread could try to update the cache to {:a 1
> :b 2 :c 3} and the other to {:a 1 :b 2 :d 4} (because they are both
> basing their updates on what they see).  Whichever one wins, one of
> the values will be "lost" from the cache.)
> So atoms make this one guarantee, allowing safe multithread
> memoization, but at great risk for other types of applications,
> because most "seemingly-obvious" uses for atoms would probably be
> hosed by the possible retry.
>
> I fear a lot of people are going to end up misusing atoms.  I assume
> they were necessary to make memoization perform better than under the
> ref-with-commute approach.

It's important to distinguish between updating atoms within
transactions and outside transactions. In the former case, one has to
ensure the update function can be retried without ill-effects.
However, outside a transaction, atoms are just mutable values, that
can safely be shared between threads, provided that their updating
does not need to be coordinated with other updates (to other atoms,
refs or agents).

Here's an example; say we have a multi-threaded service where we wish
to share a single counter to use as say a serial id. The following
code initializes serid to 0 and provides a function incserid to
increment it.

(def serid (atom 0))
(defn incserid [] (swap! serid inc))
(defn docount [n cntr] (dotimes [ind n] (cntr)))

Now, the following uses a thread factory to instantiate (nthreads)
number of threads, each which will execute the above incrementor
(ncount) number of times...

(import '(java.util.concurrent Executors))
(def th-factory (Executors/newSingleThreadExecutor))
(defn do-thrds [nthreads ncount] (dotimes [t nthreads] (.submit th-
factory (partial docount ncount incserid

So, if we then initiate 100 threads to each increment the serid 1
times...

(do-thrds 100 1)
@serid
=>100

We see that the threads have happily shared the atom and updated it
correctly with no ill-effects. Note the lack of requirement for
dosync.

So in summary, atoms are great (and should be used in preference to
refs) where the shared state needs to be mutable, shared and
independent (not requiring coordinated update with other objects).

Regards, Adrian.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-22 Thread Mark Engelberg

On Mon, Dec 22, 2008 at 4:23 AM, Parth Malwankar
 wrote:
> If I get it right, atoms are quite useful to maintain state
> in the context of a single thread with memoization and
> counter (within a thread) being two examples.

No, RH said that atoms were definitely intended for multiple threads,
not just single threads.  But their use is highly specific.  With
memoization, it doesn't matter if things get retried, as long as
things don't get "lost".  atom basically guarantees that the ref and
the set occur atomically (via swap), so you don't have to worry about
two threads losing something from the cache as follows:
Current cache {:a 1 :b 2}
One thread tries to add :c 3, and another tries to add :d 4.
Without atomic swap, one thread could try to update the cache to {:a 1
:b 2 :c 3} and the other to {:a 1 :b 2 :d 4} (because they are both
basing their updates on what they see).  Whichever one wins, one of
the values will be "lost" from the cache.)
So atoms make this one guarantee, allowing safe multithread
memoization, but at great risk for other types of applications,
because most "seemingly-obvious" uses for atoms would probably be
hosed by the possible retry.

I fear a lot of people are going to end up misusing atoms.  I assume
they were necessary to make memoization perform better than under the
ref-with-commute approach.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-22 Thread J. McConnell

On Mon, Dec 22, 2008 at 2:25 AM, Mark Engelberg
 wrote:
>
> Aside from the memoization example for
> which it was invented, I am hard-pressed to think of a good use for
> atoms.

Not having used them myself, I can't think of many good examples
either. However, one in addition to the cache example would be an
auto-incrementing identifier; something like a database sequence. It's
semantics wouldn't change if there were gaps in the produced values as
long as all ID's were unique.

- J.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-22 Thread Parth Malwankar



On Dec 22, 12:25 pm, "Mark Engelberg" 
wrote:
> I misspoke; it's the call to counter that's the problem.  Let's say
> you want to use a counter to count the number of times a ref is set,
> something like this:
>
> (dosync (counter) (ref-set r 1))
>
> If your var-set causes the transaction to retry, an atom-based counter
> will increment twice.  As I understand it, atoms are one of the most
> "dangerous" things in Clojure, and should be avoided unless you're
> completely sure it will not change the semantics of your program if it
> gets executed multiple times.  Aside from the memoization example for
> which it was invented, I am hard-pressed to think of a good use for
> atoms.  For something like a counter, you really have to use ref, and
> that should remain people's default when dealing with mutability.
>
> I haven't done much with atoms yet, so if I've misunderstood Rich's
> posts, feel free to explain my mistake.

Thats a valid example. "counter" should not be used
in the dosync.

However, if the counter is meant for a single thread then one
way to use it would be:

... (counter) (dosync (ref-set r 1)) ...

Basically, as counter has side-effects it shouldn't be called
in dosync as stated in the docs ( http://clojure.org/refs )

To quote the docs:
7. I/O and other activities with side-effects should be avoided
in transactions, since transactions will be retried. The io!
macro can be used to prevent the use of an impure function
in a transaction.

End quote.

The above is a general rule so for e.g. we should not
have (dosync (println "done setting") (ref-set r 1)). If my
understanding is correct, this should be:

... (println "done setting") (dosync (ref-set r 1)) ...

If we want a counter to count events across
multiple threads, then yes, it would make sense to
use refs.

If I get it right, atoms are quite useful to maintain state
in the context of a single thread with memoization and
counter (within a thread) being two examples.

There may possibly be performance implications
for refs and atoms but I haven't really benchmarked it.

Parth


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-21 Thread Mark Engelberg

I misspoke; it's the call to counter that's the problem.  Let's say
you want to use a counter to count the number of times a ref is set,
something like this:

(dosync (counter) (ref-set r 1))

If your var-set causes the transaction to retry, an atom-based counter
will increment twice.  As I understand it, atoms are one of the most
"dangerous" things in Clojure, and should be avoided unless you're
completely sure it will not change the semantics of your program if it
gets executed multiple times.  Aside from the memoization example for
which it was invented, I am hard-pressed to think of a good use for
atoms.  For something like a counter, you really have to use ref, and
that should remain people's default when dealing with mutability.

I haven't done much with atoms yet, so if I've misunderstood Rich's
posts, feel free to explain my mistake.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-21 Thread Parth Malwankar



On Dec 22, 5:45 am, "Mark Engelberg"  wrote:
> But if mk-counter is called twice because it's retried in part of a
> transaction, then you're in big trouble when you use atom.  Better to
> use a ref here.  atom needs to be reserved for the very few cases when
> retries don't matter (like a cache).

If I understand it right, as long as the "counter" is used
within a single thread and not across threads there shouldn't
be any issues. Same as a cache.

If the idea is to use one counter across multiple threads
then refs can be used.

I don't think I follow why mk-counter would be retried. There
is not reason for it to fail as it simply creates a new "counter"
and returns it and doesn't need to block or be blocked.

Parth



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-21 Thread Parth Malwankar



On Dec 22, 5:24 am, "Brian Doyle"  wrote:
> I haven't been following the new atom stuff, so I was wondering why atom
> would be best in this
> situation, vs a ref?  Thanks.

Rich discusses the use of atoms, refs and agents in good detail
in this thread:
http://groups.google.com/group/clojure/msg/fd0371eb7238e933

In case you don't want multiple counters but just one,
the following can also be done.

user=> (let [n (atom 0)] (defn counter [] (swap! n inc)))
#'user/counter
user=> (counter)
1
user=> (counter)
2
user=> (counter)
3

Parth


>
> On Sun, Dec 21, 2008 at 1:03 PM, Parth Malwankar
> wrote:
>
>
>
> > On Dec 21, 11:47 pm, chris  wrote:
> > > I would like to be able to encapsulate local state in a closure.
> > > Specifically, I would like a function that returns an incrementing
> > > integer, thus:
> > > (test_func)
> > > 1
> > > (test_func)
> > > 2
> > > What is the best way to go about this?  With local bindings is failing
> > > and I can't figure just why...
>
> > One way to do this would be to use atom.
>
> > (defn mk-counter [start]
> >  (let [n (atom start)]
> >    (fn [] (swap! n inc
>
> > (def counter (mk-counter 0))
>
> > user=> (counter)
> > 1
> > user=> (counter)
> > 2
> > user=> (counter)
> > 3
>
> > Parth
> > > (def test_closure
> > >            (with-local-vars [one 1]
> > >              (fn [] (var-get one
> > > #'user/test_closure
> > > user> (test_closure)
> > > ; Evaluation aborted.
> > > The var is null when I call the closure.
>
> > > Thanks,
> > > Chris
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-21 Thread Stephen C. Gilardi


On Dec 21, 2008, at 7:24 PM, Brian Doyle wrote:

I haven't been following the new atom stuff, so I was wondering why  
atom would be best in this

situation, vs a ref?  Thanks.



The implementation of atoms is supported by the JVM typically using a  
processor hardware instruction that accomplishes thread safety for a  
single location in a very focused, fast way.


From http://clojure.org/atoms :

Atoms are an efficient way to represent some state that will never  
need to be coordinated with any other, and for which you wish to make  
synchronous changes (unlike agents, which are similarly independent  
but asynchronous).


See also: http://www.ibm.com/developerworks/java/library/j-jtp11234/

--Steve



smime.p7s
Description: S/MIME cryptographic signature


Re: How to encapsulate local state in closures

2008-12-21 Thread Mark Engelberg

But if mk-counter is called twice because it's retried in part of a
transaction, then you're in big trouble when you use atom.  Better to
use a ref here.  atom needs to be reserved for the very few cases when
retries don't matter (like a cache).

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-21 Thread Brian Doyle
I haven't been following the new atom stuff, so I was wondering why atom
would be best in this
situation, vs a ref?  Thanks.

On Sun, Dec 21, 2008 at 1:03 PM, Parth Malwankar
wrote:

>
>
>
> On Dec 21, 11:47 pm, chris  wrote:
> > I would like to be able to encapsulate local state in a closure.
> > Specifically, I would like a function that returns an incrementing
> > integer, thus:
> > (test_func)
> > 1
> > (test_func)
> > 2
> > What is the best way to go about this?  With local bindings is failing
> > and I can't figure just why...
> >
>
> One way to do this would be to use atom.
>
> (defn mk-counter [start]
>  (let [n (atom start)]
>(fn [] (swap! n inc
>
> (def counter (mk-counter 0))
>
> user=> (counter)
> 1
> user=> (counter)
> 2
> user=> (counter)
> 3
>
> Parth
> > (def test_closure
> >(with-local-vars [one 1]
> >  (fn [] (var-get one
> > #'user/test_closure
> > user> (test_closure)
> > ; Evaluation aborted.
> > The var is null when I call the closure.
> >
> > Thanks,
> > Chris
> >
>

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: How to encapsulate local state in closures

2008-12-21 Thread Parth Malwankar



On Dec 21, 11:47 pm, chris  wrote:
> I would like to be able to encapsulate local state in a closure.
> Specifically, I would like a function that returns an incrementing
> integer, thus:
> (test_func)
> 1
> (test_func)
> 2
> What is the best way to go about this?  With local bindings is failing
> and I can't figure just why...
>

One way to do this would be to use atom.

(defn mk-counter [start]
  (let [n (atom start)]
(fn [] (swap! n inc

(def counter (mk-counter 0))

user=> (counter)
1
user=> (counter)
2
user=> (counter)
3

Parth
> (def test_closure
>            (with-local-vars [one 1]
>              (fn [] (var-get one
> #'user/test_closure
> user> (test_closure)
> ; Evaluation aborted.
> The var is null when I call the closure.
>
> Thanks,
> Chris
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



How to encapsulate local state in closures

2008-12-21 Thread chris

I would like to be able to encapsulate local state in a closure.
Specifically, I would like a function that returns an incrementing
integer, thus:
(test_func)
1
(test_func)
2
What is the best way to go about this?  With local bindings is failing
and I can't figure just why...

(def test_closure
   (with-local-vars [one 1]
 (fn [] (var-get one
#'user/test_closure
user> (test_closure)
; Evaluation aborted.
The var is null when I call the closure.

Thanks,
Chris
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---