I believe alernative (b) would be best. The SQL package needs a way to
distinguish NULL from a zero value, and it sounds like you have provided
that. If the program chooses not to use that mechanism, I think a NULL
should become the zero value. I think that is more likely to be useful
in practice. In most databases in my experience, both a NULL and an
empty string mean "information not available."
BTW, I haven't looked at your code (sorry), but one way to implement
NULL would be
var name *string
var arg *int
err := rows.Scan(&name, &arg)
in which NULL sets the pointers to nil and values set them to point to
values. That would make it dead easy for the program to indicate
whether or not it cares about NULL.
Ian
BTW, I haven't looked at your code (sorry), but one way to implement
NULL would be
var name *string
var arg *int
err := rows.Scan(&name, &arg)
in which NULL sets the pointers to nil and values set them to point to
values. That would make it dead easy for the program to indicate
whether or not it cares about NULL.
Another thing I could do is define:package sql// NotNull returns a ScannerInto destination that writes to dest, but// raising an error if the source value is NULL.func NotNull(dest interface{}) ScannerInto {...}So then users could write, if desired:for rows.Next {var name stringvar age interr := rows.Scan(sql.NotNull(&name), &age)...}
Another thing I could do is define:package sql// NotNull returns a ScannerInto destination that writes to dest, but// raising an error if the source value is NULL.func NotNull(dest interface{}) ScannerInto {...}So then users could write, if desired:for rows.Next {var name stringvar age interr := rows.Scan(sql.NotNull(&name), &age)...}+1 for sql.NotNull -- assuming my memory is correct in that it would return an error in err and not a panic (I think that's the way the ScannerInto interface works)And my last sentence, rewritten:If you were to choose an API which returns an error when it stores NULL into a non-pointer/non-interface type, I would expect that all other possible assignments would still be made. This way, if I ignored the error (after inspecting it, of course), it would be as if the driver had simply stored the empty string in the NULL values and not returned the error at all.
>> BTW, I haven't looked at your code (sorry), but one way to implement
>> NULL would be
>>
>> var name *string
>> var arg *int
>> err := rows.Scan(&name, &arg)
>>
>> in which NULL sets the pointers to nil and values set them to point to
>> values. That would make it dead easy for the program to indicate
>> whether or not it cares about NULL.
>>
>
> That could work. Feels a bit proto-esque, but maybe that's good to be
> consistent.
To be clear, I'm suggesting that you support both the above and also
var name string
var arg int
err := rows.Scan(&name, &arg)
Ian
FWIW, that's how mgo works. People seem happy with it.
--
Gustavo Niemeyer
http://niemeyer.net
http://niemeyer.net/plus
http://niemeyer.net/twitter
http://niemeyer.net/blog
-- I'm not absolutely sure of anything.
>>> BTW, I haven't looked at your code (sorry), but one way to implement(...)
>>> NULL would be
>>>
>>> var name *string
>>> var arg *int
>>> err := rows.Scan(&name, &arg)
> To be clear, I'm suggesting that you support both the above and alsoFWIW, that's how mgo works. People seem happy with it.
>
> var name string
> var arg int
> err := rows.Scan(&name, &arg)
I don't have in depth documentation about that aspect, but the logic
is actually very similar to the standard json package. If a field has
a pointer type and it has a value in the unmarshalled document, the
pointer will be initialized:
http://play.golang.org/p/2uvaZ2p97S
There's one aspect that is different from json, though, which touches
the point you're bringing up. If the field type is not a pointer or an
interface and the document has a null value for such a field, json
errors out, while gobson does not. IMO, failing in these cases is not
very useful in practice. If the user intended to manage the null case
specially, there are means to do so.
>> BTW, I haven't looked at your code (sorry), but one way to implementTo be clear, I'm suggesting that you support both the above and also
>> NULL would be
>>
>> var name *string
>> var arg *int
>> err := rows.Scan(&name, &arg)
>>
>> in which NULL sets the pointers to nil and values set them to point to
>> values. That would make it dead easy for the program to indicate
>> whether or not it cares about NULL.
>>
>
> That could work. Feels a bit proto-esque, but maybe that's good to be
> consistent.
var name string
var arg int
err := rows.Scan(&name, &arg)I'm happy with that, if that doesn't trigger people's complexity thresholds.So we'd have scan into T, *T, and ScannerInto.