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

2013-10-21 Thread Florian Weimer
* Steven Blenkinsop:

 On Saturday, 19 October 2013, Florian Weimer wrote:


 The problem is that if err is of type error, err != nil is true
 after the assignment of a pointer value to err.  So the usual error
 checking idiom doesn't work if your function returns a
 pointer-to-struct (that implements the error interface) instead of a
 (relatively opaque) error interface value.

 Don't do that. Return an error, not a naked error implementation. If people
 want to inspect it rather than treat it as a string, they'll do a type
 assertion rather than just a nil check.

Then the Go-level interface doesn't tell the programmer that the type
assertion continues working (i.e., that there is something to which
the caller can attach its extra information).

 Don't do that. Return either a nil error or a valid value of your error
 type. Seriously, the nil interface vs nil contents thing is only a tripping
 point for novices who don't understand what interfaces are, it's not
 something you run into once you've familiarized yourself with the language.

We'll see if that's true once we've got at analyzer that flags
this. :-)

 That's not a chaining mechanism.

 You're going to need to explain what you mean by this, then, and how it
 would apply to Rust. Note that if it's something very particular to how Go
 code is written, it's probably not constructive here.

Java exceptions have a getCause() mechanism which returns another
exception.

When you've got a piece of got that needs to provide further context
to exceptions that might be thrown by lower layers, it can at a
catch-all exception handler (well, usually for Exception, not
Throwable, so it's not quite catch-all) and throw a new exception,
specifying the existing exception as a cuase.

Traceback printing uses this information and suppresses identical
parts of the call stack, which often results in fairly useful output,
without resorting to more elaborate debugging mechanisms.

In contrast, I'm worried that error value threading (even when done
properly, not swallowing any errors) destroys potentially valuable
information about the context while the stack is (manually) unwound,
leaving little more than a bare error message when it's finally
reported or logged.
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


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

2013-10-19 Thread Steven Blenkinsop
On Saturday, 19 October 2013, Florian Weimer wrote:


 The problem is that if err is of type error, err != nil is true
 after the assignment of a pointer value to err.  So the usual error
 checking idiom doesn't work if your function returns a
 pointer-to-struct (that implements the error interface) instead of a
 (relatively opaque) error interface value.


Don't do that. Return an error, not a naked error implementation. If people
want to inspect it rather than treat it as a string, they'll do a type
assertion rather than just a nil check.

Rust doesn't have type assertions, however I feel this could be handled
satisfactorily by using concrete error types in Rust. Also, the whole nil
vs nil thing is irrelevant to Rust.


 Or put differently, if you put a typed null pointer into an interface
 value, the interface value keeps the type information and is therefore
 no longer equal to nil.


Don't do that. Return either a nil error or a valid value of your error
type. Seriously, the nil interface vs nil contents thing is only a tripping
point for novices who don't understand what interfaces are, it's not
something you run into once you've familiarized yourself with the language.

This wouldn't be an issue in Rust, since people would really have to go out
of their way to conflate an Err(None) with an Ok(v).

That's not a chaining mechanism.


You're going to need to explain what you mean by this, then, and how it
would apply to Rust. Note that if it's something very particular to how Go
code is written, it's probably not constructive here.
___
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-19 Thread Igor Bukanov
This is how we implemented error handling in Java. We defined an
abstract class ErrorSink like in:

class ErrorSink {
void addError(String s);
boolean hasError(s);
// few more methods to add extra attributes like line, file,
column etc of errors
}

A default implementation of the class just throws in the addError
method, but the requirement for addError callers is to assume that
method would not throw and try to recover or return some sensible
value. For example, a method like readFileAsString in case of
IOException reported that and returned an empty string.

A configuration parser that calls readFileAsString to read included
files has a custom implementation of ErrorSink that does not throw but
rather adds all errors on the list. At the end of parsing all those
errors plus all syntax violations was converted into a new detailed
report with proper line numbers etc and reported to the original sink.

This has number of benefits. All unexpected errors like dns failure
when reading URL are nicely formated showing the error origin. Various
low-level helpers like a date parser do not need to worry about
including proper context in the error message as that was
responsibility of the caller. This allowed to reuse the same parser in
GUI dialogs for a date input showing short and very informative
tooltip when user typed invalid date. It was trivial to add warnings
to the system extending the ErrorSink with an addWarning method and
turn those warnings into hard errors at runtime during testing via
simple throw. The callers would not need to check for errors at the
every method call.

The biggest drawback was the need to pass ErrorSink to a lot of
methods or store that as a member of many classes. We experimented
with using Java's thread locals instead, but that was rather
inflexible and inefficient.

I wonder why such error reporting is not used in other programs or languages.

On 18 October 2013 23:20, Florian Weimer f...@deneb.enyo.de wrote:
 * Igor Bukanov:

 So the Go style is to call a function, check if the was an error,
 update the error object (or create a new wrapping the old one) with
 extra information relevant to the current call stack frame and
 propagate the updated error object to the caller.

 It's more common to simply return the object.

 Due to some obscure feature of Go's type system, error values have to
 be interfaces and cannot be struct types, so I have not seen anyone
 trying to updating an existing error.  Wrapping might happen, but
 there is no general chaining mechanism like there is in Java.
___
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-18 Thread Ziad Hatahet
What about using Result types as mentioned here, but introducing some
syntactic sugar to make chaining them easier? Something like Haskell's or
Scala's do syntax:

do (
  a - x // x and y are Results
  b - y
) { /* do stuff with 'a' and 'b' */ }
else {
  /* First Err is returned. Handle here. */
}



--
Ziad


On Thu, Oct 17, 2013 at 9:40 PM, Igor Bukanov i...@mir2.org wrote:

 So the Go style is to call a function, check if the was an error,
 update the error object (or create a new wrapping the old one) with
 extra information relevant to the current call stack frame and
 propagate the updated error object to the caller. If done
 consistently, this could indeed provide very-user friendly error
 messages. But it does clutter the code with if checks and does not
 allow to recover so multiple errors could not be reported.

 In the above example the developer, before calling a parser library,
 may want to say that IO errors should be recovered from, so they could
 be reported together with other problems like syntax violations. I do
 not see how the Go style could be adopted to that. In its design the
 caller cannot influence the error propagation paths in the callee and
 its stack subframes.

 On 18 October 2013 05:29, Steven Blenkinsop steven...@gmail.com wrote:
  On Thursday, October 17, 2013, Igor Bukanov wrote:
 
 
  Go - I have not used the language, but my general impression is that
  no error will be generated. Instead the file will be read as an empty
  string.
 
 
  Go encodes the error as a value which can be either treated as a string
 or
  programmatically inspected to determine the correct response and returns
 it
  along with an invalid file handle. If the code doesn't actually
 specifically
  handle permission problems, it will usually create a new error value
  embedding the original error along with some context about what it was
 doing
  when it got the error. This new error can then be used as a failure
 value or
  passed up the stack, or it may be logged (potentially in combination with
  one of the other two options). This means that, even if the developer
 didn't
  anticipate permissions issues, the error will likely contain all the
  relevant information, such as what line of the configuration file was
 being
  processed as well as what file failed to open and why.
 ___
 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-18 Thread Ziad Hatahet
I came across this blog post which may be relevant:
https://coderwall.com/p/kokm7w

--
Ziad


On Fri, Oct 18, 2013 at 10:23 AM, Ziad Hatahet hata...@gmail.com wrote:

 What about using Result types as mentioned here, but introducing some
 syntactic sugar to make chaining them easier? Something like Haskell's or
 Scala's do syntax:

 do (
   a - x // x and y are Results
   b - y
 ) { /* do stuff with 'a' and 'b' */ }
 else {
   /* First Err is returned. Handle here. */
 }



 --
 Ziad


 On Thu, Oct 17, 2013 at 9:40 PM, Igor Bukanov i...@mir2.org wrote:

 So the Go style is to call a function, check if the was an error,
 update the error object (or create a new wrapping the old one) with
 extra information relevant to the current call stack frame and
 propagate the updated error object to the caller. If done
 consistently, this could indeed provide very-user friendly error
 messages. But it does clutter the code with if checks and does not
 allow to recover so multiple errors could not be reported.

 In the above example the developer, before calling a parser library,
 may want to say that IO errors should be recovered from, so they could
 be reported together with other problems like syntax violations. I do
 not see how the Go style could be adopted to that. In its design the
 caller cannot influence the error propagation paths in the callee and
 its stack subframes.

 On 18 October 2013 05:29, Steven Blenkinsop steven...@gmail.com wrote:
  On Thursday, October 17, 2013, Igor Bukanov wrote:
 
 
  Go - I have not used the language, but my general impression is that
  no error will be generated. Instead the file will be read as an empty
  string.
 
 
  Go encodes the error as a value which can be either treated as a string
 or
  programmatically inspected to determine the correct response and
 returns it
  along with an invalid file handle. If the code doesn't actually
 specifically
  handle permission problems, it will usually create a new error value
  embedding the original error along with some context about what it was
 doing
  when it got the error. This new error can then be used as a failure
 value or
  passed up the stack, or it may be logged (potentially in combination
 with
  one of the other two options). This means that, even if the developer
 didn't
  anticipate permissions issues, the error will likely contain all the
  relevant information, such as what line of the configuration file was
 being
  processed as well as what file failed to open and why.
 ___
 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-18 Thread Florian Weimer
* Patrick Walton:

 In other words: Why bet, as Go did, that the failure case won't
 happen much in practice when we can adopt an error-handling strategy
 that rules it out entirely?

Uh-oh, I thought that Rust has ruled out error handling constructs
based on implicit control flow? :-)

But seriously, *this* particular issue is pretty well addressed by
(unchecked) exceptions.  They definitely encourage developers not to
neglect error propagation.
___
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-18 Thread Florian Weimer
* Igor Bukanov:

 So the Go style is to call a function, check if the was an error,
 update the error object (or create a new wrapping the old one) with
 extra information relevant to the current call stack frame and
 propagate the updated error object to the caller.

It's more common to simply return the object.

Due to some obscure feature of Go's type system, error values have to
be interfaces and cannot be struct types, so I have not seen anyone
trying to updating an existing error.  Wrapping might happen, but
there is no general chaining mechanism like there is in Java.
___
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-17 Thread Steven Blenkinsop
On Wednesday, 16 October 2013, Chris Morgan wrote:

 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

It baffles me too, so it's good that Go doesn't actually let you do this
:P. You have to either ignore all return values, or explicitly ignore any
you don't want using _. You might be thinking of the comma-ok notation for
certain built-in expressions...
___
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-17 Thread Ziad Hatahet
On Wed, Oct 16, 2013 at 3:38 PM, Patrick Walton pwal...@mozilla.com wrote:

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



I tried the following code snippet, but nothing got printed out. What am I
missing?

-- cut --

struct S;

impl Drop for S {
fn drop(mut self) {
println(drop);
}
}

fn main() {
let _ = S;
}


--end cut --

Replacing `let _` with `let _s` printed drop as expected.

Thanks

--
Ziad
___
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-17 Thread Daniel Micay
On Thu, Oct 17, 2013 at 2:06 AM, Ziad Hatahet hata...@gmail.com wrote:



 On Wed, Oct 16, 2013 at 3:38 PM, Patrick Walton pwal...@mozilla.comwrote:

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



 I tried the following code snippet, but nothing got printed out. What am I
 missing?

 -- cut --

 struct S;

 impl Drop for S {
 fn drop(mut self) {
 println(drop);
 }
 }

 fn main() {
 let _ = S;
 }


 --end cut --

 Replacing `let _` with `let _s` printed drop as expected.

 Thanks

 --
 Ziad


https://github.com/mozilla/rust/issues/6892
___
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-17 Thread Ziad Hatahet
Thanks for the quick response :)

--
Ziad


On Wed, Oct 16, 2013 at 11:08 PM, Daniel Micay danielmi...@gmail.comwrote:

 On Thu, Oct 17, 2013 at 2:06 AM, Ziad Hatahet hata...@gmail.com wrote:



 On Wed, Oct 16, 2013 at 3:38 PM, Patrick Walton pwal...@mozilla.comwrote:

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



 I tried the following code snippet, but nothing got printed out. What am
 I missing?

 -- cut --

 struct S;

 impl Drop for S {
 fn drop(mut self) {
 println(drop);
 }
 }

 fn main() {
 let _ = S;
 }


 --end cut --

 Replacing `let _` with `let _s` printed drop as expected.

 Thanks

 --
 Ziad


 https://github.com/mozilla/rust/issues/6892

___
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-17 Thread Florian Weimer
* Chris Morgan:

 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.

I did an informal study some time ago, and it does not appear to be
that common a mistake.  (I was biased and tried to prove that the
current state of affairs what bad, but the results weren't
convincing.)  It only happens when there are no results whatsoever.
If there are results that need processing, programmers do some form of
error handling or threading.

There is, however, one major design blunder.  Some of the I/O
interfaces (Reader, ReaderAt etc.) do not follow the rest of the
standard library in treating the result/error return as a sum type.
In the rest of the library, you have to check the error first because
it is often not possible to see from the result itself that it is part
of an error (say, the value 0 from an string-to-inter parsing
routine).  With I/O, you have to check the result first because some
of the interfaces are specified to return both data and an error.
Here's an example for io.Reader: http://golang.org/pkg/io/#Reader

Rust shouldn't have this problem if it uses a proper sum type, and
even with Go the language, it would have been possible to avoid this
mess with a better choice in Go the library.
___
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-17 Thread Patrick Walton

On 10/17/13 11:54 AM, Florian Weimer wrote:

* Chris Morgan:


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.


I did an informal study some time ago, and it does not appear to be
that common a mistake.  (I was biased and tried to prove that the
current state of affairs what bad, but the results weren't
convincing.)  It only happens when there are no results whatsoever.
If there are results that need processing, programmers do some form of
error handling or threading.


On the other hand, Cindy Rubio-González's work shows that in the Linux 
kernel, forgetting to handle error codes is *extremely* common.


http://www.eecs.berkeley.edu/~rubio/

I don't see anything fundamentally different with Go's approach that 
will lead to a different outcome.


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-17 Thread Florian Weimer
* Patrick Walton:

 On the other hand, Cindy Rubio-González's work shows that in the Linux
 kernel, forgetting to handle error codes is *extremely* common.

 http://www.eecs.berkeley.edu/~rubio/

 I don't see anything fundamentally different with Go's approach that
 will lead to a different outcome.

The kernel usually passes results by storing them in an existing
object because allocation by the callee is less efficient and
impossible in many contexts.  Go has garbage collection, and returning
a new object and an error return value is the more common style.  The
result-plus-error case has a much better chance of being handled
correctly.

Go also has exceptions (for signaling certain errors).  I'm not sure
if it deals with memory allocation failures gracefully.  If it
doesn't, that would eliminate a fair chunk of kernel error handling,
too.

So in short, Go is quite different. :-)
___
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-17 Thread Patrick Walton
You make a good case that it happens less in Go, but I'm still not sold on Go's 
error handling, given that it's fundamentally built on a model that's known to 
be error-prone. We know that the flaw of error-code-based systems without 
checked returns is that you can forget to handle errors. Go makes this harder 
in many situations, but it has known holes when the function returns nothing 
but an error or the function is invoked only for its side effects. I don't see 
any reason why we should deliberately go with a system with known flaws and 
failure modes when there are better alternatives available.

In other words: Why bet, as Go did, that the failure case won't happen much in 
practice when we can adopt an error-handling strategy that rules it out 
entirely?

Florian Weimer f...@deneb.enyo.de wrote:
* Patrick Walton:

 On the other hand, Cindy Rubio-González's work shows that in the
Linux
 kernel, forgetting to handle error codes is *extremely* common.

 http://www.eecs.berkeley.edu/~rubio/

 I don't see anything fundamentally different with Go's approach that
 will lead to a different outcome.

The kernel usually passes results by storing them in an existing
object because allocation by the callee is less efficient and
impossible in many contexts.  Go has garbage collection, and returning
a new object and an error return value is the more common style.  The
result-plus-error case has a much better chance of being handled
correctly.

Go also has exceptions (for signaling certain errors).  I'm not sure
if it deals with memory allocation failures gracefully.  If it
doesn't, that would eliminate a fair chunk of kernel error handling,
too.

So in short, Go is quite different. :-)

-- 
Sent from my Android phone with K-9 Mail. Please excuse my brevity.___
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-17 Thread Igor Bukanov
To make discussion about a way to handle IO errors less generic
consider a hypothetical program that that reads some configuration
files that have include  statements and suppose that one of the
included files could not be read due to bad permissions. Ideally a
user should receive a message like that include statement in file
foo.conf line 123 could not be processed due to bad permissions. In
the real world, especially if the permission problem would not be
anticipated by the developer, a typical program I suppose would behave
like:

C - program terminates with an abort message about permission
problems. The message may include the name of the file, but there
would be no information about the location of that include statement
or even that the error happened during parsing of config files.

Java and Python - a stack trace will be generated with error message
similar to the C case. To the developer the stack trace tells that it
was generated during parsing of the include statement, but the user
will have no clue.

Go - I have not used the language, but my general impression is that
no error will be generated. Instead the file will be read as an empty
string.

The question is can Rust provide such error handling so the ideal
scenario can be implemented with minimal efforts?

From a personal experience in Java the solution was to pass an extra
Reporter interface parameter into most of the parser and IO supporting
libraries and stop using exceptions. Various program components then
implemented that interface to add information about error location and
conditions. The Reporter interface also provided a way to query about
the current error status.

Surprisingly with this setup besides the extra reporter parameter the
source was not clattered with return status checks as the code style
became to report errors, but still return sensible defaults (like
reading the file as empty string). This way the caller can proceed as
if error would not happen, but the report would not be lost. As an
added benefit reporting several errors became trivial.

On 17 October 2013 21:59, Patrick Walton pwal...@mozilla.com wrote:
 You make a good case that it happens less in Go, but I'm still not sold on
 Go's error handling, given that it's fundamentally built on a model that's
 known to be error-prone. We know that the flaw of error-code-based systems
 without checked returns is that you can forget to handle errors. Go makes
 this harder in many situations, but it has known holes when the function
 returns nothing but an error or the function is invoked only for its side
 effects. I don't see any reason why we should deliberately go with a system
 with known flaws and failure modes when there are better alternatives
 available.

 In other words: Why bet, as Go did, that the failure case won't happen much
 in practice when we can adopt an error-handling strategy that rules it out
 entirely?

 Florian Weimer f...@deneb.enyo.de wrote:

 * Patrick Walton:


 On the other hand, Cindy Rubio-González's work shows that in the Linux
 kernel, forgetting to handle error codes is *extremely* common.

 http://www.eecs.berkeley.edu/~rubio/

 I don't see anything fundamentally different with Go's approach that
 will lead to a different outcome.


 The kernel usually passes results by storing them in an existing
 object because allocation by the callee is less efficient and
 impossible in many contexts.  Go has garbage collection, and returning
 a new object and an error return value is the more common style.  The
 result-plus-error case has a much better chance of being handled
 correctly.

 Go also has exceptions (for signaling certain errors).  I'm not sur
  e
 if it deals with memory allocation failures gracefully.  If it
 doesn't, that would eliminate a fair chunk of kernel error handling,
 too.

 So in short, Go is quite different. :-)


 --
 Sent from my Android phone with K-9 Mail. Please excuse my brevity.

 ___
 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-17 Thread Steven Blenkinsop
On Thursday, October 17, 2013, Igor Bukanov wrote:


 Go - I have not used the language, but my general impression is that
 no error will be generated. Instead the file will be read as an empty
 string.


Go encodes the error as a value which can be either treated as a string or
programmatically inspected to determine the correct response and returns it
along with an invalid file handle. If the code doesn't actually
specifically handle permission problems, it will usually create a new error
value embedding the original error along with some context about what it
was doing when it got the error. This new error can then be used as a
failure value or passed up the stack, or it may be logged (potentially in
combination with one of the other two options). This means that, even if
the developer didn't anticipate permissions issues, the error will likely
contain all the relevant information, such as what line of the
configuration file was being processed as well as what file failed to open
and why.
___
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-17 Thread Igor Bukanov
So the Go style is to call a function, check if the was an error,
update the error object (or create a new wrapping the old one) with
extra information relevant to the current call stack frame and
propagate the updated error object to the caller. If done
consistently, this could indeed provide very-user friendly error
messages. But it does clutter the code with if checks and does not
allow to recover so multiple errors could not be reported.

In the above example the developer, before calling a parser library,
may want to say that IO errors should be recovered from, so they could
be reported together with other problems like syntax violations. I do
not see how the Go style could be adopted to that. In its design the
caller cannot influence the error propagation paths in the callee and
its stack subframes.

On 18 October 2013 05:29, Steven Blenkinsop steven...@gmail.com wrote:
 On Thursday, October 17, 2013, Igor Bukanov wrote:


 Go - I have not used the language, but my general impression is that
 no error will be generated. Instead the file will be read as an empty
 string.


 Go encodes the error as a value which can be either treated as a string or
 programmatically inspected to determine the correct response and returns it
 along with an invalid file handle. If the code doesn't actually specifically
 handle permission problems, it will usually create a new error value
 embedding the original error along with some context about what it was doing
 when it got the error. This new error can then be used as a failure value or
 passed up the stack, or it may be logged (potentially in combination with
 one of the other two options). This means that, even if the developer didn't
 anticipate permissions issues, the error will likely contain all the
 relevant information, such as what line of the configuration file was being
 processed as well as what file failed to open and why.
___
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