Re: core.async timeout channels are values - is this intended

2013-11-20 Thread Michał Marczyk
The reason = considers you timeout channels to be equal is that they
are, in fact, the same object. In fact, they may end up being the same
object even with different timeout values:

(identical? (timeout 1) (timeout 2))
;= true

Except I got a false just now with a fresh REPL and same timeout
value... All subsequent invocations return true though, and I'm sure
with a little digging the reason for the false would become clear.

The reason for them being the same object is that timeout goes out of
its way to avoid creating to many timeout channels and will reuse
existing ones if their timeouts are due within a small amount of time
(clojure.core.async.impl.timers/TIMEOUT_RESOLUTION_MS, currently 10
ms) of the requested timeout.

Cheers,
Michał

On 20 November 2013 10:08, Thomas G. Kristensen
thomas.g.kristen...@gmail.com wrote:
 Hi all,

 I ran into a core.async behaviour that confused me a bit the other day. In
 some of our systems, we need to fire different timeouts, perform actions and
 schedule a new timeout. The problem is, that if the timeouts are of the same
 number of ms, we can't distinguish them, and therefore not keep track of and
 remove them from a set (at least not easily).

 That sounds a bit fuzzy. Hopefully this spike will make it clearer what I'm
 trying to say:

 (require '[clojure.core.async :refer [chan timeout alts!! alts!]])

 (= (chan) (chan))
 ;; false

 (= (timeout 1) (timeout 2))
 ;; false

 (= (timeout 1) (timeout 1))
 ;; true

 (do (loop [ch-v (into {} (for [v [1 2 3]] [(timeout 1000) v]))]
   (when-let [chs (keys ch-v)]
 (let [[_ ch] (alts!! chs)]
   (println (ch-v ch))
   (recur (dissoc ch-v ch)
 (println done))
 ;; only fires 3, the last channel in the map

 The intended behaviour of the last loop is to print 1, 2 and 3 (not
 necessarily in that order). However, the ch-v map will only contain one
 key, as timeouts with the same duration are considered the same value. In
 the real example, a new timeout with the same value should be scheduled
 again, by being put in the map.

 So, my questions are:

 - Is this intended behaviour?
 - Is there a different pattern for achieving the scheduling behaviour I'm
 looking for?

 Thanks for your help,

 Thomas

 --
 --
 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
 Note that posts from new members are moderated - please be patient with your
 first post.
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.

-- 
-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: core.async timeout channels are values - is this intended

2013-11-20 Thread Cedric Greevey
Isn't that not only violating least astonishment, but potentially
introducing a terrible bug into the library? One could use two different
timeout channels in two different alts, and if the timeout channels are
aliased, then perhaps only one of the alts would actually get notified.


On Wed, Nov 20, 2013 at 5:05 AM, Michał Marczyk michal.marc...@gmail.comwrote:

 The reason = considers you timeout channels to be equal is that they
 are, in fact, the same object. In fact, they may end up being the same
 object even with different timeout values:

 (identical? (timeout 1) (timeout 2))
 ;= true

 Except I got a false just now with a fresh REPL and same timeout
 value... All subsequent invocations return true though, and I'm sure
 with a little digging the reason for the false would become clear.

 The reason for them being the same object is that timeout goes out of
 its way to avoid creating to many timeout channels and will reuse
 existing ones if their timeouts are due within a small amount of time
 (clojure.core.async.impl.timers/TIMEOUT_RESOLUTION_MS, currently 10
 ms) of the requested timeout.

 Cheers,
 Michał

 On 20 November 2013 10:08, Thomas G. Kristensen
 thomas.g.kristen...@gmail.com wrote:
  Hi all,
 
  I ran into a core.async behaviour that confused me a bit the other day.
 In
  some of our systems, we need to fire different timeouts, perform actions
 and
  schedule a new timeout. The problem is, that if the timeouts are of the
 same
  number of ms, we can't distinguish them, and therefore not keep track of
 and
  remove them from a set (at least not easily).
 
  That sounds a bit fuzzy. Hopefully this spike will make it clearer what
 I'm
  trying to say:
 
  (require '[clojure.core.async :refer [chan timeout alts!! alts!]])
 
  (= (chan) (chan))
  ;; false
 
  (= (timeout 1) (timeout 2))
  ;; false
 
  (= (timeout 1) (timeout 1))
  ;; true
 
  (do (loop [ch-v (into {} (for [v [1 2 3]] [(timeout 1000) v]))]
(when-let [chs (keys ch-v)]
  (let [[_ ch] (alts!! chs)]
(println (ch-v ch))
(recur (dissoc ch-v ch)
  (println done))
  ;; only fires 3, the last channel in the map
 
  The intended behaviour of the last loop is to print 1, 2 and 3 (not
  necessarily in that order). However, the ch-v map will only contain one
  key, as timeouts with the same duration are considered the same value. In
  the real example, a new timeout with the same value should be scheduled
  again, by being put in the map.
 
  So, my questions are:
 
  - Is this intended behaviour?
  - Is there a different pattern for achieving the scheduling behaviour I'm
  looking for?
 
  Thanks for your help,
 
  Thomas
 
  --
  --
  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
  Note that posts from new members are moderated - please be patient with
 your
  first post.
  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
  ---
  You received this message because you are subscribed to the Google Groups
  Clojure group.
  To unsubscribe from this group and stop receiving emails from it, send an
  email to clojure+unsubscr...@googlegroups.com.
  For more options, visit https://groups.google.com/groups/opt_out.

 --
 --
 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
 Note that posts from new members are moderated - please be patient with
 your first post.
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: core.async timeout channels are values - is this intended

2013-11-20 Thread Michał Marczyk
The behaviour of timeout channels is to close after the timeout
elapses. This will be visible everywhere the channel is used.

Cheers,
Michał


On 20 November 2013 11:22, Cedric Greevey cgree...@gmail.com wrote:
 Isn't that not only violating least astonishment, but potentially
 introducing a terrible bug into the library? One could use two different
 timeout channels in two different alts, and if the timeout channels are
 aliased, then perhaps only one of the alts would actually get notified.


 On Wed, Nov 20, 2013 at 5:05 AM, Michał Marczyk michal.marc...@gmail.com
 wrote:

 The reason = considers you timeout channels to be equal is that they
 are, in fact, the same object. In fact, they may end up being the same
 object even with different timeout values:

 (identical? (timeout 1) (timeout 2))
 ;= true

 Except I got a false just now with a fresh REPL and same timeout
 value... All subsequent invocations return true though, and I'm sure
 with a little digging the reason for the false would become clear.

 The reason for them being the same object is that timeout goes out of
 its way to avoid creating to many timeout channels and will reuse
 existing ones if their timeouts are due within a small amount of time
 (clojure.core.async.impl.timers/TIMEOUT_RESOLUTION_MS, currently 10
 ms) of the requested timeout.

 Cheers,
 Michał

 On 20 November 2013 10:08, Thomas G. Kristensen
 thomas.g.kristen...@gmail.com wrote:
  Hi all,
 
  I ran into a core.async behaviour that confused me a bit the other day.
  In
  some of our systems, we need to fire different timeouts, perform actions
  and
  schedule a new timeout. The problem is, that if the timeouts are of the
  same
  number of ms, we can't distinguish them, and therefore not keep track of
  and
  remove them from a set (at least not easily).
 
  That sounds a bit fuzzy. Hopefully this spike will make it clearer what
  I'm
  trying to say:
 
  (require '[clojure.core.async :refer [chan timeout alts!! alts!]])
 
  (= (chan) (chan))
  ;; false
 
  (= (timeout 1) (timeout 2))
  ;; false
 
  (= (timeout 1) (timeout 1))
  ;; true
 
  (do (loop [ch-v (into {} (for [v [1 2 3]] [(timeout 1000) v]))]
(when-let [chs (keys ch-v)]
  (let [[_ ch] (alts!! chs)]
(println (ch-v ch))
(recur (dissoc ch-v ch)
  (println done))
  ;; only fires 3, the last channel in the map
 
  The intended behaviour of the last loop is to print 1, 2 and 3 (not
  necessarily in that order). However, the ch-v map will only contain one
  key, as timeouts with the same duration are considered the same value.
  In
  the real example, a new timeout with the same value should be scheduled
  again, by being put in the map.
 
  So, my questions are:
 
  - Is this intended behaviour?
  - Is there a different pattern for achieving the scheduling behaviour
  I'm
  looking for?
 
  Thanks for your help,
 
  Thomas
 
  --
  --
  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
  Note that posts from new members are moderated - please be patient with
  your
  first post.
  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
  ---
  You received this message because you are subscribed to the Google
  Groups
  Clojure group.
  To unsubscribe from this group and stop receiving emails from it, send
  an
  email to clojure+unsubscr...@googlegroups.com.
  For more options, visit https://groups.google.com/groups/opt_out.

 --
 --
 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
 Note that posts from new members are moderated - please be patient with
 your first post.
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


 --
 --
 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
 Note that posts from new members are moderated - please be patient with your
 first post.
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to 

Re: core.async timeout channels are values - is this intended

2013-11-20 Thread Michał Marczyk
As for scheduling the printlns, this prints out 1, 2, 3 (in some order):

(let [c (chan)]
  (doseq [v [1 2 3]]
(take! (async/timeout 1000) (fn [_] (put! c v
  (go-loop [v (! c)]
(println v)
(recur (! c

Cheers,
Michał


On 20 November 2013 11:34, Michał Marczyk michal.marc...@gmail.com wrote:
 The behaviour of timeout channels is to close after the timeout
 elapses. This will be visible everywhere the channel is used.

 Cheers,
 Michał


 On 20 November 2013 11:22, Cedric Greevey cgree...@gmail.com wrote:
 Isn't that not only violating least astonishment, but potentially
 introducing a terrible bug into the library? One could use two different
 timeout channels in two different alts, and if the timeout channels are
 aliased, then perhaps only one of the alts would actually get notified.


 On Wed, Nov 20, 2013 at 5:05 AM, Michał Marczyk michal.marc...@gmail.com
 wrote:

 The reason = considers you timeout channels to be equal is that they
 are, in fact, the same object. In fact, they may end up being the same
 object even with different timeout values:

 (identical? (timeout 1) (timeout 2))
 ;= true

 Except I got a false just now with a fresh REPL and same timeout
 value... All subsequent invocations return true though, and I'm sure
 with a little digging the reason for the false would become clear.

 The reason for them being the same object is that timeout goes out of
 its way to avoid creating to many timeout channels and will reuse
 existing ones if their timeouts are due within a small amount of time
 (clojure.core.async.impl.timers/TIMEOUT_RESOLUTION_MS, currently 10
 ms) of the requested timeout.

 Cheers,
 Michał

 On 20 November 2013 10:08, Thomas G. Kristensen
 thomas.g.kristen...@gmail.com wrote:
  Hi all,
 
  I ran into a core.async behaviour that confused me a bit the other day.
  In
  some of our systems, we need to fire different timeouts, perform actions
  and
  schedule a new timeout. The problem is, that if the timeouts are of the
  same
  number of ms, we can't distinguish them, and therefore not keep track of
  and
  remove them from a set (at least not easily).
 
  That sounds a bit fuzzy. Hopefully this spike will make it clearer what
  I'm
  trying to say:
 
  (require '[clojure.core.async :refer [chan timeout alts!! alts!]])
 
  (= (chan) (chan))
  ;; false
 
  (= (timeout 1) (timeout 2))
  ;; false
 
  (= (timeout 1) (timeout 1))
  ;; true
 
  (do (loop [ch-v (into {} (for [v [1 2 3]] [(timeout 1000) v]))]
(when-let [chs (keys ch-v)]
  (let [[_ ch] (alts!! chs)]
(println (ch-v ch))
(recur (dissoc ch-v ch)
  (println done))
  ;; only fires 3, the last channel in the map
 
  The intended behaviour of the last loop is to print 1, 2 and 3 (not
  necessarily in that order). However, the ch-v map will only contain one
  key, as timeouts with the same duration are considered the same value.
  In
  the real example, a new timeout with the same value should be scheduled
  again, by being put in the map.
 
  So, my questions are:
 
  - Is this intended behaviour?
  - Is there a different pattern for achieving the scheduling behaviour
  I'm
  looking for?
 
  Thanks for your help,
 
  Thomas
 
  --
  --
  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
  Note that posts from new members are moderated - please be patient with
  your
  first post.
  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
  ---
  You received this message because you are subscribed to the Google
  Groups
  Clojure group.
  To unsubscribe from this group and stop receiving emails from it, send
  an
  email to clojure+unsubscr...@googlegroups.com.
  For more options, visit https://groups.google.com/groups/opt_out.

 --
 --
 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
 Note that posts from new members are moderated - please be patient with
 your first post.
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


 --
 --
 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
 Note that posts from new members are moderated - please be patient with your
 first post.
 To unsubscribe from this group, send email to
 

Re: core.async timeout channels are values - is this intended

2013-11-20 Thread Thomas G. Kristensen
Thanks for the response and discussion. Your proposal solves the problem, 
but not the general observation: that timeout channels are not usable keys. 
A small tweak on your proposal can make a key-safe channel:

(defn unique-timeout
  [ms]
  (let [c (chan)]
(take! (timeout ms) (fn [_] (close! c)))
c))

(do (loop [ch-v (into {} (for [v [1 2 3]] [(unique-timeout 1000) v]))]
  (when-let [chs (keys ch-v)]
(let [[_ ch] (alts!! chs)]
  (println (ch-v ch))
  (recur (dissoc ch-v ch)
(println done))

I think the lesson learned is, that the implementation of timeout-channels 
favours efficiency over the possibility of storing them in maps or sets, 
and removing them from these datastructures in a loop.

Once again, thanks for all the feedback!

Thomas

On Wednesday, November 20, 2013 10:53:45 AM UTC, Michał Marczyk wrote:

 As for scheduling the printlns, this prints out 1, 2, 3 (in some order): 

 (let [c (chan)] 
   (doseq [v [1 2 3]] 
 (take! (async/timeout 1000) (fn [_] (put! c v 
   (go-loop [v (! c)] 
 (println v) 
 (recur (! c 

 Cheers, 
 Michał 


 On 20 November 2013 11:34, Michał Marczyk michal@gmail.comjavascript: 
 wrote: 
  The behaviour of timeout channels is to close after the timeout 
  elapses. This will be visible everywhere the channel is used. 
  
  Cheers, 
  Michał 
  
  
  On 20 November 2013 11:22, Cedric Greevey cgre...@gmail.comjavascript: 
 wrote: 
  Isn't that not only violating least astonishment, but potentially 
  introducing a terrible bug into the library? One could use two 
 different 
  timeout channels in two different alts, and if the timeout channels are 
  aliased, then perhaps only one of the alts would actually get notified. 
  
  
  On Wed, Nov 20, 2013 at 5:05 AM, Michał Marczyk 
  michal@gmail.comjavascript: 

  wrote: 
  
  The reason = considers you timeout channels to be equal is that they 
  are, in fact, the same object. In fact, they may end up being the same 
  object even with different timeout values: 
  
  (identical? (timeout 1) (timeout 2)) 
  ;= true 
  
  Except I got a false just now with a fresh REPL and same timeout 
  value... All subsequent invocations return true though, and I'm sure 
  with a little digging the reason for the false would become clear. 
  
  The reason for them being the same object is that timeout goes out of 
  its way to avoid creating to many timeout channels and will reuse 
  existing ones if their timeouts are due within a small amount of time 
  (clojure.core.async.impl.timers/TIMEOUT_RESOLUTION_MS, currently 10 
  ms) of the requested timeout. 
  
  Cheers, 
  Michał 
  
  On 20 November 2013 10:08, Thomas G. Kristensen 
  thomas.g@gmail.com javascript: wrote: 
   Hi all, 
   
   I ran into a core.async behaviour that confused me a bit the other 
 day. 
   In 
   some of our systems, we need to fire different timeouts, perform 
 actions 
   and 
   schedule a new timeout. The problem is, that if the timeouts are of 
 the 
   same 
   number of ms, we can't distinguish them, and therefore not keep 
 track of 
   and 
   remove them from a set (at least not easily). 
   
   That sounds a bit fuzzy. Hopefully this spike will make it clearer 
 what 
   I'm 
   trying to say: 
   
   (require '[clojure.core.async :refer [chan timeout alts!! alts!]]) 
   
   (= (chan) (chan)) 
   ;; false 
   
   (= (timeout 1) (timeout 2)) 
   ;; false 
   
   (= (timeout 1) (timeout 1)) 
   ;; true 
   
   (do (loop [ch-v (into {} (for [v [1 2 3]] [(timeout 1000) v]))] 
 (when-let [chs (keys ch-v)] 
   (let [[_ ch] (alts!! chs)] 
 (println (ch-v ch)) 
 (recur (dissoc ch-v ch) 
   (println done)) 
   ;; only fires 3, the last channel in the map 
   
   The intended behaviour of the last loop is to print 1, 2 and 3 (not 
   necessarily in that order). However, the ch-v map will only contain 
 one 
   key, as timeouts with the same duration are considered the same 
 value. 
   In 
   the real example, a new timeout with the same value should be 
 scheduled 
   again, by being put in the map. 
   
   So, my questions are: 
   
   - Is this intended behaviour? 
   - Is there a different pattern for achieving the scheduling 
 behaviour 
   I'm 
   looking for? 
   
   Thanks for your help, 
   
   Thomas 
   
   -- 
   -- 
   You received this message because you are subscribed to the Google 
   Groups Clojure group. 
   To post to this group, send email to 
   clo...@googlegroups.comjavascript: 
   Note that posts from new members are moderated - please be patient 
 with 
   your 
   first post. 
   To unsubscribe from this group, send email to 
   clojure+u...@googlegroups.com javascript: 
   For more options, visit this group at 
   http://groups.google.com/group/clojure?hl=en 
   --- 
   You received this message because you are subscribed to the Google 
   Groups 
   Clojure group. 
   To unsubscribe from this group and stop