[rust-dev] How to manage multiple interacting I/O streams?

2013-10-16 Thread Andreas Neuhaus
Hi everybody,

after using Rust for the last few months to get used to it (I really love it), 
I recently started to play around with the new I/O, especially the networking 
stuff. I'd say that I'm familiar with how std::rt.:io, std::task and std::comm 
works. However I'm not sure how I should handle multiple I/O streams.

Let's say I'm building a simple chat server where people can connect on a TCP 
port, set a name and broadcast messages to everyone else. For each accepted 
incoming stream, I'd spawn a new task and pass the stream to it. Or actually 
I'd create a struct Connection that contains the stream and connection related 
information, like the user's name. Every child task would run a loop that reads 
a line from its stream and processes it. It should either broadcast to all 
other connections or do something else like setting the name.

How can one connection write stuff to the others if it doesn't know about them? 
If I use a chan/port for every connection to report text to be broadcasted back 
to the main task, the broadcast needs to take place in the main task. But the 
main task can not hold a list of connections since every connection has moved 
to its own task where the reading loop takes place. There could be a second 
chan/port for every connection that allows the main task to send something to a 
connection, but how would a connection's task be supposed to recv from the port 
when it's generally waiting to read from the stream most time?

I'm also unsure how the main task should be able to iterate all connection, 
e.g. if somebody wants to list all connected users.

I'd appreciate any hint on how this can be done the Rust-way. (I thereby want 
to prevent using @-boxes at all)

Thanks,
Andreas

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Should I/O use conditions?

2013-10-16 Thread Alex Crichton
There have been some recent grumblings [1] about the use of conditions in the
new runtime's I/O system. It was decided awhile back [2] that we'd try out the
use of conditions for error handling in the new runtime. This has manifested
itself in the `io_error` and `read_error` conditions inside of the `rt::io`
module.

I've done some recent work [3][4] in removing std::io, and I've personally
found the use of conditions a little painful. Here's a few of the problems that
I ran into:

* Do you catch io_error or read_error? Catching both is really painful, and
  remembering which one to catch is sometimes more painful. This could be
  alleviated by having a read_error raise on an io_error if there is no handler
  registered, so this is certainly not a show stopper.

* If you want to catch an error, it's pretty ergonomically painful

let mut err = None;
let ret = do io::io_error::cond.trap(|e| err = Some(e)).inside {
// some i/o operation
};
match err {
None = {} // yay we succeeded
Some(e) {} // oh no, an error!
}

This seems like a lot of verbage for doing something as simple as checking
to see whether an i/o operation resulted in an error or not.

* Using closures prevents certain kinds of movements between values. This is a
  known limitation of closures today and may be alleviated by the closure
  redesign, however. This isn't quite a show stopper, but it is another pain
  point.

* The blanket error condition isn't really being used for what I thought
  conditions were intended for, which is somehow continuing the work at the
  raise site using the result of the condition. Because the io error conditions
  both return (), then there's not really anything you can do but hope to
  squirrel away the conditions somewhere.

These various reasons have added to the pain points when dealing with error
handling in the new runtime. I certainly don't think that we should remove
conditions entirely (they're an effective error handling system for many
purposes), but for the use case of simply reporting errors I don't feel that
they're quite appropriate.

All that being said, we're not making much progress without an idea of where to
possibly go next. Right now, the current idea is to create an Error trait and
have I/O operations return ResultT, ~Error instead of OptionT. This would
mean that Reader/Writer and other associated traits would be defined for
ResultT, ~Error where T: Trait (so you could still chain operations easily),
and you could very easily check for an I/O error.

This is all still pretty early-stage, though, and we certainly haven't committed
to anything just yet. I wanted to canvas everyone to see what others' opinions
are about using conditions for error handling. I'm certainly not the only
use-case so far!

[1] https://github.com/mozilla/rust/issues/9795
[2] https://mail.mozilla.org/pipermail/rust-dev/2013-April/003746.html
[3] https://github.com/mozilla/rust/pull/9749
[4] https://github.com/mozilla/rust/pull/9888
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Patrick Walton

On 10/16/13 11:02 AM, Alex Crichton wrote:

All that being said, we're not making much progress without an idea of where to
possibly go next. Right now, the current idea is to create an Error trait and
have I/O operations return ResultT, ~Error instead of OptionT. This would
mean that Reader/Writer and other associated traits would be defined for
ResultT, ~Error where T: Trait (so you could still chain operations easily),
and you could very easily check for an I/O error.


+1 for the use of Result. Yay monads!

Patrick

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Kevin Ballard
+1 here too. I agree with what Alex said about conditions. They're useful for 
when you can actually recover from the error gracefully, but for generic error 
reporting they're kind of a PITA.

-Kevin

On Oct 16, 2013, at 11:16 AM, Patrick Walton pwal...@mozilla.com wrote:

 On 10/16/13 11:02 AM, Alex Crichton wrote:
 All that being said, we're not making much progress without an idea of where 
 to
 possibly go next. Right now, the current idea is to create an Error trait and
 have I/O operations return ResultT, ~Error instead of OptionT. This would
 mean that Reader/Writer and other associated traits would be defined for
 ResultT, ~Error where T: Trait (so you could still chain operations 
 easily),
 and you could very easily check for an I/O error.
 
 +1 for the use of Result. Yay monads!
 
 Patrick
 
 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev



smime.p7s
Description: S/MIME cryptographic signature
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Steven Fackler
+1 on getting rid of IO conditions. I'd be okay with a Result based API. If
we change it over, we should have a tutorial that goes over how to deal
with Results to make it less painful for people (e.g. using or_return!
macros).

I'm not a huge fan of implementing Reader for ResultReader, ~Error, etc.
One thing that I've tried that I kind of like is having separate `foo` and
`try_foo` methods, where `try_foo` returns a Result and `foo` is a wrapper
around `try_foo` that fails with a good error message if `foo` returned
Err. It makes it more explicit to users of the API what's going to happen,
and when failure will occur if there's an error. A failed ResultT, ~Error
can hang around for a long time before any methods are called on it. It can
also allow for slightly better failure messages. For example, if `prepare`
fails, its error message can print the query string without having to copy
it into a new ~str. In the IO case, you could keep this cost free to
implement by having `Reader` contain a default implementation for `read`
and only require users to implement `try_read`. See
http://docs.octayn.net/postgres/struct.PostgresConnection.html for some
examples.

Steven Fackler


On Wed, Oct 16, 2013 at 11:20 AM, Kevin Ballard ke...@sb.org wrote:

 +1 here too. I agree with what Alex said about conditions. They're useful
 for when you can actually recover from the error gracefully, but for
 generic error reporting they're kind of a PITA.

 -Kevin

 On Oct 16, 2013, at 11:16 AM, Patrick Walton pwal...@mozilla.com wrote:

  On 10/16/13 11:02 AM, Alex Crichton wrote:
  All that being said, we're not making much progress without an idea of
 where to
  possibly go next. Right now, the current idea is to create an Error
 trait and
  have I/O operations return ResultT, ~Error instead of OptionT. This
 would
  mean that Reader/Writer and other associated traits would be defined for
  ResultT, ~Error where T: Trait (so you could still chain operations
 easily),
  and you could very easily check for an I/O error.
 
  +1 for the use of Result. Yay monads!
 
  Patrick
 
  ___
  Rust-dev mailing list
  Rust-dev@mozilla.org
  https://mail.mozilla.org/listinfo/rust-dev


 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Bill Myers
What about the idea of making Result cause task failure if it is destroyed in 
the error case? (as opposed to destructuring it)

This just needs a simple language change to add an attribute that would be 
applied on Result to declare that it's OK to destructure it and cause drop() to 
not be called.

In addition, maybe some EH syntax sugar like the one I proposed in 
http://www.mail-archive.com/rust-dev@mozilla.org/msg04093.html

  ___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Patrick Walton

On 10/16/13 1:44 PM, Bill Myers wrote:

What about the idea of making Result cause task failure if it is
destroyed in the error case? (as opposed to destructuring it)


For a long time now I've been wanting to make unused non-unit return 
values a warning. I think this would be a perfect time to do that...


Patrick

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Kevin Ballard
This seems rather heavy-weight to me. I’d much prefer if such a thing was 
opt-in, e.g. by a function attribute that says the return value must be handled.

-Kevin

On Oct 16, 2013, at 2:12 PM, Patrick Walton pwal...@mozilla.com wrote:

 On 10/16/13 1:44 PM, Bill Myers wrote:
 What about the idea of making Result cause task failure if it is
 destroyed in the error case? (as opposed to destructuring it)
 
 For a long time now I've been wanting to make unused non-unit return values a 
 warning. I think this would be a perfect time to do that...
 
 Patrick
 
 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Chris Morgan
On Oct 17, 2013 8:12 AM, Patrick Walton pwal...@mozilla.com wrote:
 For a long time now I've been wanting to make unused non-unit return
values a warning. I think this would be a perfect time to do that...

I would love this to be the case. It's the biggest problem I had with Go's
error handling: that it's far too easy to just ignore a return value
accidentally. (Truth to tell, the problem is far worse in Go because for
some reason they decided you could take not all of the return values, e.g.
for a func returning (T, err), `t = f()` will silently discard the err;
this has been a decision that has baffled me; I'm glad we have generics and
Result and tuples-as-real-types to fix that bad idiom!) Truly explicit is
better than implicit.

I have three remaining questions on this feature:

1. Is there a functional difference between the lines `let _ = f()` and
`let _foo = f()` (assuming no usage of the variable)? These will probably
become common if this check is in place.

2. When will Drop happen? I suspect this would make it happen at the end of
the callee block, whereas silent ignoring probably before returning
execution to the callee?

3. Would such a thing be able to be overridden with something along the
lines of #[allow(unused_return_values)]?
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Should I/O use conditions?

2013-10-16 Thread Patrick Walton

On 10/16/13 3:31 PM, Chris Morgan wrote:

1. Is there a functional difference between the lines `let _ = f()` and
`let _foo = f()` (assuming no usage of the variable)? These will
probably become common if this check is in place.


There's no difference except that let _ runs the destructor 
immediately whereas let _foo runs the destructor at the end of the 
block. (This is admittedly subtle.)



2. When will Drop happen? I suspect this would make it happen at the end
of the callee block, whereas silent ignoring probably before returning
execution to the callee?


See above.


3. Would such a thing be able to be overridden with something along the
lines of #[allow(unused_return_values)]?


Yes, and on a per-callee basis as well. (Lots of C functions want return 
values to be ignorable, so this should be able to be specified.)


Patrick

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Proposal for macro invocation sugar

2013-10-16 Thread Marvin Löbel
Hello! I was thinking a bit about macros, and I had an idea for a kind 
of syntactic sugar that might be useful to have. I also posted this to 
the issue tracker at https://github.com/mozilla/rust/issues/9894.


# Current situation

Right now, rust knows about two kinds of macro invocation:

IDENT!(...)
IDENT! IDENT (...)

The latter one is just used by `macro_rules!` right now, and seems kinda 
out of place because of that.


Additionally, just being restricted to `IDENT!(...)` means that, while 
you can define macros just fine, the resulting invocation syntax often 
looks a bit weird because of the need for the outer `()` pair.


For example, if you want to write some kind of custom `match` macro you 
ideally want a syntax like `macro! EXPR { CASES... }`, but in practice 
are forced to decide between redundant, deeply nested brackets or weird 
syntax if you want to reduce the brackets:


~~~
my_match!(
foo().bar().baz() {
case 1 = ...
case 2 = ...
...
}
)

my_match!(foo().bar().baz() cases:
case 1 = ...
case 2 = ...
...
)
~~~

# Proposal

We can't just allow macros to accept different syntax like `IDENT! EXPR 
( ... )`, because it would create ambiguity in the parser, but it 
occurred to me that we _can_ provide syntactic sugar for transforming 
'nicer looking' variants into the regular `IDENT!(...)` syntax.


Basically, I'm thinking of leveraging the bang in a macro invocation to 
annotate how many following bracket pairs to group into one regular 
macro invocation:


~~~
IDENT!! (...) (...) = desugaring = IDENT!((...) (...))
IDENT!!! (...) (...) (...)  = desugaring = IDENT!((...) (...) (...))
... etc
~~~

The number of bangs could become confusing fast, but I don't expect that 
macros with more than two bracket groups are going to be common. And 
because it would just be sugar, you could always write it as the regular 
form.


# Advantages

There are a number of advantages I see with this proposal:

1. The two macro invocation forms can be folded into one:
   ~~~
   IDENT!(...)= IDENT!(...)
   IDENT! IDENT (...) = IDENT!! (IDENT) (...) == IDENT!((IDENT) (...))
   ~~~

2. Custom syntax can become nicer looking, especially for control 
structures.

   Looking at the `my_match` example:
   ~~~
   my_match!! (foo().bar().baz()) {
   case 1 = ...
   case 2 = ...
   ...
   }
   ~~~
   ... which looks more natural than any the two options outlined above.

3. It's pure syntactic sugar, which means it's easy to implement and 
reason about.
   All `libsyntax` needs to do is to consume a list of bracket-counted 
token trees
   equal to the number of bangs, and introduce an artificial outer 
bracket pair if

   the number is higher than one.

4. It's just invocation sugar, which means there is no difference 
between defining a
   macro that uses this vs one that doesn't - you just declare them all 
assuming the

   explicit outer `()` pair.

# Potential issues

The possible issues I can see with this are confusing error messages if 
the number of bangs is wrong, and uncertainty about which brackets 
belong to a macro invocation and which are regular rust code if their 
contents become big and/or their number become high.


However, in theory rust might be able to provide good error messages for 
the first one, because if the macro name is right you'd get an `No rules 
expected this ...` error, and there could be some heuristics for 
recognizing cases where the user has do add/remove bangs to match the 
macro definition.


And the second one can likely be managed by syntax highlighting, and by 
the usual convention of not abusing the syntax to the point where it 
becomes illegible.


# Backwards compatibility

Adding this sugar would be backwards compatible because it doesn't 
change any existing macro syntax, however if `IDENT! IDENT (...)` ends 
up obsolete through this, that would break existing uses of 
`macro_rules!` - but macros are behind a feature flag anyway at this 
point, so it wouldn't matter as much.


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Audio for Rust: A Friendly Introduction now available

2013-10-16 Thread Cadence Marseille
Hi Tim,

Thanks for posting these.  I haven't listened to the audio, but I read
through the slides and I like your presentation.  For me, it is a good
reminder of why Rust is so cool.

I don't know about other users (survey time, anyone? [?]), but my background
is mostly C++ and Java.  The notes about C++ vs. Rust are helpful.

Cadence


On Tue, Oct 15, 2013 at 2:28 PM, Tim Chevalier catamorph...@gmail.comwrote:

 Hi all,

 The audio recording for my June 2013 talk at Open Source Bridge,
 Rust: A Friendly Introduction, is now available:

 http://opensourcebridge.org/sessions/970

 As far as I know, there was no video recording, but the slides are linked
 from:

 http://opensourcebridge.org/wiki/2013/Rust%3A_A_Friendly_Introduction

 Cheers,
 Tim


 --
 Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt
 Being queer is not about a right to privacy; it is about the freedom
 to be public, to just be who we are. -- anonymous, June 1990
 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev

330.gif___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev