Comment by _8ljf
6 years ago
Even if it counts in picoseconds it’ll take several centuries to roll-over, so these probably aren’t questions you ever need to ask. Though that’s kind of the point: the API and its documentation should highlight the stuff you need to worry about, such as where you get these values from and what they do, and hide everything else that you don’t (internal implementation details).
But that particular API does the opposite. Just typedef-ing that data as an opaque `WordClockTime_t` would go a long way to fixing this, telling API users to ignore how it works internally and enabling automated documentation tools to to locate and list every other API that produces/consumes this particular value. A simple automation-friendly abstraction that would reduce—if not eliminate—the need for additional manually-written documentation. i.e. Put the knowledge in the code and the automation can graph it.
Alas, there’s something about C programming that seems to bring out the worst abstractions in many C programmers… and if they’re being lazy in their API design, they’ll be twice as lazy when it comes to manually documenting it.
--
"What is wrong with giving tree, here?"
"Well, he don't know talking good like me and you, so his vocabulistics is limited to 'I' and 'am' and 'Groot.' Exclusively, in that order."
> Even if it counts in picoseconds it’ll take several centuries to roll-over, so these probably aren’t questions you ever need to ask.
That's an assumption, that an edge case won't happen. Docs exist to spell out where the edge cases are.
Cisco thought a 32bit number for RTP timestamp would never rollover. It happened. [0] Centuries it might take if it's initialised from zero, but it doesn't have to be. And if you don't give the documentation, then you can't expect reasonable defaults to be used.
It's important to know when something like that happens, so that they can also know how to handle behaviour that may well be completely unexpected. Hiding the type doesn't help. It just tells you you're even more on your own if you want to handle exceptional events, which leads to code with holes so big you can drive a CVE through it.
[0] https://quickview.cloudapps.cisco.com/quickview/bug/CSCvc865...
Aye, I’m well aware what can go wrong when an integer overflow occurs. My point was the way Apple presumably[1] uses this particular Uint64 precludes such an event ever occurring within macOS’s lifetime, therefore there’s no need to explain it. If a macOS API generates that value and a macOS API modifies it and a macOS API consumes it, and users should only ever pass it around as-is and never screw with it directly, it’s opaque data and its internal workings are none of their business.
Okay, it would really help if C’s so-called “typesystem” would actually enforce a custom-defined type like `WordClockTime_t` so that client code can’t do stupid/malicious things with it like stick its own arbitrary integers in it; but hey, C. While a sensible runtime would also chuck an exception if a fixed-width integer overflows, rendering rollover dangers moot; but again, C. It is what it is; and so it goes.
But if, as an API designer, you’re going to document every single way your API may potentially blow up during normal/abnormal use then perhaps you should write that documentation in the form of defensive code that validates your API’s inputs and handles bad inputs accordingly. e.g. A timestamp API should not be making its users fret about (never mind cope with) C integer overflows; guarding against any edge-case crap is the API’s job, not its users’.
Again, the problem is not a lack of documentation so much as lack of clarity. A good abstraction shows only what its users need to know and hides everything that they don’t; the more that can be left unsaid, the better. (If an API can’t be documented clearly and concisely, that’s a huge red flag that the API design is bad so needs reworked until it can.) The problem with an API like this is the not-knowing, which indicates deeper, more systemic, failings than merely “needs more documentation”.
..
TL;DR: If your API is puking on its users then don’t start documenting the color and odor of that puke; fix its code so it doesn’t puke again.
--
[1] I say “presumably” because damned if I’m going to spend hours spelunking Apple’s crappy documentation just to find out exactly where this mWordClockTime value comes from and where it goes to.
> If a macOS API generates that value and a macOS API modifies it and a macOS API consumes it, and users should only ever pass it around as-is and never screw with it directly, it’s opaque data and its internal workings are none of their business.
But that's not the case. You get to set mWordClockTime as part of the init [0]. If you can initialise a value, but aren't given bounds for the value, then the documentation has screwed up.
The value is something the developer can create, and pass in when creating any AudioTimeStamp, which you will be doing a lot of if you're dealing with sound.
This isn't an arbitrary value you can just rely on to be correct, there may be good reasons for altering the value, such as when splitting sound into several thousand chunks and rearranging them.
It's a part of the exposed API - it needs to be documented how it behaves.
For a different take on a similar problem, let's look at how PulseAudio handles it [1].
> pa_core doesn't have any interesting functions associated with it, it is just a central collection of all the components and globally relevant variables. You're not supposed to modify the fields, at least not directly.
This is how you abstract away an API safely. The dev knows up front that pa_core is the type that'll be used, and that other functions will be modifying the sample cache for them - that is, they can't supply a value directly to the type or they've entered unsafe behaviour.
They can go off and find the right setter.
What follows on that page is only a courtesy, and can clearly not be used safely in most programs. It doesn't need to be there at all.
So the dev finds [2], where they call the client to get the sample.
And whilst duration is a uint64, is also has a few more things in the docs, such as the value can be lazy, so you need to check it exists before using it, and the property can raise an error when you try to access it and it doesn't yet exist. You'll also find that this a property (so you won't be creating it), generated by an interface, and where to find that interface.
I mean, I'm not one to compliment PulseAudio's documentation. It is an awful mess, just like the internals.
But they've given us a lot more than Apple bothered to.
[0] https://developer.apple.com/documentation/coreaudiotypes/aud...
[1] https://www.freedesktop.org/wiki/Software/PulseAudio/Documen...
[2] https://www.freedesktop.org/wiki/Software/PulseAudio/Documen...
1 reply →