>From a previous life (with Icon), I'm almost tempted to return as erroneous 
as possible a value along with a non-nil error.
On a 36-bit Honeywell, there was a value that was an illegal int, float and 
pointer.  I want to return that (;-))

--dave (wearing his Dr Evil hat) c-b
[Are you the Dave Cheney from the University of Waterloo? Thoth, Port and 
the electric trains course?]

On Saturday, April 1, 2017 at 7:41:45 AM UTC-4, Dave Cheney wrote:
>
>
>
> On Saturday, 1 April 2017 22:26:20 UTC+11, Axel Wagner wrote:
>>
>> Ian:
>> Re your question: See my example given above (or the one below, which is 
>> probably more authentic). For example, you might be allocating the returned 
>> struct, and piece by piece filling in the fields. If there can be errors, 
>> the natural expression might be, to just return the allocated struct, 
>> whereas to then return nil, you need to explicitly branch. For example, say 
>> I'd want to have a type which operates on some file:
>>
>> type Foo struct {
>>     file *os.File
>> }
>>
>> func NewFoo(fname string) (*Foo, error) {
>>     f, err := os.Open(fname)
>>     return &Foo{
>>         file: f,
>>     }, err
>> }
>>
>> vs.
>>
>> func NewFoo(fname string) (*Foo, error) {
>>     f, err := os.Open(fname)
>>     if err != nil {
>>         return nil, err
>>     }
>>     return &Foo{
>>         file: f,
>>     }, nil
>> }
>>
>> I would usually write the latter version, even if the former is shorter 
>> and the extra branch isn't necessary, because people shouldn't rely on the 
>> first return if there's an error anyway.
>> Because I do feel like people might not be so careful and then 
>> dereferencing a nil *Foo will be a clearer symptom to debug, than debugging 
>> whatever weird value Open might theoretically return being used 
>> accidentally.
>>
>> On Sat, Apr 1, 2017 at 2:26 AM, Dave Cheney <da...@cheney.net> wrote:
>>
>>> On 1 Apr 2017, at 11:02, Axel Wagner <axel.wa...@googlemail.com> wrote:
>>>
>>> On Sat, Apr 1, 2017 at 1:50 AM, Dave Cheney <da...@cheney.net> wrote:
>>>
>>>>
>>>>
>>>> On 1 Apr 2017, at 10:41, Axel Wagner <axel.wa...@googlemail.com> wrote:
>>>>
>>>> So… Given that I'm *not* talking about modifying any contract - see a) 
>>>> in my previous message - but just making an effort that I'm not 
>>>> contractual 
>>>> bound by, I am not sure how I am supposed to read this. Is this an 
>>>> argument 
>>>> for not being helpful? Because I don't quite see how your point 
>>>> invalidates 
>>>> that. Or is it an argument for being hurtful? Which I also don't really 
>>>> see, as I'm not talking about any change in contract.
>>>>
>>>> Like, I legit starting to doubt my sanity here; I don't see how I can 
>>>> actually be any clearer about how I do not intend to change anything about 
>>>> the "if a non-nil error is returned, assume the returns are invalid" rule. 
>>>> The question is "how is it hurtful, if I then also add an extra layer of 
>>>> defense against people violating that contract"?
>>>>
>>>>
>>>> But why? Why encourage people to be reckless. IMO this is difference 
>>>> between map ordering during iteration being undefined, which it is, rather 
>>>> than guaranteed to be random, which is not.
>>>>
>>>
>>> Great point. Why does gc implement it that way, then? And does it hurt, 
>>> that gc implement it that way? The contract does not contain anything about 
>>> the iteration order, so why did we add that code and CPU time to explicitly 
>>> randomize it, instead of just letting buggy code be buggy and blow up at 
>>> some point with hard to debug errors? This seems to be essentially the 
>>> argument you are making, so why does it, seemingly, not apply to randomized 
>>> map iteration in gc?
>>>
>>>
>>> Map ordering is undefined by the spec, some implementations choose to 
>>> randomise the order but this is an implementation detail.
>>>
>>
>> But that is what I'm saying. The equivalency of the spec here is the API 
>> contract and I am not changing that, but I'm changing an implementation 
>> detail (and also reserve the right to change that later). It is incredibly 
>> frustrated that you seem to continue to suppose I'm trying to somehow make 
>> this a guarantee or part of the API contract, when I said so often that I'm 
>> not.
>>
>
> But you are. I've been very clear that if there is an error the caller can 
> assume nothing about the state of an other variable; they are, like the 
> floor, lava.
>  
>
>>  
>>
>>> Both are contracts with the same result to the casual user -- map 
>>>> iteration is unpredictable, but by not guaranteeing that the order will be 
>>>> random, it prevents people relying on the side effect.
>>>>
>>>> This is the argument I'm making now, yes, you could go to effort to 
>>>> make sure that some of the values you return are nil so that they explode 
>>>> as soon as someone forgets to check an error, but you probably shouldn't 
>>>> because
>>>>
>>>> A, this is providing a stronger contract than necessary.
>>>>
>>>
>>> No, it is not. The contract is the same. I'm sorry to be a stickler 
>>> here, but I really don't see why this point is so elusive. I am not 
>>> suggesting adding a "if an error is returned, the other return values will 
>>> have their zero value" to my godoc.
>>>
>>>
>>> No, it's not. One is "in the presence of an error, the other values 
>>> returned are undefined", your contract is "in the presence of an error, the 
>>> others values returned will be their respective zero value"
>>>
>>
>> No, this is categorically not what I'm suggesting and I have been very 
>> explicit about that.
>> I'm saying "I'll try to do X, because I think it's sometimes helpful", 
>> not "I promise you that I will always do X, so trust me on this". Just like 
>> gc decided to randomize the map-iteration order to expose bugs where code 
>> relies on iteration order but did not change the spec 
>>
>
> You cannot write a useful API contract that says "in the event of an 
> error, we'll try to return a useful zero value", because a confirming 
> implementation can simply _not_ return a useful zero value, and still be 
> compliant with the contract of the API. I hold as an example, 
> runtime.SetFinalizer
>  
>
>>
>>>  
>>>
>>>> B, it encourages people to be clever and try to avoid the error 
>>>> checking idiom.
>>>>
>>>
>>> I legit don't see how, given that this is not a rule. I also don't do it 
>>> with any kind of strictness that would allow people to rely on it.
>>>
>>>
>>> In your scheme, if there is an error, the function 
>>>
>>> func NewT() (*T, error)
>>>
>>> I could check if the value of T is nil, or the error is nil, to confirm 
>>> the error condition.
>>>
>>
>> But then your code is buggy. Because that is not part of the API. 
>>
>
> But this is what your API contract allows; you've committed to the caller 
> that in the event of and error, T _WILL_ be nil, and people will rely on 
> that. I argue it's better to save people from themselves and offer no 
> guarentee on the state of any other return values in the case of an error.
>  
>
>>  
>>
>>> C, doesn't work for all return values, only the pointer shaped ones.
>>>>
>>>
>>> I disagree. An empty string or a 0 or whatever is *still* a much more 
>>> telling symptom to debug than *some* string/integer/whatever, especially if 
>>> it's an invalid value (and if it isn't; why is would we even talk about it).
>>>
>>>
>>> But now you've introduced the problem that sometimes func f() (int, 
>>> error) might return 0, but you don't know if that's a valid value, or the 
>>> zero value--without checking the error value, so your back to square one.
>>>
>>
>> *exasperated sigh*
>> So? Yes, of course errors need to be checked. Yes, of course, not always 
>> will people look at the return and say "well, that can't be right". Of 
>> course, not every API lends itself to this.
>> But that's okay because this is not about changing any API contracts or 
>> to reduce any requirement on checking error values or anything… but just to 
>> *sometimes* add a branch to *sometimes* make things blow up in a clearer 
>> way if *sometimes* people forget to do it.
>>
>
> Sure, it's nice the be helpful, but where does it stop? I *guarantee* you 
> that people will built upon the contract of this method; knowing that all 
> the return values are valid; even in the presence of errors.
>
> How many times do we see, on a daily basis, people post code without 
> appropriate error checking to this mailing list, to the bug tracker, to 
> other support venues, because it mostly works; and because it mostly works 
> it'll keep working right up to the point there is an error in their 
> production code. 
>
> It is simpler, and more importantly more consistent, which helps all users 
> of all APIs, not just the ones who are lucky enough to use yours, to stick 
> to the error contract; if an error occurs you cannot say anything about the 
> state of the other return values, they are simply undefined.
>  
>
>>  
>>
>>>
>>>
>>> But anyway, yes, I mostly do this with pointers, but *so what*? Why 
>>> throw the baby out with the bathwater? Again, this is not part of any API. 
>>> This is not an all or nothing thing. This is a safety net for people coding 
>>> bugs and it's totally fine if it is there sometimes and not there at other 
>>> times (and you even argue yourself that it shouldn't, to "keep people on 
>>> their toes").
>>>
>>>
>>> People will build castles on your foundation of unexpected side effects. 
>>> You want to avoid that. 
>>>
>>
>> Then why does gc randomizes map-iteration order? People might rely on 
>> that. And the spec clearly says it's unspecified, so we shouldn't implement 
>> a particular behavior beyond what is required by spec…
>>
>> Anyway. I *do* give up. I don't think this is an actual controversy, but 
>> apparently it is either impossible for me to express unambiguously what I'm 
>> talking about or impossible for others to read what I'm writing. Because I 
>> did try, in every E-Mail, to be unambiguously clear but it still just got 
>> ignored again… I give up.
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to