Doctest stdlib timerelated#11327
Conversation
CT Test Results 2 files 100 suites 1h 6m 55s ⏱️ For more details on these failures, see this check. Results for commit 146a141. ♻️ This comment has been updated with latest results. To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts
// Erlang/OTP Github Action Bot |
| 2> F = random:uniform(), is_float(F), F > 0.0, F < 1.0. | ||
| true |
There was a problem hiding this comment.
This results in true for any F that is a number (including integers) that is less than 1.0, for example -5.
There was a problem hiding this comment.
Thanks for pointing it . The idea was to demonstrate output as floating and between 0.0 and 1.0. Added 'and' operator now to correct the same than the 'comma' operator. Hope now is ok
There was a problem hiding this comment.
andalso is generally used for performance when we do not want the second operand to be evaluated, but since here emphasis is on user understanding and documentation i kept it as just "and". Just wondering if really need a change or if this would keep it simpler for user
There was a problem hiding this comment.
and and or are deprecated and will raise warnings starting with OTP 29. Effectively, their usage is discouraged. Bringing them up again in documentation examples plainly runs against that. The need for precedence-parentheses that comes with them also makes the examples more confusing. (My 2ct anyway XD).
| 3> I = random:uniform(10), I >= 1, I =< 10. | ||
| true |
There was a problem hiding this comment.
This results in true for any I that is a number (including floats) that is less than or equal to 10, for example -5.5.
| 2> {Float, _NewState} = random:uniform_s(State), is_float(Float), Float > 0.0, Float < 1.0. | ||
| true |
There was a problem hiding this comment.
This results in true for any Float that is a number (including integers) that is less than 1.0, for example -5.
| 3> {Int, _NewState2} = random:uniform_s(10, State), Int >= 1, Int =< 10. | ||
| true |
There was a problem hiding this comment.
This results in true for any Int that is a number (including floats) that is less than or equal to 10, for example -5.5.
| 1> ok = element(1, timer:apply_after(5000, io, format, ["~nHello World!~n", []])). | ||
| ok |
There was a problem hiding this comment.
This wrapping in element(1, ...) makes the examples pretty confusing. A newcomer will certainly wonder, "Is that needed? What for? 🤔"?
There was a problem hiding this comment.
I agree that it makes the example not too clear enough for beginers. I have reverted preexisting examples at start of document back to text script. For newer added examples, since the TRef that is given by apply_after is always dynamic its hard to pattern match output and fails by doctest function in performed by timer_suite module. As per my understanding, examples should pass doctest at anypoint and hence a way verifying they are correct , so here TRef being dynamically generated will not be able to pattern match and hence extracting first element 'ok which will also validate success. I am happy to discuss any other better method that could be adopted otherwise :)
There was a problem hiding this comment.
Hm, I don't have much experience with doctests, but as far as I understand the documentation (and by a quick trial), something like...
1> timer:apply_after(5000, io, format, ["~nHello World!~n", []]).
{ok, TRef1}... should work? Or, since you're not using TRef1 subsequently in the example, you could use {ok, _}.
There was a problem hiding this comment.
Hm, I don't have much experience with doctests, but as far as I understand the documentation (and by a quick trial), something like...
1> timer:apply_after(5000, io, format, ["~nHello World!~n", []]). {ok, TRef1}... should work? Or, since you're not using
TRef1subsequently in the example, you could use{ok, _}.
Or...
1> {ok, _} = timer:apply_after(5000, io, format, ["~nHello World!~n", []]).... and omit the return value if just want to insist on the ok?
There was a problem hiding this comment.
if we demonstrate only this one liner without output this works as we completly ignore the TRef which is dynamically generated. Was less aware of this way in doctest.
| 2> {ok, {send_local, Ref1}} = timer:send_after(1000, self(), world), is_reference(Ref1). | ||
| true |
There was a problem hiding this comment.
The return type of timer:send_after/3 (and friends) is {ok, TRef} (or {error, Reason} for completeness' sake). TRef in turn is of type tref/0, which is an opaque type: you are not supposed to assume anything about what it actually looks like, as you do here with matching on {send_local, Ref1} and later is_reference(Ref1).
| Returns a random float uniformly distributed between `0.0` and `1.0`, updating | ||
| the state in the process dictionary. | ||
| """. | ||
| -doc(#{equiv => uniform(1)}). |
There was a problem hiding this comment.
This is not correct. As you can see from the spec already, uniform/0 (this function) returns a float(), whereas uniform/1 (the function you declare as equivalent to uniform/0 here) returns a pos_integer().
That is, uniform(1) will always return integer 1, while uniform() will return a float F in the range 0.0 <= F <= 1.0.
| 2> F = random:uniform() , is_float(F) and ((F>= 0.0) and (F =< 1.0)). | ||
| true |
There was a problem hiding this comment.
This does not belong here. As I said in my previous comment, uniform/0 is a different function (which just happens to have the same name).
| 3> I = random:uniform(10), ((I >= 1) and (I =< 10)). | ||
| true |
There was a problem hiding this comment.
I don't think that this is especially enlightening, if anything it makes the example confusing. If you absolutely want to have the "I is an integer 1 =< I =< 10" demonstration in there, you should put it on a different line, like this:
3> I = random:uniform(10).
4> is_integer(I, 1, 10).
true| Returns, for a specified state, a random float uniformly distributed between | ||
| `0.0` and `1.0`, and a new state. | ||
| """. | ||
| -doc(#{equiv => uniform_s(1, State0)}). |
There was a problem hiding this comment.
Same as with uniform/0/uniform/1, this is not correct.
|
One of your doctests for |
|
Looking at your PR in general, you are focusing a lot on testable (vs enlightening) examples. This in turn adds a lot of noise which obfuscates what the examples are actually supposed to demonstrate. IMO, examples in documentation should, first of all, highlight the usage of the function it documents. If the examples can be tested without adding confusing noise, then by all means do so - but if the testability adds confusing noise, don't. Think about it: there was documentation with imperfect, typo-ridden examples for decades, and people were fine with them nonetheless since it gave them a general idea of how to use something and what happened when. They were rarely used as they were written verbatim. I guess what I'm trying to say is, there is nothing wrong with debugging examples and making sure that they stay debugged. But making them testable at all costs actually reduces their value for readers. |
Thanks for feedback . Thinking on same lines, I have now tried to reiterate on some examples that felt like noise , removed emphasis on "testing" (for example (is_tuple(x), or just checking on ok etc) and have tried to rather emphasize on user readability and understanding. Since the doctest idea is that the code examples in module documentation remain guaranteed to stay correct because they are run during testing, have tried to keep in mind that they could be tested as far as possible :). |
This PR adds doctest examples to time related modules in Stdlib application for most of the functions