On Wed, Apr 18, 2012 at 8:18 AM, Julian Foad <julianf...@btopenworld.com> wrote:
> Hyrum K Wright wrote:
>
>> On Wed, Apr 18, 2012 at 2:15 AM, Julian Foad wrote:
>>>  Blair Zajac wrote:
>>>>  In case of an illegal svn_checksum_kind_t being passed to
>>>>  svn_checksum__from_digest(), I want to change it from
>>>>
>>>>  svn_checksum_t *
>>>>  svn_checksum__from_digest(const unsigned char *digest,
>>>>                            svn_checksum_kind_t kind,
>>>>                            apr_pool_t *result_pool);
>>>>
>>>>  to
>>>>
>>>>  svn_error_t *
>>>>  svn_checksum__from_digest(svn_checksum_t **checksum,
>>>>                            const unsigned char *digest,
>>>>                            svn_checksum_kind_t kind,
>>>>                            apr_pool_t *result_pool);
>>>
>>>  Wouldn't a better API be:
>>>
>>>    svn_checksum_t *
>>>    svn_checksum__from_digest_md5(digest, result_pool);
>>>    svn_checksum_t *
>>>    svn_checksum__from_digest_sha1(digest, result_pool);
>>>
>>>  since all current callers want just one specific kind (apart from internal
>>> calls from the implementations of svn_checksum_dup and
>> svn_checksum_empty_checksum)?
>>
>> No.  This would be the only case where a specific checksum kind is
>> embedded in the API name rather than as a parameter.  The latter makes
>> extending the API easier in the future, and localizes the 'switch'
>> statement to that method.
>
> It *would* make extending the API easier and localize the 'switch' *if* there 
> were parameterized calls... but there aren't any.  So there is no need for 
> any 'switch' statement, in practice.  Look at the use cases.  There are 14 
> callers.  The 12 callers outside of checksum.c all want an already-known 
> kind, not a parameterized kind.  The two internal callers each handle any 
> kind, but one of them (_empty_checksum) already contains a switch on the 
> kind.  That leaves only one caller, the implementation of _dup(), where a 
> parameterized API could be beneficial, but such implementation is of course 
> free to use local static functions and other short-cuts.

There aren't any such callers *now*.  That does not preclude the
addition of them in the future.

> We could certainly keep the parameterized API for cases when it would be 
> useful, and if it were public that would be the right thing to do, but it's 
> private.
>
>>  What would be the benefit of separate APIs?
>
> Consistency with the style of related APIs is good, granted.  Simplicity
>  of APIs is good too.  Simplicity prefers avoiding possible error
> conditions by design, rather than coding to detect and handle errors.
> Omitting the 'kind' input and the 'error' output (where the only possible 
> error is 'you passed an invalid kind') makes a much simpler API.
>
> In response to consistency: after writing the above I've just realized why 
> this function really is different from the others.  Most of the checksum 
> functions that take a 'kind' input will create whatever kind you like, 
> independently of their other params.  On the other hand, *this* function 
> takes two parameters that are required to agree with each other: the 'digest' 
> parameter has to point to an MD5 digest iff 'kind'=md5, and to a SHA1 digest 
> iff kind=sha1.  It's not like 'const char *digest' is the universal standard 
> external representation of an arbitrary checksum kind; although it would be 
> possible for any checksum kind to have an external repr that can be addressed 
> as 'char *', the next kind we add might prefer to use a different external 
> representation such as 'struct foo'.  So it's not wierd to have one 
> 'checksum' constructor function per checksum kind.  That would be the normal 
> pattern for constructor functions.

That argument makes sense.

-Hyrum

>>>  Notice that svn_checksum_empty_checksum() returns NULL if the kind is not
>> recognized, while svn_checksum_dup() does no such check and would pass the
>> unknown kind into ...from_digest().
>>>
>>>  Therefore it appears that _dup() is the only caller that could have been
>> passing a bad kind -- at least in current trunk code; it may be different in
>> whatever version you're running.  And so, to fix the crash, you will still
>> need to decide how _dup() should handle a bogus checksum struct.  You could 
>> have
>> _dup() return NULL, but unless the callers check for null that would just 
>> defer
>> the crash.  It would be a little better to call 
>> SVN_ERR_MALFUNCTION_NO_RETURN(),
>> to give the client program a little more awareness of the abnormal 
>> termination.
>>>
>>>
>>>>  This is to prevent a core dump we've observed with our RPC server.
>>>>
>>>>  The function is in a public .h file but shown as private.  Do I need to
>> add
>>>>  svn_checksum__from_digest2() or can I just change it?
>>>
>>>  We're allowed to just change it, as I understand it.
>>>
>>>  (The closest thing I can find in 'hacking' is
>> <http://subversion.apache.org/docs/community-guide/conventions.html#interface-visibility>.
>> But that doesn't seem to mention the nuances of ABI vs. API and the issue
>> of, IIRC, all symbols in a shared library getting into a Windows DLL ABI 
>> even if
>> they're supposed to be private, or whatever exactly that issue was.)
>>
>> Nobody should be calling this function anyway, so ABI shouldn't be an
>> issue, IIUC.
>>
>> -Hyrum



-- 

uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/

Reply via email to