Re: core.async - handling nils

2013-08-27 Thread Max Penet
It's a real problem for me too, I also wonder what was the intention behind 
this. I guess there could be a very good reason for this special treatement 
of nils, but I haven't seen it yet. 

I would love to hear about this from people involved in core.async 
development.

On Friday, August 16, 2013 4:44:48 AM UTC+2, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but 
 bit I'm finding it *very* inconvenient that nil can't be sent over 
 channels. In particular, you can't pipe arbitrary Clojure sequences through 
 channels (since sequences can contain nils). 

 I see this as a pretty big design flaw given the ubiquity of sequences in 
 Clojure code - it appears to imply that you can't easily compose channels 
 with generic sequence-handling code without some pretty ugly special-case 
 handling.

 Am I missing something? Is this a real problem for others too? 

 If it is a design flaw, can it be fixed before the API gets locked down?


-- 
-- 
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 - handling nils

2013-08-27 Thread Timothy Baldridge
The reason for not allowing nils isn't a complex one, and basically boils
down to the following:

a) to avoid race conditions, we need a single value to signal the channel
is closed. As mentioned, nil is the obvious choice for this as it matches
lazy seqs and fits well with the rest of clojure:

(when-let [v (! c)]
  (process v))

If we chose a different value, this becomes much more ugly:

(let [v (! c)]
  (when-not (= v :async/closed)
(process v)))

b) I question if there are any valid uses for putting nil in a channel.
With all due respect to all who have written here, thus far, every
complaint about nils and channels boils down to a conversion from seqs to
channels. This is the wrong way to look at the problem. Channels are
co-ordination primitives not data structures. Simply because a lazy seq
looks like a channel, doesn't mean that they should be treated as such.

In all the core.async code I've written I've never had to put a nil in a
channel, so I'm left with the uncomfortable conclusion that most complaints
on this subject are contrived. I could be wrong, but I just haven't seen a
valid use case yet.


This all being said, there really isn't a technical reason to not allow
nils, it just simplifies much of the design and that probably translates to
better performance. So the restriction could be lifted if a rock solid
reason could be found, but as of yet, I haven't seen it.

Timothy Baldridge


On Tue, Aug 27, 2013 at 2:12 AM, Max Penet m...@qbits.cc wrote:

 It's a real problem for me too, I also wonder what was the intention
 behind this. I guess there could be a very good reason for this special
 treatement of nils, but I haven't seen it yet.

 I would love to hear about this from people involved in core.async
 development.

 On Friday, August 16, 2013 4:44:48 AM UTC+2, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but
 bit I'm finding it *very* inconvenient that nil can't be sent over
 channels. In particular, you can't pipe arbitrary Clojure sequences through
 channels (since sequences can contain nils).

 I see this as a pretty big design flaw given the ubiquity of sequences in
 Clojure code - it appears to imply that you can't easily compose channels
 with generic sequence-handling code without some pretty ugly special-case
 handling.

 Am I missing something? Is this a real problem for others too?

 If it is a design flaw, can it be fixed before the API gets locked down?

  --
 --
 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.




-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
-- 
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 - handling nils

2013-08-27 Thread Mike Anderson
On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.com wrote:

 The reason for not allowing nils isn't a complex one, and basically boils
 down to the following:

 a) to avoid race conditions, we need a single value to signal the channel
 is closed. As mentioned, nil is the obvious choice for this as it matches
 lazy seqs and fits well with the rest of clojure:


Agreed that you want a single sentinel value.

It doesn't match lazy-seqs at all though: lazy seqs can contain nils just
fine. There's a big difference between (next some-lazy-seq) [which could be
nil, indicating an empty sequence] and the actual values in the seq [which
could also be nil but don't indicate the end of the seq].


 (when-let [v (! c)]
   (process v))

 If we chose a different value, this becomes much more ugly:

 (let [v (! c)]
   (when-not (= v :async/closed)
 (process v)))


This can be solved easily by providing a macro or some other predicate that
knows how to check for the sentinel value correctly. e.g.

(when-more [v (! c)]
  (process v))


 b) I question if there are any valid uses for putting nil in a channel.
 With all due respect to all who have written here, thus far, every
 complaint about nils and channels boils down to a conversion from seqs to
 channels. This is the wrong way to look at the problem. Channels are
 co-ordination primitives not data structures. Simply because a lazy seq
 looks like a channel, doesn't mean that they should be treated as such.

 In all the core.async code I've written I've never had to put a nil in a
 channel, so I'm left with the uncomfortable conclusion that most complaints
 on this subject are contrived. I could be wrong, but I just haven't seen a
 valid use case yet.


To me it's all about consistency with other Clojure constructs. You can
safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
value just like anything else. So why can't you put them in a channel?

Two use cases I have encountered that motivate this:

a) what if you want to send a sequence through a channel? Since nil as a
value represents the empty sequence, you have to put in some extra special
case handling with the current core.async model.

b) what if you want to write generic code to send all the values in an
arbitrary collection through a channel? you would have to wrap/unwrap nils
at either end to make this work currently.

Both of these, I think, are reasonable and common enough use cases that
it's worth supporting them elegantly rather than forcing users to implement
their own nil-wrapping functionality.


 This all being said, there really isn't a technical reason to not allow
 nils, it just simplifies much of the design and that probably translates to
 better performance. So the restriction could be lifted if a rock solid
 reason could be found, but as of yet, I haven't seen it.


I don't believe there is any noticeable performance difference between
checking for nil and checking if a value is identical? to some sentinel
value (which would presumably be static, final, immutable and hence very
well optimised by the JVM). In addition, not allowing nils just means you
have to do extra work to wrap/unwrap nils as a user - which is almost
certainly a net loss on overall performance.

Still, I think consistency is more significant than the performance
argument in this case.



 Timothy Baldridge


 On Tue, Aug 27, 2013 at 2:12 AM, Max Penet m...@qbits.cc wrote:

 It's a real problem for me too, I also wonder what was the intention
 behind this. I guess there could be a very good reason for this special
 treatement of nils, but I haven't seen it yet.

 I would love to hear about this from people involved in core.async
 development.

 On Friday, August 16, 2013 4:44:48 AM UTC+2, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but
 bit I'm finding it *very* inconvenient that nil can't be sent over
 channels. In particular, you can't pipe arbitrary Clojure sequences through
 channels (since sequences can contain nils).

 I see this as a pretty big design flaw given the ubiquity of sequences
 in Clojure code - it appears to imply that you can't easily compose
 channels with generic sequence-handling code without some pretty ugly
 special-case handling.

 Am I missing something? Is this a real problem for others too?

 If it is a design flaw, can it be fixed before the API gets locked down?

  --
 --
 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 

Re: core.async - handling nils

2013-08-27 Thread Timothy Baldridge
All your arguments come down to this:

I have an arbitrary seq of things I want to send down a channel. It's
exactly that concept I that I push against. Everything you've mentioned
thus far is a data structure. Channels are not data structures they are
concurrency management primitives, treat them as such and I doubt you'll
ever have a need for nils in a channel.

If we treat channels as ways of co-ordinating concurrent processes, then
nil doesn't have a use case. In every use of channels I've had thus far,
nil is better expressed as an empty collection, false, 0, :tick, or some
other ground value.

It's these Rx style programming methods that make people think they need
this feature.

Timothy




On Tue, Aug 27, 2013 at 8:51 AM, Mike Anderson mike.r.anderson...@gmail.com
 wrote:

 On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.com wrote:

 The reason for not allowing nils isn't a complex one, and basically boils
 down to the following:

 a) to avoid race conditions, we need a single value to signal the
 channel is closed. As mentioned, nil is the obvious choice for this as it
 matches lazy seqs and fits well with the rest of clojure:


 Agreed that you want a single sentinel value.

 It doesn't match lazy-seqs at all though: lazy seqs can contain nils just
 fine. There's a big difference between (next some-lazy-seq) [which could be
 nil, indicating an empty sequence] and the actual values in the seq [which
 could also be nil but don't indicate the end of the seq].


 (when-let [v (! c)]
   (process v))

 If we chose a different value, this becomes much more ugly:

 (let [v (! c)]
   (when-not (= v :async/closed)
 (process v)))


 This can be solved easily by providing a macro or some other predicate
 that knows how to check for the sentinel value correctly. e.g.

 (when-more [v (! c)]
   (process v))


 b) I question if there are any valid uses for putting nil in a channel.
 With all due respect to all who have written here, thus far, every
 complaint about nils and channels boils down to a conversion from seqs to
 channels. This is the wrong way to look at the problem. Channels are
 co-ordination primitives not data structures. Simply because a lazy seq
 looks like a channel, doesn't mean that they should be treated as such.


 In all the core.async code I've written I've never had to put a nil in a
 channel, so I'm left with the uncomfortable conclusion that most complaints
 on this subject are contrived. I could be wrong, but I just haven't seen a
 valid use case yet.


 To me it's all about consistency with other Clojure constructs. You can
 safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
 value just like anything else. So why can't you put them in a channel?

 Two use cases I have encountered that motivate this:

 a) what if you want to send a sequence through a channel? Since nil as a
 value represents the empty sequence, you have to put in some extra special
 case handling with the current core.async model.

 b) what if you want to write generic code to send all the values in an
 arbitrary collection through a channel? you would have to wrap/unwrap nils
 at either end to make this work currently.

 Both of these, I think, are reasonable and common enough use cases that
 it's worth supporting them elegantly rather than forcing users to implement
 their own nil-wrapping functionality.


 This all being said, there really isn't a technical reason to not allow
 nils, it just simplifies much of the design and that probably translates to
 better performance. So the restriction could be lifted if a rock solid
 reason could be found, but as of yet, I haven't seen it.


 I don't believe there is any noticeable performance difference between
 checking for nil and checking if a value is identical? to some sentinel
 value (which would presumably be static, final, immutable and hence very
 well optimised by the JVM). In addition, not allowing nils just means you
 have to do extra work to wrap/unwrap nils as a user - which is almost
 certainly a net loss on overall performance.

 Still, I think consistency is more significant than the performance
 argument in this case.



 Timothy Baldridge


 On Tue, Aug 27, 2013 at 2:12 AM, Max Penet m...@qbits.cc wrote:

 It's a real problem for me too, I also wonder what was the intention
 behind this. I guess there could be a very good reason for this special
 treatement of nils, but I haven't seen it yet.

 I would love to hear about this from people involved in core.async
 development.

 On Friday, August 16, 2013 4:44:48 AM UTC+2, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good,
 but bit I'm finding it *very* inconvenient that nil can't be sent over
 channels. In particular, you can't pipe arbitrary Clojure sequences through
 channels (since sequences can contain nils).

 I see this as a pretty big design flaw given the ubiquity of sequences
 in Clojure code - it appears to imply 

Re: core.async - handling nils

2013-08-27 Thread David Nolen
On Tue, Aug 27, 2013 at 10:51 AM, Mike Anderson 
mike.r.anderson...@gmail.com wrote:

 To me it's all about consistency with other Clojure constructs. You can
 safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
 value just like anything else. So why can't you put them in a channel?


Channels are *not* data structures nor are they a place to put something.


 a) what if you want to send a sequence through a channel? Since nil as a
 value represents the empty sequence, you have to put in some extra special
 case handling with the current core.async model.


You're not going to put random sequences into channels. Channels are
conduits for meaningful messages - some well considered coordination
protocol.


 Both of these, I think, are reasonable and common enough use cases that
 it's worth supporting them elegantly rather than forcing users to implement
 their own nil-wrapping functionality.


If you're putting arbitrary sequences into a channel and need to wrap nils,
you probably need to redesign your coordination protocol.

David

-- 
-- 
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 - handling nils

2013-08-27 Thread Brandon Bloom
 In every use of channels I've had thus far, nil is better expressed as an
empty collection, false, 0, :tick, or some other ground value.

I agree completely. But I'll note that you mention false being useful...

If you're writing completely general operators, like map, which are
*sometimes* quite useful, then you have no choice but to do something like
if-recv or explicitly test against nil.

 It's these Rx style programming methods that make people think they need
this feature.

I built my little Rx with channels library (asyncx) without intention to
use it directly, but because I wanted to learn how to work with channels. I
rapidly learned that the techniques are a lot more different than they
look. In particular, it's more difficult to write channel  process
combinators precisely because they are more powerful. However, in practice,
each new reusable channel/process combinator yields more complexity than it
tends to save. I'd rather intentionally choose strictly less powerful
primitives where appropriate and enforce that with encapsulation.

With that in mind, if I ever revisit asyncx, I'll probably define push
sequences or streams in terms of protocols and deftypes. I'd use
core.async to implement them, but only for the lowest level primitives. I'd
provide ways to get in to or out of the stream subsystem for interop with
channels, but the public interface would take IStream objects.


On Tue, Aug 27, 2013 at 10:58 AM, Timothy Baldridge tbaldri...@gmail.comwrote:

 All your arguments come down to this:

 I have an arbitrary seq of things I want to send down a channel. It's
 exactly that concept I that I push against. Everything you've mentioned
 thus far is a data structure. Channels are not data structures they are
 concurrency management primitives, treat them as such and I doubt you'll
 ever have a need for nils in a channel.

 If we treat channels as ways of co-ordinating concurrent processes, then
 nil doesn't have a use case. In every use of channels I've had thus far,
 nil is better expressed as an empty collection, false, 0, :tick, or some
 other ground value.

 It's these Rx style programming methods that make people think they need
 this feature.

 Timothy




 On Tue, Aug 27, 2013 at 8:51 AM, Mike Anderson 
 mike.r.anderson...@gmail.com wrote:

 On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.com wrote:

 The reason for not allowing nils isn't a complex one, and basically
 boils down to the following:

 a) to avoid race conditions, we need a single value to signal the
 channel is closed. As mentioned, nil is the obvious choice for this as it
 matches lazy seqs and fits well with the rest of clojure:


 Agreed that you want a single sentinel value.

 It doesn't match lazy-seqs at all though: lazy seqs can contain nils just
 fine. There's a big difference between (next some-lazy-seq) [which could be
 nil, indicating an empty sequence] and the actual values in the seq [which
 could also be nil but don't indicate the end of the seq].


 (when-let [v (! c)]
   (process v))

 If we chose a different value, this becomes much more ugly:

 (let [v (! c)]
   (when-not (= v :async/closed)
 (process v)))


 This can be solved easily by providing a macro or some other predicate
 that knows how to check for the sentinel value correctly. e.g.

 (when-more [v (! c)]
   (process v))


 b) I question if there are any valid uses for putting nil in a channel.
 With all due respect to all who have written here, thus far, every
 complaint about nils and channels boils down to a conversion from seqs to
 channels. This is the wrong way to look at the problem. Channels are
 co-ordination primitives not data structures. Simply because a lazy seq
 looks like a channel, doesn't mean that they should be treated as such.


 In all the core.async code I've written I've never had to put a nil in a
 channel, so I'm left with the uncomfortable conclusion that most complaints
 on this subject are contrived. I could be wrong, but I just haven't seen a
 valid use case yet.


 To me it's all about consistency with other Clojure constructs. You can
 safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
 value just like anything else. So why can't you put them in a channel?

 Two use cases I have encountered that motivate this:

 a) what if you want to send a sequence through a channel? Since nil as a
 value represents the empty sequence, you have to put in some extra special
 case handling with the current core.async model.

 b) what if you want to write generic code to send all the values in an
 arbitrary collection through a channel? you would have to wrap/unwrap nils
 at either end to make this work currently.

 Both of these, I think, are reasonable and common enough use cases that
 it's worth supporting them elegantly rather than forcing users to implement
 their own nil-wrapping functionality.


 This all being said, there really isn't a technical reason to not allow
 nils, it just 

Re: core.async - handling nils

2013-08-27 Thread Timothy Baldridge
Right, the use of false is a special case. I'm thinking of a mouse event
stream, may have a button channel that sends true or false based on the
state of the mouse button. Even saying that though, I would probably opt
for :clicked and :unclicked or somethig of that nature.

Timothy


On Tue, Aug 27, 2013 at 9:15 AM, Brandon Bloom brandon.d.bl...@gmail.comwrote:

  In every use of channels I've had thus far, nil is better expressed as
 an empty collection, false, 0, :tick, or some other ground value.

 I agree completely. But I'll note that you mention false being useful...

 If you're writing completely general operators, like map, which are
 *sometimes* quite useful, then you have no choice but to do something like
 if-recv or explicitly test against nil.

  It's these Rx style programming methods that make people think they
 need this feature.

 I built my little Rx with channels library (asyncx) without intention to
 use it directly, but because I wanted to learn how to work with channels. I
 rapidly learned that the techniques are a lot more different than they
 look. In particular, it's more difficult to write channel  process
 combinators precisely because they are more powerful. However, in
 practice, each new reusable channel/process combinator yields more
 complexity than it tends to save. I'd rather intentionally choose strictly
 less powerful primitives where appropriate and enforce that with
 encapsulation.

 With that in mind, if I ever revisit asyncx, I'll probably define push
 sequences or streams in terms of protocols and deftypes. I'd use
 core.async to implement them, but only for the lowest level primitives. I'd
 provide ways to get in to or out of the stream subsystem for interop with
 channels, but the public interface would take IStream objects.


 On Tue, Aug 27, 2013 at 10:58 AM, Timothy Baldridge 
 tbaldri...@gmail.comwrote:

 All your arguments come down to this:

 I have an arbitrary seq of things I want to send down a channel. It's
 exactly that concept I that I push against. Everything you've mentioned
 thus far is a data structure. Channels are not data structures they are
 concurrency management primitives, treat them as such and I doubt you'll
 ever have a need for nils in a channel.

 If we treat channels as ways of co-ordinating concurrent processes, then
 nil doesn't have a use case. In every use of channels I've had thus far,
 nil is better expressed as an empty collection, false, 0, :tick, or some
 other ground value.

 It's these Rx style programming methods that make people think they need
 this feature.

 Timothy




 On Tue, Aug 27, 2013 at 8:51 AM, Mike Anderson 
 mike.r.anderson...@gmail.com wrote:

 On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.com wrote:

 The reason for not allowing nils isn't a complex one, and basically
 boils down to the following:

 a) to avoid race conditions, we need a single value to signal the
 channel is closed. As mentioned, nil is the obvious choice for this as it
 matches lazy seqs and fits well with the rest of clojure:


 Agreed that you want a single sentinel value.

 It doesn't match lazy-seqs at all though: lazy seqs can contain nils
 just fine. There's a big difference between (next some-lazy-seq) [which
 could be nil, indicating an empty sequence] and the actual values in the
 seq [which could also be nil but don't indicate the end of the seq].


 (when-let [v (! c)]
   (process v))

 If we chose a different value, this becomes much more ugly:

 (let [v (! c)]
   (when-not (= v :async/closed)
 (process v)))


 This can be solved easily by providing a macro or some other predicate
 that knows how to check for the sentinel value correctly. e.g.

 (when-more [v (! c)]
   (process v))


 b) I question if there are any valid uses for putting nil in a channel.
 With all due respect to all who have written here, thus far, every
 complaint about nils and channels boils down to a conversion from seqs to
 channels. This is the wrong way to look at the problem. Channels are
 co-ordination primitives not data structures. Simply because a lazy seq
 looks like a channel, doesn't mean that they should be treated as such.


 In all the core.async code I've written I've never had to put a nil in
 a channel, so I'm left with the uncomfortable conclusion that most
 complaints on this subject are contrived. I could be wrong, but I just
 haven't seen a valid use case yet.


 To me it's all about consistency with other Clojure constructs. You can
 safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
 value just like anything else. So why can't you put them in a channel?

 Two use cases I have encountered that motivate this:

 a) what if you want to send a sequence through a channel? Since nil as a
 value represents the empty sequence, you have to put in some extra special
 case handling with the current core.async model.

 b) what if you want to write generic code to send all the values in an
 arbitrary 

Re: core.async - handling nils

2013-08-27 Thread Softaddicts
+1

We built a distributed software sending/receiving *messages* based on 
different protocols.

All our protocols wrap data in an envelope. The receiver can then decide how to 
handle the message based on the envelope. Obviously, nil makes a bad envelope.

A nil message on a channel never had any significance to us four years ago 
and rethinking about it we reach the same conclusion today :)


Luc P.


 On Tue, Aug 27, 2013 at 10:51 AM, Mike Anderson 
 mike.r.anderson...@gmail.com wrote:
 
  To me it's all about consistency with other Clojure constructs. You can
  safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
  value just like anything else. So why can't you put them in a channel?
 
 
 Channels are *not* data structures nor are they a place to put something.
 
 
  a) what if you want to send a sequence through a channel? Since nil as a
  value represents the empty sequence, you have to put in some extra special
  case handling with the current core.async model.
 
 
 You're not going to put random sequences into channels. Channels are
 conduits for meaningful messages - some well considered coordination
 protocol.
 
 
  Both of these, I think, are reasonable and common enough use cases that
  it's worth supporting them elegantly rather than forcing users to implement
  their own nil-wrapping functionality.
 
 
 If you're putting arbitrary sequences into a channel and need to wrap nils,
 you probably need to redesign your coordination protocol.
 
 David
 
 -- 
 -- 
 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.
 
--
Softaddictslprefonta...@softaddicts.ca sent by ibisMail from my ipad!

-- 
-- 
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 - handling nils

2013-08-27 Thread Ben Wolfson
On Tue, Aug 27, 2013 at 7:51 AM, Mike Anderson mike.r.anderson...@gmail.com
 wrote:

 On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.com wrote:

 The reason for not allowing nils isn't a complex one, and basically boils
 down to the following:

 a) to avoid race conditions, we need a single value to signal the
 channel is closed. As mentioned, nil is the obvious choice for this as it
 matches lazy seqs and fits well with the rest of clojure:


 Agreed that you want a single sentinel value.

 It doesn't match lazy-seqs at all though: lazy seqs can contain nils just
 fine. There's a big difference between (next some-lazy-seq) [which could be
 nil, indicating an empty sequence] and the actual values in the seq [which
 could also be nil but don't indicate the end of the seq].


And the when-first macro correctly handles this! It's not just `(when-let
[~x (first ~xs)] ~@body). when-first nicely hides away what would otherwise
be much more ugly.



-- 
Ben Wolfson
Human kind has used its intelligence to vary the flavour of drinks, which
may be sweet, aromatic, fermented or spirit-based. ... Family and social
life also offer numerous other occasions to consume drinks for pleasure.
[Larousse, Drink entry]

-- 
-- 
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 - handling nils

2013-08-27 Thread Brandon Bloom
As long as we don't go full Haskell mode:

data Message a = Value a | Done


On Tue, Aug 27, 2013 at 11:20 AM, Timothy Baldridge tbaldri...@gmail.comwrote:

 Right, the use of false is a special case. I'm thinking of a mouse event
 stream, may have a button channel that sends true or false based on the
 state of the mouse button. Even saying that though, I would probably opt
 for :clicked and :unclicked or somethig of that nature.

 Timothy


 On Tue, Aug 27, 2013 at 9:15 AM, Brandon Bloom 
 brandon.d.bl...@gmail.comwrote:

  In every use of channels I've had thus far, nil is better expressed as
 an empty collection, false, 0, :tick, or some other ground value.

 I agree completely. But I'll note that you mention false being useful...

 If you're writing completely general operators, like map, which are
 *sometimes* quite useful, then you have no choice but to do something like
 if-recv or explicitly test against nil.

  It's these Rx style programming methods that make people think they
 need this feature.

 I built my little Rx with channels library (asyncx) without intention to
 use it directly, but because I wanted to learn how to work with channels. I
 rapidly learned that the techniques are a lot more different than they
 look. In particular, it's more difficult to write channel  process
 combinators precisely because they are more powerful. However, in
 practice, each new reusable channel/process combinator yields more
 complexity than it tends to save. I'd rather intentionally choose strictly
 less powerful primitives where appropriate and enforce that with
 encapsulation.

 With that in mind, if I ever revisit asyncx, I'll probably define push
 sequences or streams in terms of protocols and deftypes. I'd use
 core.async to implement them, but only for the lowest level primitives. I'd
 provide ways to get in to or out of the stream subsystem for interop with
 channels, but the public interface would take IStream objects.


 On Tue, Aug 27, 2013 at 10:58 AM, Timothy Baldridge tbaldri...@gmail.com
  wrote:

 All your arguments come down to this:

 I have an arbitrary seq of things I want to send down a channel. It's
 exactly that concept I that I push against. Everything you've mentioned
 thus far is a data structure. Channels are not data structures they are
 concurrency management primitives, treat them as such and I doubt you'll
 ever have a need for nils in a channel.

 If we treat channels as ways of co-ordinating concurrent processes, then
 nil doesn't have a use case. In every use of channels I've had thus far,
 nil is better expressed as an empty collection, false, 0, :tick, or some
 other ground value.

 It's these Rx style programming methods that make people think they need
 this feature.

 Timothy




 On Tue, Aug 27, 2013 at 8:51 AM, Mike Anderson 
 mike.r.anderson...@gmail.com wrote:

 On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.comwrote:

 The reason for not allowing nils isn't a complex one, and basically
 boils down to the following:

 a) to avoid race conditions, we need a single value to signal the
 channel is closed. As mentioned, nil is the obvious choice for this as it
 matches lazy seqs and fits well with the rest of clojure:


 Agreed that you want a single sentinel value.

 It doesn't match lazy-seqs at all though: lazy seqs can contain nils
 just fine. There's a big difference between (next some-lazy-seq) [which
 could be nil, indicating an empty sequence] and the actual values in the
 seq [which could also be nil but don't indicate the end of the seq].


 (when-let [v (! c)]
   (process v))

 If we chose a different value, this becomes much more ugly:

 (let [v (! c)]
   (when-not (= v :async/closed)
 (process v)))


 This can be solved easily by providing a macro or some other predicate
 that knows how to check for the sentinel value correctly. e.g.

 (when-more [v (! c)]
   (process v))


 b) I question if there are any valid uses for putting nil in a
 channel. With all due respect to all who have written here, thus far, 
 every
 complaint about nils and channels boils down to a conversion from seqs to
 channels. This is the wrong way to look at the problem. Channels are
 co-ordination primitives not data structures. Simply because a lazy seq
 looks like a channel, doesn't mean that they should be treated as such.


 In all the core.async code I've written I've never had to put a nil in
 a channel, so I'm left with the uncomfortable conclusion that most
 complaints on this subject are contrived. I could be wrong, but I just
 haven't seen a valid use case yet.


 To me it's all about consistency with other Clojure constructs. You can
 safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
 value just like anything else. So why can't you put them in a channel?

 Two use cases I have encountered that motivate this:

 a) what if you want to send a sequence through a channel? Since nil as
 a value represents the empty sequence, you have to 

Re: core.async - handling nils

2013-08-27 Thread Mike Anderson
I still don't see why you would want to to arbitrarily limit what you can
put down a channel. FWIW, plenty of other concurrency management primitives
allow nils as values (java.util.concurrent.AtomicReference, Clojure atoms /
refs / agents to name but a few).

My motivating use case is the ability to create higher order constructs
that communicate via channels, as a way of gluing concurrent processes
together. A simplified example:

(defn printer [ch id]
  (go (while true
(let [v (! ch)]
  (prn (str Printer  id  handled value:  v))

(defn sender [ch]
 (fn [xs] (go (doseq [x xs] (! ch x)

(let [ch (chan)
  pr1 (printer ch 1)
  pr2 (printer ch 2)
  sendr (sender ch)]
  (sendr [foo a])
  (sendr [bar]))

Using nil as a sentinel appears to prevent such constructs from working
with arbitrary Clojure values (or alternatively forces extra wrapping /
special case handling that adds complexity and overhead). Furthermore, if
different libraries start adopting different protocols / techniques for
wrapping nils then the composability of such constructs will be severely
restricted.

I may be missing something, but this seems like a reasonable use case for
core.async to support?

Of course, if anyone has an actual technical argument why it is
necessary/better to use nil as a sentinel value, I would be delighted to
learn of it and would consider myself enlightened.


On 27 August 2013 22:58, Timothy Baldridge tbaldri...@gmail.com wrote:

 All your arguments come down to this:

 I have an arbitrary seq of things I want to send down a channel. It's
 exactly that concept I that I push against. Everything you've mentioned
 thus far is a data structure. Channels are not data structures they are
 concurrency management primitives, treat them as such and I doubt you'll
 ever have a need for nils in a channel.

 If we treat channels as ways of co-ordinating concurrent processes, then
 nil doesn't have a use case. In every use of channels I've had thus far,
 nil is better expressed as an empty collection, false, 0, :tick, or some
 other ground value.

 It's these Rx style programming methods that make people think they need
 this feature.

 Timothy




 On Tue, Aug 27, 2013 at 8:51 AM, Mike Anderson 
 mike.r.anderson...@gmail.com wrote:

 On 27 August 2013 20:45, Timothy Baldridge tbaldri...@gmail.com wrote:

 The reason for not allowing nils isn't a complex one, and basically
 boils down to the following:

 a) to avoid race conditions, we need a single value to signal the
 channel is closed. As mentioned, nil is the obvious choice for this as it
 matches lazy seqs and fits well with the rest of clojure:


 Agreed that you want a single sentinel value.

 It doesn't match lazy-seqs at all though: lazy seqs can contain nils just
 fine. There's a big difference between (next some-lazy-seq) [which could be
 nil, indicating an empty sequence] and the actual values in the seq [which
 could also be nil but don't indicate the end of the seq].


 (when-let [v (! c)]
   (process v))

 If we chose a different value, this becomes much more ugly:

 (let [v (! c)]
   (when-not (= v :async/closed)
 (process v)))


 This can be solved easily by providing a macro or some other predicate
 that knows how to check for the sentinel value correctly. e.g.

 (when-more [v (! c)]
   (process v))


 b) I question if there are any valid uses for putting nil in a channel.
 With all due respect to all who have written here, thus far, every
 complaint about nils and channels boils down to a conversion from seqs to
 channels. This is the wrong way to look at the problem. Channels are
 co-ordination primitives not data structures. Simply because a lazy seq
 looks like a channel, doesn't mean that they should be treated as such.


 In all the core.async code I've written I've never had to put a nil in a
 channel, so I'm left with the uncomfortable conclusion that most complaints
 on this subject are contrived. I could be wrong, but I just haven't seen a
 valid use case yet.


 To me it's all about consistency with other Clojure constructs. You can
 safely put nils in sequences, vectors, lists, sets etc.. nil is a valid
 value just like anything else. So why can't you put them in a channel?

 Two use cases I have encountered that motivate this:

 a) what if you want to send a sequence through a channel? Since nil as a
 value represents the empty sequence, you have to put in some extra special
 case handling with the current core.async model.

 b) what if you want to write generic code to send all the values in an
 arbitrary collection through a channel? you would have to wrap/unwrap nils
 at either end to make this work currently.

 Both of these, I think, are reasonable and common enough use cases that
 it's worth supporting them elegantly rather than forcing users to implement
 their own nil-wrapping functionality.


 This all being said, there really isn't a technical reason to not allow
 nils, it just simplifies 

Re: core.async - handling nils

2013-08-27 Thread guns
On Wed 28 Aug 2013 at 09:38:06AM +0800, Mike Anderson wrote:

 Of course, if anyone has an actual technical argument why it is
 necessary/better to use nil as a sentinel value, I would be delighted to
 learn of it and would consider myself enlightened.

Forgive me if someone already mentioned this, but isn't this simply a
consequence of building on the existing Java Queue implementations?

Quoting http://docs.oracle.com/javase/7/docs/api/java/util/Queue.html:

Queue implementations generally do not allow insertion of null
elements, although some implementations, such as LinkedList, do not
prohibit insertion of null. Even in the implementations that permit
it, null should not be inserted into a Queue, as null is also used
as a special return value by the poll method to indicate that the
queue contains no elements.

I think most would agree with you that a configurable sentinel value
is best (I like using ::namespaced-keywords myself), but the existing
machinery has already decided on null, so that's what we have.

guns


pgp6xD5GT3rVU.pgp
Description: PGP signature


Re: core.async - handling nils

2013-08-27 Thread Mikera
Well, that's certainly a good explanation of why core.async works the way 
it does now - it's a natural and sensible starting point to build on Java 
Queues.

I don't think that this necessarily implies that we have to follow this 
model in the future Clojure API though. The Java designers didn't always 
get everything right :-)

There's no reason I can see why core.async can't internally substitute its 
own nil-representing value into the underlying Java infrastructure. And 
this would free users of core.async from the burden of doing this 
translation every time that the transmission of nil values is desired.

As for configurable sentinel value: I'm less sure that there's a need for 
this. In fact, I think it's more useful to guarantee a standard sentinel 
value so that different channel-handling code can interoperate. I just 
think that this sentinel shouldn't be nil (or any other regular Clojure 
value). A simple singleton object that is privately owned by core.async 
should suffice?

On Wednesday, 28 August 2013 09:54:51 UTC+8, guns wrote:

 On Wed 28 Aug 2013 at 09:38:06AM +0800, Mike Anderson wrote: 

  Of course, if anyone has an actual technical argument why it is 
  necessary/better to use nil as a sentinel value, I would be delighted to 
  learn of it and would consider myself enlightened. 

 Forgive me if someone already mentioned this, but isn't this simply a 
 consequence of building on the existing Java Queue implementations? 

 Quoting http://docs.oracle.com/javase/7/docs/api/java/util/Queue.html: 

 Queue implementations generally do not allow insertion of null 
 elements, although some implementations, such as LinkedList, do not 
 prohibit insertion of null. Even in the implementations that permit 
 it, null should not be inserted into a Queue, as null is also used 
 as a special return value by the poll method to indicate that the 
 queue contains no elements. 

 I think most would agree with you that a configurable sentinel value 
 is best (I like using ::namespaced-keywords myself), but the existing 
 machinery has already decided on null, so that's what we have. 

 guns 


-- 
-- 
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 - handling nils

2013-08-27 Thread guns
On Tue 27 Aug 2013 at 07:42:53PM -0700, Mikera wrote:

 On Wednesday, 28 August 2013 09:54:51 UTC+8, guns wrote:
 
  On Wed 28 Aug 2013 at 09:38:06AM +0800, Mike Anderson wrote:
 
   Of course, if anyone has an actual technical argument why it is
   necessary/better to use nil as a sentinel value, I would be delighted to
   learn of it and would consider myself enlightened.
 
  Forgive me if someone already mentioned this, but isn't this simply a
  consequence of building on the existing Java Queue implementations?
 
  Quoting http://docs.oracle.com/javase/7/docs/api/java/util/Queue.html:
 
  Queue implementations generally do not allow insertion of null
  elements, although some implementations, such as LinkedList, do not
  prohibit insertion of null. Even in the implementations that permit
  it, null should not be inserted into a Queue, as null is also used
  as a special return value by the poll method to indicate that the
  queue contains no elements.

 I don't think that this necessarily implies that we have to follow
 this model in the future Clojure API though. The Java designers didn't
 always get everything right :-)

I agree with you that this is an inconvenience. The bit about avoiding
null even in collections that support null elements because poll uses
null as a sentinel value is a classic leaky abstraction.

That said, I haven't found designing around it to be a terrible
nuisance. I often use queues as messaging channels, so it is natural to
simply send maps or tuples instead of atomic values.

 As for configurable sentinel value: I'm less sure that there's
 a need for this. In fact, I think it's more useful to guarantee a
 standard sentinel value so that different channel-handling code can
 interoperate. I just think that this sentinel shouldn't be nil (or
 any other regular Clojure value). A simple singleton object that is
 privately owned by core.async should suffice?

Oh, I was confused; I was thinking about sentinel values in user code.
Yes, I imagine a single private (Object.) would work just fine, with
very little overhead.

guns


pgp0C89I2s0Ka.pgp
Description: PGP signature


Re: core.async - handling nils

2013-08-27 Thread Alan Busby
On Wed, Aug 28, 2013 at 12:18 PM, guns s...@sungpae.com wrote:

 Oh, I was confused; I was thinking about sentinel values in user code.
 Yes, I imagine a single private (Object.) would work just fine, with
 very little overhead.


First, I'd hope that sentinel values would be handled by the back-end
implementation, as we're seeing core.sync implemented on other
systems like ZeroMQ already.

Second, as (Object.) doesn't play nicely over the wire, a random UUID
or similar value would be much preferred.

Third, I'd recommend reviewing,
http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html
to understand why core.async is not just a better queue.

Fourth, if you dislike how core.async works, just wrap it in your own
library so it works the way you'd like.
It looks like core.async-with-nil is available on Clojars. ;)

With nil, without nil, it's just bike shedding. Clojure gives you the
freedom to do it the way you want.

-- 
-- 
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 - handling nils

2013-08-27 Thread guns
On Wed 28 Aug 2013 at 12:50:19PM +0900, Alan Busby wrote:

 On Wed, Aug 28, 2013 at 12:18 PM, guns s...@sungpae.com wrote:

  Oh, I was confused; I was thinking about sentinel values in user
  code. Yes, I imagine a single private (Object.) would work just
  fine, with very little overhead.

 Third, I'd recommend reviewing,
 http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html to
 understand why core.async is not just a better queue.

In my mind, core.async is a nice marriage of BlockingQueues, async
processing, and a supercharged POSIX select(2) that works on queue
objects. Nothing about these ideas necessarily requires that null be
reserved by the channel implementation.

 Fourth, if you dislike how core.async works, just wrap it in
 your own library so it works the way you'd like. It looks like
 core.async-with-nil is available on Clojars. ;)

 With nil, without nil, it's just bike shedding. Clojure gives you the
 freedom to do it the way you want.

Rich Hickey, from: 
http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html

 While the library is still in an early state, we are ready for people
 to start trying it out and giving us feedback.

I think mikera is trying to be constructive.

For my own part, I am quite ambivalent since I am already used to
avoiding pushing nulls onto Queues. I am quite happy to accept that this
is an implementation detail and move on, but I can also see why it might
be worth it to support nil channel values to avoid confusing users that
are not familiar with this quirk of java.util.Queue.

guns


pgpQWVvS0WkaO.pgp
Description: PGP signature


Re: core.async - handling nils

2013-08-27 Thread Mike Anderson
On 28 August 2013 11:50, Alan Busby thebu...@gmail.com wrote:

 On Wed, Aug 28, 2013 at 12:18 PM, guns s...@sungpae.com wrote:

 Oh, I was confused; I was thinking about sentinel values in user code.
 Yes, I imagine a single private (Object.) would work just fine, with
 very little overhead.


 First, I'd hope that sentinel values would be handled by the back-end
 implementation, as we're seeing core.sync implemented on other
 systems like ZeroMQ already.

 Second, as (Object.) doesn't play nicely over the wire, a random UUID
 or similar value would be much preferred.


Hi Alan,

Agreed on all the above. The issue is not so much what sentinel value is
used internally, but what sentinel value gets exposed to user code.



 Third, I'd recommend reviewing,
 http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html
 to understand why core.async is not just a better queue.

 Fourth, if you dislike how core.async works, just wrap it in your own
 library so it works the way you'd like.
 It looks like core.async-with-nil is available on Clojars. ;)


That's precisely what I'm trying to avoid, and the reason why I've been
raising the topic here - the last thing we want in the ecosystem is more
fragmentation with incompatible subsystems and protocols. That's the Lisp
Curse all over again. I think we should aspire to better in the Clojure
community - which means working together to make the best implementation
possible and rallying around it.

Sending nil as a value over channels is clearly a significant issue if
people are willing to fork or create a new wrapper for core.async in order
to achieve it. Better, in my view, to make a breaking change to core.async
now to fix this issue rather than encouraging a free-for-all.

I'm reminded of Rich Hickey's keynote The Language of the System, which
emphasised composing systems out of simple services that communicate via
values. core.async would IMHO be a much more useful tool for realising this
sort of vision if it is able transmit arbitrary Clojure values (i.e.
including nil).

-- 
-- 
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 - handling nils

2013-08-18 Thread Mikera
If you use a singleton sentinel value that is generated privately within 
the core.async implementation, then the sentinel isn't really a regular 
value in the sense that it can be created by regular user code.

nil, on the other hand, gets used very frequently as a value in regular 
Clojure code.

That's a key reason IMHO why it's better to use a sentinel as a closed 
channel indicator than nil.

On Sunday, 18 August 2013 09:43:34 UTC+8, Ben wrote:

 A sentinel value also prevents channels from being able to send/receive 
 arbitrary values, without further wrapping.

 Sent from my iPhone

 On Aug 17, 2013, at 5:48 PM, Mikera mike.r.an...@gmail.com javascript: 
 wrote:

 My overall sense is that the convenience of using if-let directly in a few 
 use cases doesn't justify making channels fall short of being able to send 
 arbitrary values (nil specifically, and clearly boolean false can cause 
 some problems too). 

 I think it would be a much better design to have a sentinel value and a 
 couple of specialised functions or macros that can detect  / interact with 
 it appropriately. With a sentinel value the key part of your if-recv code 
 could just be something like:

 `(let [~name (! ~port)]
   (if (end-of-stream? ~name)
 ~else
 ~then


 I can see that wrappers for nil values could also work, but that seems to 
 be a more complex solution (and also potentially with more overhead) than a 
 sentinel value


 On Saturday, 17 August 2013 07:50:06 UTC+8, Brandon Bloom wrote:

 I ran into the other half of this problem: If you expect nils to signify 
 closed channels, then you can't leverage the logically false nature of nil 
 without excluding explicit boolean false values. Given the pleasant syntax 
 of if-let / ! pairs, I reworked my early experiments to use if-recv 
 which is defined as follows:

 (defmacro if-recv
   Reads from port, binding to name. Evaluates the then block if the
   read was successful. Evaluates the else block if the port was closed.
   ([[name port :as binding] then]
`(if-recv ~binding ~then nil))
   ([[name port] then else]
`(let [~name (! ~port)]
   (if (nil? ~name)
 ~else
 ~then


 I've considered some alternative core.async designs, such as an 
 additional done sentinel value, or a pair of quote/unquote operators (see 
 reduced), but nothing seems as simple as just avoiding booleans and nils, 
 as annoying as that is. I'd be curious to here what Rich  team 
 considered and how they're thinking about it. However, my expectation is 
 that the nil approach won't change, since it's pretty much good enough.

 On Thursday, August 15, 2013 10:44:48 PM UTC-4, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but 
 bit I'm finding it *very* inconvenient that nil can't be sent over 
 channels. In particular, you can't pipe arbitrary Clojure sequences through 
 channels (since sequences can contain nils). 

 I see this as a pretty big design flaw given the ubiquity of sequences 
 in Clojure code - it appears to imply that you can't easily compose 
 channels with generic sequence-handling code without some pretty ugly 
 special-case handling.

 Am I missing something? Is this a real problem for others too? 

 If it is a design flaw, can it be fixed before the API gets locked down?

  -- 
 -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@googlegroups.com javascript:
 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 receiving emails from it, send an 
 email to clojure+u...@googlegroups.com javascript:.
 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 - handling nils

2013-08-17 Thread Mikera
My overall sense is that the convenience of using if-let directly in a few 
use cases doesn't justify making channels fall short of being able to send 
arbitrary values (nil specifically, and clearly boolean false can cause 
some problems too). 

I think it would be a much better design to have a sentinel value and a 
couple of specialised functions or macros that can detect  / interact with 
it appropriately. With a sentinel value the key part of your if-recv code 
could just be something like:

`(let [~name (! ~port)]
  (if (end-of-stream? ~name)
~else
~then


I can see that wrappers for nil values could also work, but that seems to 
be a more complex solution (and also potentially with more overhead) than a 
sentinel value


On Saturday, 17 August 2013 07:50:06 UTC+8, Brandon Bloom wrote:

 I ran into the other half of this problem: If you expect nils to signify 
 closed channels, then you can't leverage the logically false nature of nil 
 without excluding explicit boolean false values. Given the pleasant syntax 
 of if-let / ! pairs, I reworked my early experiments to use if-recv 
 which is defined as follows:

 (defmacro if-recv
   Reads from port, binding to name. Evaluates the then block if the
   read was successful. Evaluates the else block if the port was closed.
   ([[name port :as binding] then]
`(if-recv ~binding ~then nil))
   ([[name port] then else]
`(let [~name (! ~port)]
   (if (nil? ~name)
 ~else
 ~then


 I've considered some alternative core.async designs, such as an additional 
 done sentinel value, or a pair of quote/unquote operators (see 
 reduced), but nothing seems as simple as just avoiding booleans and nils, 
 as annoying as that is. I'd be curious to here what Rich  team 
 considered and how they're thinking about it. However, my expectation is 
 that the nil approach won't change, since it's pretty much good enough.

 On Thursday, August 15, 2013 10:44:48 PM UTC-4, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but 
 bit I'm finding it *very* inconvenient that nil can't be sent over 
 channels. In particular, you can't pipe arbitrary Clojure sequences through 
 channels (since sequences can contain nils). 

 I see this as a pretty big design flaw given the ubiquity of sequences in 
 Clojure code - it appears to imply that you can't easily compose channels 
 with generic sequence-handling code without some pretty ugly special-case 
 handling.

 Am I missing something? Is this a real problem for others too? 

 If it is a design flaw, can it be fixed before the API gets locked down?



-- 
-- 
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 - handling nils

2013-08-17 Thread Brandon Bloom
That's precisely the design followed by Magpie, described here:
http://journal.stuffwithstuff.com/2013/04/17/well-done/

Parts 1  2 of that series are worth reading too.


On Sat, Aug 17, 2013 at 8:48 PM, Mikera mike.r.anderson...@gmail.comwrote:

 My overall sense is that the convenience of using if-let directly in a few
 use cases doesn't justify making channels fall short of being able to send
 arbitrary values (nil specifically, and clearly boolean false can cause
 some problems too).

 I think it would be a much better design to have a sentinel value and a
 couple of specialised functions or macros that can detect  / interact with
 it appropriately. With a sentinel value the key part of your if-recv code
 could just be something like:

 `(let [~name (! ~port)]
   (if (end-of-stream? ~name)
 ~else
 ~then


 I can see that wrappers for nil values could also work, but that seems to
 be a more complex solution (and also potentially with more overhead) than a
 sentinel value


 On Saturday, 17 August 2013 07:50:06 UTC+8, Brandon Bloom wrote:

 I ran into the other half of this problem: If you expect nils to signify
 closed channels, then you can't leverage the logically false nature of nil
 without excluding explicit boolean false values. Given the pleasant syntax
 of if-let / ! pairs, I reworked my early experiments to use if-recv
 which is defined as follows:

 (defmacro if-recv
   Reads from port, binding to name. Evaluates the then block if the
   read was successful. Evaluates the else block if the port was closed.
   ([[name port :as binding] then]
`(if-recv ~binding ~then nil))
   ([[name port] then else]
`(let [~name (! ~port)]
   (if (nil? ~name)
 ~else
 ~then


 I've considered some alternative core.async designs, such as an
 additional done sentinel value, or a pair of quote/unquote operators (see
 reduced), but nothing seems as simple as just avoiding booleans and nils,
 as annoying as that is. I'd be curious to here what Rich  team
 considered and how they're thinking about it. However, my expectation is
 that the nil approach won't change, since it's pretty much good enough.

 On Thursday, August 15, 2013 10:44:48 PM UTC-4, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but
 bit I'm finding it *very* inconvenient that nil can't be sent over
 channels. In particular, you can't pipe arbitrary Clojure sequences through
 channels (since sequences can contain nils).

 I see this as a pretty big design flaw given the ubiquity of sequences
 in Clojure code - it appears to imply that you can't easily compose
 channels with generic sequence-handling code without some pretty ugly
 special-case handling.

 Am I missing something? Is this a real problem for others too?

 If it is a design flaw, can it be fixed before the API gets locked down?

  --
 --
 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 a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/pF9FEP7b77U/unsubscribe.
 To unsubscribe from this group and all its topics, 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 - handling nils

2013-08-17 Thread Ben Wolfson
A sentinel value also prevents channels from being able to send/receive 
arbitrary values, without further wrapping.

Sent from my iPhone

On Aug 17, 2013, at 5:48 PM, Mikera mike.r.anderson...@gmail.com wrote:

 My overall sense is that the convenience of using if-let directly in a few 
 use cases doesn't justify making channels fall short of being able to send 
 arbitrary values (nil specifically, and clearly boolean false can cause some 
 problems too). 
 
 I think it would be a much better design to have a sentinel value and a 
 couple of specialised functions or macros that can detect  / interact with it 
 appropriately. With a sentinel value the key part of your if-recv code could 
 just be something like:
 
 `(let [~name (! ~port)]
   (if (end-of-stream? ~name)
 ~else
 ~then
 
 I can see that wrappers for nil values could also work, but that seems to be 
 a more complex solution (and also potentially with more overhead) than a 
 sentinel value
 
 
 On Saturday, 17 August 2013 07:50:06 UTC+8, Brandon Bloom wrote:
 I ran into the other half of this problem: If you expect nils to signify 
 closed channels, then you can't leverage the logically false nature of nil 
 without excluding explicit boolean false values. Given the pleasant syntax 
 of if-let / ! pairs, I reworked my early experiments to use if-recv which 
 is defined as follows:
 
 (defmacro if-recv
   Reads from port, binding to name. Evaluates the then block if the
   read was successful. Evaluates the else block if the port was closed.
   ([[name port :as binding] then]
`(if-recv ~binding ~then nil))
   ([[name port] then else]
`(let [~name (! ~port)]
   (if (nil? ~name)
 ~else
 ~then
 
 I've considered some alternative core.async designs, such as an additional 
 done sentinel value, or a pair of quote/unquote operators (see reduced), 
 but nothing seems as simple as just avoiding booleans and nils, as annoying 
 as that is. I'd be curious to here what Rich  team considered and how 
 they're thinking about it. However, my expectation is that the nil approach 
 won't change, since it's pretty much good enough.
 
 On Thursday, August 15, 2013 10:44:48 PM UTC-4, Mikera wrote:
 
 Hi all,
 
 I'm experimenting with core.async. Most of it is exceptionally good, but 
 bit I'm finding it *very* inconvenient that nil can't be sent over 
 channels. In particular, you can't pipe arbitrary Clojure sequences through 
 channels (since sequences can contain nils). 
 
 I see this as a pretty big design flaw given the ubiquity of sequences in 
 Clojure code - it appears to imply that you can't easily compose channels 
 with generic sequence-handling code without some pretty ugly special-case 
 handling.
 
 Am I missing something? Is this a real problem for others too? 
 
 If it is a design flaw, can it be fixed before the API gets locked down?
 
 -- 
 -- 
 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 - handling nils

2013-08-16 Thread Brandon Bloom
I ran into the other half of this problem: If you expect nils to signify 
closed channels, then you can't leverage the logically false nature of nil 
without excluding explicit boolean false values. Given the pleasant syntax 
of if-let / ! pairs, I reworked my early experiments to use if-recv which 
is defined as follows:

(defmacro if-recv
  Reads from port, binding to name. Evaluates the then block if the
  read was successful. Evaluates the else block if the port was closed.
  ([[name port :as binding] then]
   `(if-recv ~binding ~then nil))
  ([[name port] then else]
   `(let [~name (! ~port)]
  (if (nil? ~name)
~else
~then


I've considered some alternative core.async designs, such as an additional 
done sentinel value, or a pair of quote/unquote operators (see 
reduced), but nothing seems as simple as just avoiding booleans and nils, 
as annoying as that is. I'd be curious to here what Rich  team considered 
and how they're thinking about it. However, my expectation is that the nil 
approach won't change, since it's pretty much good enough.

On Thursday, August 15, 2013 10:44:48 PM UTC-4, Mikera wrote:

 Hi all,

 I'm experimenting with core.async. Most of it is exceptionally good, but 
 bit I'm finding it *very* inconvenient that nil can't be sent over 
 channels. In particular, you can't pipe arbitrary Clojure sequences through 
 channels (since sequences can contain nils). 

 I see this as a pretty big design flaw given the ubiquity of sequences in 
 Clojure code - it appears to imply that you can't easily compose channels 
 with generic sequence-handling code without some pretty ugly special-case 
 handling.

 Am I missing something? Is this a real problem for others too? 

 If it is a design flaw, can it be fixed before the API gets locked down?


-- 
-- 
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 - handling nils

2013-08-16 Thread Ben Wolfson
On Fri, Aug 16, 2013 at 4:50 PM, Brandon Bloom brandon.d.bl...@gmail.comwrote:

 I ran into the other half of this problem: If you expect nils to signify
 closed channels, then you can't leverage the logically false nature of nil
 without excluding explicit boolean false values. Given the pleasant syntax
 of if-let / ! pairs, I reworked my early experiments to use if-recv
 which is defined as follows:

 (defmacro if-recv
   Reads from port, binding to name. Evaluates the then block if the
   read was successful. Evaluates the else block if the port was closed.
   ([[name port :as binding] then]
`(if-recv ~binding ~then nil))
   ([[name port] then else]
`(let [~name (! ~port)]
   (if (nil? ~name)
 ~else
 ~then


 I've considered some alternative core.async designs, such as an additional
 done sentinel value, or a pair of quote/unquote operators (see
 reduced), but nothing seems as simple as just avoiding booleans and nils,
 as annoying as that is. I'd be curious to here what Rich  team
 considered and how they're thinking about it. However, my expectation is
 that the nil approach won't change, since it's pretty much good enough.


One possibility is to retain nil as closed and have every other value
come wrapped in a Just or Some-like constructor, which an if-recv macro
would unwrap transparently, something like:

(defmacro if-recv [[name port] then else]
   `(let [~name (! ~port)]
  (if (nil? ~name)
  ~else
(let [~name (unwrap ~name)]
  ~then

That would enable sending of nils, since on the far side they'd be wrapped.

-- 
Ben Wolfson
Human kind has used its intelligence to vary the flavour of drinks, which
may be sweet, aromatic, fermented or spirit-based. ... Family and social
life also offer numerous other occasions to consume drinks for pleasure.
[Larousse, Drink entry]

-- 
-- 
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 - handling nils

2013-08-16 Thread Brandon Bloom
 have every other value come wrapped in a Just or Some-like constructor

That's what I meant by a pair of quote/unquote operators

-- 
-- 
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 - handling nils

2013-08-16 Thread Ben Wolfson
On Fri, Aug 16, 2013 at 5:07 PM, Brandon Bloom brandon.d.bl...@gmail.comwrote:

  have every other value come wrapped in a Just or Some-like constructor

 That's what I meant by a pair of quote/unquote operators


 ah, gotcha

-- 
Ben Wolfson
Human kind has used its intelligence to vary the flavour of drinks, which
may be sweet, aromatic, fermented or spirit-based. ... Family and social
life also offer numerous other occasions to consume drinks for pleasure.
[Larousse, Drink entry]

-- 
-- 
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.