digitalmars.D - TickDuration deprecation
- Timon Gehr (30/35) Nov 18 2017 This is quite annoying:
- Jonathan M Davis (32/68) Nov 18 2017 core.time and std.datetime avoid floating point math, because using it
- bauss (10/25) Nov 18 2017 If you ask me, then time durations doesn't make sense as anything
- Jon Degenhardt (17/30) Nov 18 2017 When I use timers to measure time durations, whether for program
- Rumbu (8/19) Nov 19 2017 +1.
- Jonathan M Davis (9/28) Nov 19 2017 Was the documentation on Duration not informative enough, or did you hav...
- Rumbu (5/15) Nov 19 2017 The documentation on Duration doesn't specify any method of
- Jonathan M Davis (22/38) Nov 19 2017 Duration doesn't have any ticks. As its documentation states, it holds i...
- Rumbu (37/83) Nov 19 2017 Thank you Jonathan for the effort of explaini g, better put all
- Jonathan M Davis (4/12) Nov 19 2017 I would expect you to go read the documentation for Duration if you don'...
- Jon Degenhardt (51/63) Nov 19 2017 1) Finding the documentation for Duration from the documentation
- Timon Gehr (4/34) Nov 20 2017 This is exactly how I think about this. I'd additionally recommend to
- bauss (3/14) Nov 20 2017 Considering you know what would improve the documentations, why
- Kagamin (3/7) Nov 21 2017 dpldocs sort of allow you to do it:
- Kagamin (6/9) Nov 21 2017 If you want to communicate with a system that uses a floating
- qznc (6/10) Nov 19 2017 Makes me think about my money library. It does accept floating
- Walter Bright (4/8) Nov 21 2017 Yup. It's the same reason one does not do accounting with floating point...
- Timon Gehr (10/24) Nov 21 2017 The use case here is plotting the time taken by an algorithm depending
- Walter Bright (11/21) Nov 21 2017 I'm in general opposed to "kitchen sink" abstractions, preferring plugga...
- Walter Bright (5/5) Nov 21 2017 There is another, perhaps obsolete, consideration.
- Jon Degenhardt (43/50) Nov 21 2017 Hi Walter - I wonder if there is a miscommunication. My
- Walter Bright (24/44) Nov 22 2017 My perspective is that the time package should not deal with floating po...
- Timon Gehr (2/9) Nov 22 2017 Why would the conversion function be linked in if I never use it?
- Walter Bright (6/7) Nov 22 2017 Good question. It depends on how the code is written, and how the compil...
- Walter Bright (5/11) Nov 22 2017 For another example, unreferenced virtual functions never get elided bec...
- Jacob Carlborg (6/10) Nov 23 2017 Yeah, that's one of the reason why the original Objective-C/D bridge
- Timon Gehr (20/57) Nov 22 2017 But this is orthogonal to my complaint. I don't care which Phobos module...
- Walter Bright (2/5) Nov 22 2017 I refer to my reply to Jon Degenhardt which has a substantial answer to ...
- Daniel Kozak (12/19) Nov 22 2017 Ok I understand why there is no conversion from Duration to float, but
- Jonathan M Davis (18/28) Nov 22 2017 How would that help anything? You can clearly create an msecs alias righ...
- Steven Schveighoffer (48/63) Nov 22 2017 My take on this, as someone who has argued extensively NOT to use double...
- Walter Bright (30/46) Nov 22 2017 Microsoft has numerous COM APIs for time functions. One of them I had to...
- sarn (6/20) Nov 22 2017 It's fixed point, not floating point, but this famous software
- captaindet (16/17) Nov 22 2017 and nobody is advocating to change this.
This is quite annoying: void main(){ import std.datetime; StopWatch sw; import std.stdio; writeln(sw.peek().to!("seconds",double)); } This gives the deprecation warning: Deprecation: struct std.datetime.StopWatch is deprecated - Use std.datetime.stopwatch.StopWatch. Then, if I do that: void main(){ import std.datetime.stopwatch: StopWatch; StopWatch sw; import std.stdio; writeln(sw.peek().to!("seconds",double)); } Error: no property 'to' for type 'Duration' This is among the most basic use cases for StopWatch. For example, if I want to quickly plot some timing data, I'll invariably want to convert times to floating point values of the correct units. The reason given for this situation is: https://issues.dlang.org/show_bug.cgi?id=11353TickDuration will soon be deprecated, and none of the other time stuff supports floating point. Anyone who wants that functionality cancalculatethe floating point values from the integral values that the types do provide. It's not something that most code should be doing, but the API makes it possible for those who care."Not something that most code should be doing"? I have never used StopWatch and then /not/ wanted to do something like to!("seconds",double)! There seems to be no good reason to break my code beyond requiring a different import here. What are the perceived shortcomings of the to!("seconds", double) interface?
Nov 18 2017
On Saturday, November 18, 2017 15:03:05 Timon Gehr via Digitalmars-d wrote:This is quite annoying: void main(){ import std.datetime; StopWatch sw; import std.stdio; writeln(sw.peek().to!("seconds",double)); } This gives the deprecation warning: Deprecation: struct std.datetime.StopWatch is deprecated - Use std.datetime.stopwatch.StopWatch. Then, if I do that: void main(){ import std.datetime.stopwatch: StopWatch; StopWatch sw; import std.stdio; writeln(sw.peek().to!("seconds",double)); } Error: no property 'to' for type 'Duration' This is among the most basic use cases for StopWatch. For example, if I want to quickly plot some timing data, I'll invariably want to convert times to floating point values of the correct units. The reason given for this situation is: https://issues.dlang.org/show_bug.cgi?id=11353 > TickDuration will soon be deprecated, and none of the other time stuff > supports floating point. Anyone who wants that functionality can calculate > the floating point values from the integral values that the types do > provide. It's not something that most code should be doing, but the API > makes it possible for those who care. "Not something that most code should be doing"? I have never used StopWatch and then /not/ wanted to do something like to!("seconds",double)! There seems to be no good reason to break my code beyond requiring a different import here. What are the perceived shortcomings of the to!("seconds", double) interface?core.time and std.datetime avoid floating point math, because using it introduces errors into the calculations. It does make some sense to generate a floating point value if all you're looking to do is print it out at the end, but using floating point values in the calculations is a source of bugs - e.g. converting between clock frequencies using floating point values would be particularly bad, much as it's the obvious first implementation; core.time.convClockFreq does it all with integral math and avoids the problem and even manages to support a higher range of values in the process than it would if it were implemented with double or real. As such, I've avoided floating point values like the plague in the time stuff. The only reason that TickDuration does it at all is because it was written by someone else, and it has various design flaws that mean that it really should never have been in core.time in the first place (most notably that it conflates a point in time of the monotonic clock a a duration of the monotonic clock, making it really easy to screw up when using it). So, we've slowly been moving towards getting rid of it in favor of using MonoTime and Duration. Printing out a floating point value for something like the number of seconds can make sense, but using floating point to do math with time really doesn't. And it's trivial enough to do the math yourself to get the number of seconds (or milliseconds or minutes or whatever) as a floating point value if you really want that that I'd much rather not add it to core.time, because that would just be encouraging folks to start using floating point values for something other than simply printing out the value, which will lead to buggy code which could have easily been avoided just by sticking to integral math. Folks have asked for the ability to create Durations from floating point values too, and I rejected that for the same reason - using floating point values with time is just begging for bugs, and Walter backed me up on that one. - Jonathan M Davis
Nov 18 2017
On Saturday, 18 November 2017 at 16:17:00 UTC, Jonathan M Davis wrote:On Saturday, November 18, 2017 15:03:05 Timon Gehr via Digitalmars-d wrote:If you ask me, then time durations doesn't make sense as anything else other than signed integers. I can see that you can do something like "0.5" for half a second, but really you shouldn't be doing the duration in seconds then, but rather in milliseconds and pass 500 for half a second. So please, I hope it never gets added. That's just my two cents. Especially seeing how flawed floating points are.[...]core.time and std.datetime avoid floating point math, because using it introduces errors into the calculations. It does make some sense to generate a floating point value if all you're looking to do is print it out at the end, but using floating point values in the calculations is a source of bugs - e.g. converting between clock frequencies using floating point values would be particularly bad, much as it's the obvious first implementation; core.time.convClockFreq does it all with integral math and avoids the problem and even manages to support a higher range of values in the process than it would if it were implemented with double or real. [...]
Nov 18 2017
On Saturday, 18 November 2017 at 16:17:00 UTC, Jonathan M Davis wrote:On Saturday, November 18, 2017 15:03:05 Timon Gehr via Digitalmars-d wrote: [snip] Printing out a floating point value for something like the number of seconds can make sense, but using floating point to do math with time really doesn't. And it's trivial enough to do the math yourself to get the number of seconds (or milliseconds or minutes or whatever) as a floating point value if you really want that that I'd much rather not add it to core.time, because that would just be encouraging folks to start using floating point values for something other than simply printing out the value, which will lead to buggy code which could have easily been avoided just by sticking to integral math.When I use timers to measure time durations, whether for program performance or something else, at the end I usually want to convert to units of time appropriate for what is being measured and print it in a format easily consumable by human readers. That typically means some fixed precision floating point format. I admittedly don't understand the argument that it should be hard to user programs to convert time durations to alternate standard units of measure. But even so, it would seem to make sense for the documentation of std.datetime.stopwatch to provide clear examples of printing a duration in different standard time units. In documentation's current form, it takes quite a bit of digging to figure out how to do this. I'd recommend at least making it clear in the documentation how to do this. Yes, this would also make it easier for users to convert to float, but printing in standard units of measure is a rather basic operation.
Nov 18 2017
On Saturday, 18 November 2017 at 22:46:20 UTC, Jon Degenhardt wrote:I admittedly don't understand the argument that it should be hard to user programs to convert time durations to alternate standard units of measure. But even so, it would seem to make sense for the documentation of std.datetime.stopwatch to provide clear examples of printing a duration in different standard time units. In documentation's current form, it takes quite a bit of digging to figure out how to do this. I'd recommend at least making it clear in the documentation how to do this. Yes, this would also make it easier for users to convert to float, but printing in standard units of measure is a rather basic operation.+1. I had the same problem with some benchmark intensive project. It took me some time to resolve the deprecations, but I lost more time diging for a way to display times in a human readable form. Internal representations of durations are useless if you cannot display them in a standard unit of measure.
Nov 19 2017
On Sunday, November 19, 2017 15:01:50 Rumbu via Digitalmars-d wrote:On Saturday, 18 November 2017 at 22:46:20 UTC, Jon Degenhardt wrote:Was the documentation on Duration not informative enough, or did you have trouble finding it from the documentation for the benchmarking functions, or something else? Simply converting a Duration to a string gives you what I would have thought would have been plenty human readable (though obviously not necessarily what you want in all cases), and it's split and total functions should make it straightforward to put the result in some other format if that's what you want. Was the documentation on those not enough? - Jonathan M DavisI admittedly don't understand the argument that it should be hard to user programs to convert time durations to alternate standard units of measure. But even so, it would seem to make sense for the documentation of std.datetime.stopwatch to provide clear examples of printing a duration in different standard time units. In documentation's current form, it takes quite a bit of digging to figure out how to do this. I'd recommend at least making it clear in the documentation how to do this. Yes, this would also make it easier for users to convert to float, but printing in standard units of measure is a rather basic operation.+1. I had the same problem with some benchmark intensive project. It took me some time to resolve the deprecations, but I lost more time diging for a way to display times in a human readable form. Internal representations of durations are useless if you cannot display them in a standard unit of measure.
Nov 19 2017
On Sunday, 19 November 2017 at 16:02:34 UTC, Jonathan M Davis wrote:Was the documentation on Duration not informative enough, or did you have trouble finding it from the documentation for the benchmarking functions, or something else? Simply converting a Duration to a string gives you what I would have thought would have been plenty human readable (though obviously not necessarily what you want in all cases), and it's split and total functions should make it straightforward to put the result in some other format if that's what you want. Was the documentation on those not enough? - Jonathan M DavisThe documentation on Duration doesn't specify any method of converting it to usecs (that's what I need). TickDuration has a usecs member, I really don't care how many ticks are there.
Nov 19 2017
On Sunday, November 19, 2017 16:55:06 Rumbu via Digitalmars-d wrote:On Sunday, 19 November 2017 at 16:02:34 UTC, Jonathan M Davis wrote:Duration doesn't have any ticks. As its documentation states, it holds its time internally in hecto-nanoseconds. Its total function can be used to convert the entire Duration to whatever units you want: https://dlang.org/phobos/core_time.html#.Duration.total whereas its split function allows you to split it into whatever units you want: https://dlang.org/phobos/core_time.html#.Duration.split And simply converting a Duration to a string prints out the units with them split out in a human readable manner. e.g. writeln(usecs(502397292)); would print 8 minutes, 22 secs, 397 ms, and 292 μs https://dlang.org/phobos/core_time.html#.Duration.toString Subtracting MonoTimes specifically gives a Duration rather than a TickDuration or anything else representing the number of ticks, because you don't normally care about the number of ticks, and its cleaner to have only one duration type. Anyone who wants the number of ticks would have to use MonoTime's ticks property to get at them and then subtract those directly. So, anything holding the monotonic time now uses MonoTime to hold the times and gives the length of time as a Duration. - Jonathan M DavisWas the documentation on Duration not informative enough, or did you have trouble finding it from the documentation for the benchmarking functions, or something else? Simply converting a Duration to a string gives you what I would have thought would have been plenty human readable (though obviously not necessarily what you want in all cases), and it's split and total functions should make it straightforward to put the result in some other format if that's what you want. Was the documentation on those not enough? - Jonathan M DavisThe documentation on Duration doesn't specify any method of converting it to usecs (that's what I need). TickDuration has a usecs member, I really don't care how many ticks are there.
Nov 19 2017
On Sunday, 19 November 2017 at 17:26:04 UTC, Jonathan M Davis wrote:Duration doesn't have any ticks. As its documentation states, it holds its time internally in hecto-nanoseconds. Its total function can be used to convert the entire Duration to whatever units you want: https://dlang.org/phobos/core_time.html#.Duration.total whereas its split function allows you to split it into whatever units you want: https://dlang.org/phobos/core_time.html#.Duration.split And simply converting a Duration to a string prints out the units with them split out in a human readable manner. e.g. writeln(usecs(502397292)); would print 8 minutes, 22 secs, 397 ms, and 292 μs https://dlang.org/phobos/core_time.html#.Duration.toString Subtracting MonoTimes specifically gives a Duration rather than a TickDuration or anything else representing the number of ticks, because you don't normally care about the number of ticks, and its cleaner to have only one duration type. Anyone who wants the number of ticks would have to use MonoTime's ticks property to get at them and then subtract those directly. So, anything holding the monotonic time now uses MonoTime to hold the times and gives the length of time as a Duration. - Jonathan M DavisThank you Jonathan for the effort of explaini g, better put all this in the docs. Believe me, total is not the first word that comes to my mind when I want to use a conversion. More than that, total is documented on another page. The documentation is lost in details like internal representation (I don't care), mono time (I don't even want to know what is this), operators (I don't see the point of documenting internals) instead of highlighting the main usage. Now put yourself in the user's shoes. You had something like x.usecs in your code, now you get a deprecation message. You resolve the deprecation, but the compiler complains: On Sunday, 19 November 2017 at 17:26:04 UTC, Jonathan M Davis wrote:Duration doesn't have any ticks. As its documentation states, it holds its time internally in hecto-nanoseconds. Its total function can be used to convert the entire Duration to whatever units you want: https://dlang.org/phobos/core_time.html#.Duration.total whereas its split function allows you to split it into whatever units you want: https://dlang.org/phobos/core_time.html#.Duration.split And simply converting a Duration to a string prints out the units with them split out in a human readable manner. e.g. writeln(usecs(502397292)); would print 8 minutes, 22 secs, 397 ms, and 292 μs https://dlang.org/phobos/core_time.html#.Duration.toString Subtracting MonoTimes specifically gives a Duration rather than a TickDuration or anything else representing the number of ticks, because you don't normally care about the number of ticks, and its cleaner to have only one duration type. Anyone who wants the number of ticks would have to use MonoTime's ticks property to get at them and then subtract those directly. So, anything holding the monotonic time now uses MonoTime to hold the times and gives the length of time as a Duration. - Jonathan M DavisThank you Jonathan for the effort of explaini g, better put all this in the docs. Believe me, total is not the first word that comes to my mind when I want to use a conversion. More than that, total is documented on another page. The documentation is lost in details like internal representation (I don't care), mono time (I don't even want to know what is this), operators (I don't see the point of documenting internals) instead of highlighting the main usage. Now put yourself in the phobos user's shoes. You had something like sometickdurationresult.usecs in your code, now you get a deprecation message. I skip the part where I must write now my own benchmarkig functions because someone had the brilliant idea to deprecate them too (why?). Finally, you resolve the deprecation, but the compiler throws an error like this: core.time.dur!"usecs".dur (long length) is not callable using argument types (Duration) Based on the error above, how in the world can I deduce that I must use something like "total"? Note: I understood what happens, I'm just playing the devil's advocate here :)
Nov 19 2017
On Sunday, November 19, 2017 17:56:37 Rumbu via Digitalmars-d wrote:Finally, you resolve the deprecation, but the compiler throws an error like this: core.time.dur!"usecs".dur (long length) is not callable using argument types (Duration) Based on the error above, how in the world can I deduce that I must use something like "total"? Note: I understood what happens, I'm just playing the devil's advocate here :)I would expect you to go read the documentation for Duration if you don't already know how to use Duration. - Jonathan M Davis
Nov 19 2017
On Sunday, 19 November 2017 at 16:02:34 UTC, Jonathan M Davis wrote:On Sunday, November 19, 2017 15:01:50 Rumbu via Digitalmars-d wrote:On Saturday, 18 November 2017 at 22:46:20 UTC, Jon DegenhardtWas the documentation on Duration not informative enough, or did you have trouble finding it from the documentation for the benchmarking functions, or something else? Simply converting a Duration to a string gives you what I would have thought would have been plenty human readable (though obviously not necessarily what you want in all cases), and it's split and total functions should make it straightforward to put the result in some other format if that's what you want. Was the documentation on those not enough?1) Finding the documentation for Duration from the documentation of std.datetime.stopwatch is not quick enough. There is only one link from the page, and it's near the bottom, with the benchmark function (which is rarely what I need). Also, aside from the link at the bottom of the page, no mention of what module it is in. 2) The stopwatch page doesn't describe a Duration, and it also refers to core.time.MonoTime, plus a discussion that the "precision of StopWatch differs from system to system. And references to the depreciated TickDuration Before one can do anything, one has to parse through all this material. It's all necessary material for tasks requiring very high accuracy. However, if what is being timed is inherently precise only to hundreds or tens of milliseconds, then this is way more investigation than needs to be done for the task at hand. 3) hecto-nanoseconds is not an especially common unit of measure. 4) Even from the Duration documentation, there aren't many examples of conversion to other standard units of measure. The only one I see is converting 12 days to hecto-nanoseconds, which isn't helpful as an example. 5) The built in conversion to string is one I've never found useful. Generally, I'm putting a set a values in a table, perhaps a large table. The output shown is not amenable to this. And yes, it often needs to be both human and machine readable. For example, I may read the table into R and plot the values. Some recommendations: a) Put a link to the Duration documentation in StopWatch page. b) Put examples in the StopWatch and Duration sections that explicitly show how to convert to usecs, milliseconds, and perhaps seconds in floating point formats. Show this in the context of printing them. c) Try to clean up some of the language describing the backward compatibility vs the newer stuff. It's a bit intertwined. The language doesn't have to explain the depreciation or justify it, at least not mixed with the description of the new facilities. d) Be more explicit in the documentation about tradeoffs of integer precision used in Duration and floating point accuracy. That Duration supports this high accuracy without loss of precision in the face of mathematical operations is a real value, one worth calling out. However, it's also the case that this high mathematical precision is not required for many timing use cases, especially in the printing, but even calculations. Making this distinction puts the stopwatch facilities more in the position of being an enabler of good end-user choices and less trying to prevent end-user mistakes. The reality is, that the accuracy needs are only known in the context of the timing measurements being done. The library code does not have enough information to know. However, providing the user with the information to make good choices about accuracy representation is a real benefit.
Nov 19 2017
On 19.11.2017 20:29, Jon Degenhardt wrote:... Some recommendations: a) Put a link to the Duration documentation in StopWatch page. b) Put examples in the StopWatch and Duration sections that explicitly show how to convert to usecs, milliseconds, and perhaps seconds in floating point formats. Show this in the context of printing them. c) Try to clean up some of the language describing the backward compatibility vs the newer stuff. It's a bit intertwined. The language doesn't have to explain the depreciation or justify it, at least not mixed with the description of the new facilities. d) Be more explicit in the documentation about tradeoffs of integer precision used in Duration and floating point accuracy. That Duration supports this high accuracy without loss of precision in the face of mathematical operations is a real value, one worth calling out. However, it's also the case that this high mathematical precision is not required for many timing use cases, especially in the printing, but even calculations. Making this distinction puts the stopwatch facilities more in the position of being an enabler of good end-user choices and less trying to prevent end-user mistakes. The reality is, that the accuracy needs are only known in the context of the timing measurements being done. The library code does not have enough information to know. However, providing the user with the information to make good choices about accuracy representation is a real benefit.This is exactly how I think about this. I'd additionally recommend to keep supporting something like "to". It's nicer to read than something like total!"hnsecs"/1e7.
Nov 20 2017
On Sunday, 19 November 2017 at 19:29:06 UTC, Jon Degenhardt wrote:On Sunday, 19 November 2017 at 16:02:34 UTC, Jonathan M Davis wrote:Considering you know what would improve the documentations, why not create a pull-request yourself?[...][...]1) Finding the documentation for Duration from the documentation of std.datetime.stopwatch is not quick enough. There is only one link from the page, and it's near the bottom, with the benchmark function (which is rarely what I need). Also, aside from the link at the bottom of the page, no mention of what module it is in. [...]
Nov 20 2017
On Sunday, 19 November 2017 at 19:29:06 UTC, Jon Degenhardt wrote:1) Finding the documentation for Duration from the documentation of std.datetime.stopwatch is not quick enough. There is only one link from the page, and it's near the bottom, with the benchmark function (which is rarely what I need).dpldocs sort of allow you to do it: http://dpldocs.info/experimental-docs/std.datetime.stopwatch StopWatch.peek.html it links types used in function signature.
Nov 21 2017
On Saturday, 18 November 2017 at 22:46:20 UTC, Jon Degenhardt wrote:I admittedly don't understand the argument that it should be hard to user programs to convert time durations to alternate standard units of measure.If you want to communicate with a system that uses a floating point time format, you would need exactly same conversion algorithm not just something similar, so that round trip doesn't introduce computational errors.
Nov 21 2017
On Saturday, 18 November 2017 at 16:17:00 UTC, Jonathan M Davis wrote:Folks have asked for the ability to create Durations from floating point values too, and I rejected that for the same reason - using floating point values with time is just begging for bugs, and Walter backed me up on that one.Makes me think about my money library. It does accept floating point values and it has lead to at least one confused user [0]. Hm. [0] https://github.com/qznc/d-money/issues/3
Nov 19 2017
On 11/18/2017 8:17 AM, Jonathan M Davis wrote:Folks have asked for the ability to create Durations from floating point values too, and I rejected that for the same reason - using floating point values with time is just begging for bugs, and Walter backed me up on that one.Yup. It's the same reason one does not do accounting with floating point. Computer clocks have discrete ticks, they are not continuous. The behavior maps cleanly onto integral math, not fuzzy fp math.
Nov 21 2017
On 21.11.2017 21:52, Walter Bright wrote:On 11/18/2017 8:17 AM, Jonathan M Davis wrote:The use case here is plotting the time taken by an algorithm depending on instance size.Folks have asked for the ability to create Durations from floating point values too, and I rejected that for the same reason - using floating point values with time is just begging for bugs, and Walter backed me up on that one.Yup. It's the same reason one does not do accounting with floating point. ...Computer clocks have discrete ticks, they are not continuous.That may be true, but the plotting library may still just expect a list of doubles. What's the point of removing the simple conversion function that was already available for such use cases? This is a breaking change with zero benefits.The behavior maps cleanly onto integral math,I'm not doing computations on times. I could just use Duration for that.not fuzzy fp math.There is nothing fuzzy about floating point operations, but still, yes, for some use cases, the tiny rounding error will just not matter.
Nov 21 2017
On 11/21/2017 1:40 PM, Timon Gehr wrote:I'm in general opposed to "kitchen sink" abstractions, preferring pluggable component abstractions. Floating point has no business being in a type that is represented as an integral type. There are no 0.3 clock ticks, the notion does not exist.Computer clocks have discrete ticks, they are not continuous.That may be true, but the plotting library may still just expect a list of doubles. What's the point of removing the simple conversion function that was already available for such use cases? This is a breaking change with zero benefits.Time durations are always discrete quanta by the nature of the clock used.The behavior maps cleanly onto integral math,I'm not doing computations on times. I could just use Duration for that.Fuzzy as in inexact. Integral time computations are always an exact multiple of clock ticks.not fuzzy fp math.There is nothing fuzzy about floating point operations,but still, yes, for some use cases, the tiny rounding error will just not matter.Whether the rounding error matters or not should not be decided by the time package, it should be decided by what the user decides to do with the time values. I.e. it is not properly part of the time abstraction.
Nov 21 2017
There is another, perhaps obsolete, consideration. Some CPUs do not have floating point units. C, for example, is carefully set up so that when you don't need floating point, it isn't required to have an FPU. This made C usable on cheap processors. It's sorta like "why is the GC linked in even though I never used it?"
Nov 21 2017
On Wednesday, 22 November 2017 at 05:50:53 UTC, Walter Bright wrote:There is another, perhaps obsolete, consideration. Some CPUs do not have floating point units. C, for example, is carefully set up so that when you don't need floating point, it isn't required to have an FPU. This made C usable on cheap processors. It's sorta like "why is the GC linked in even though I never used it?"Hi Walter - I wonder if there is a miscommunication. My understanding is that the question is whether there should be a built-in conversion from Duration to float/double in a specific unit of measure, like milliseconds. It sounds as if your concern is more to ensure that the time package not be required to support something other than integral values in its internal operations. Perhaps there is an alternative perspective, but being able to convert a Duration to a double in a specific unit of measure would not seem to place any burden on the time package to support the result of conversion as a first class time object. In this view, what happens with the converted value is entirely in the hands of the end user, not the time package. If the user decides to use the double in a mathematical operation, floating point round off error is the responsibility of the user, not the time package. To give a concrete example of why this is conversion is useful - I often do performance analysis involving service calls that take from single digit milliseconds to hundreds of milliseconds, with standard deviations in that ballpark. I might use tens of thousands of timing samples and analyze those samples using stats and graphing packages. Those packages all use doubles, and it is generally convenient to work in units appropriate for the measurements being done, milliseconds in the case I described. In this case, the last step in generating a timing value is to convert to milliseconds as a double and store it somewhere, often a log file. These will be read back in by the stats/graphing package, where follow-up processing will be done. In the older version of StopWatch, this last step conversion could be done with a call like: double ms = sw.peek.to!("msecs", double)); In the new version, a call needs to be something like: double ms = sw.peek.total!("hnsecs").to!double / 1e+04); The latter form is more error prone and less clear about intent, etc. It sounds as the rationale for depreciating the previous form of conversion is because the end user may incur floating point round-off error by performing mathematical operations on the double value. The user can still perform the conversion, but must go to greater effort. It sounds as if the other part of the rationale is that conversion is likely to be rare. In my experience, this is not the case.
Nov 21 2017
On 11/21/2017 11:48 PM, Jon Degenhardt wrote:Hi Walter - I wonder if there is a miscommunication. My understanding is that the question is whether there should be a built-in conversion from Duration to float/double in a specific unit of measure, like milliseconds. It sounds as if your concern is more to ensure that the time package not be required to support something other than integral values in its internal operations.My perspective is that the time package should not deal with floating point at all. I understand that it is useful in some circumstances to treat them as floating point values, but this should be a layer added on by the user, not by the time package.In the older version of StopWatch, this last step conversion could be done with a call like: double ms = sw.peek.to!("msecs", double));That puts the logic of the double conversion into the time package.In the new version, a call needs to be something like: double ms = sw.peek.total!("hnsecs").to!double / 1e+04); The latter form is more error prone and less clear about intent, etc.I agree. It is a prime candidate for further encapsulating in a function, such as: /* Returns: duration in milliseconds to 4 digits past the decimal point */ double swAsDouble(StopWatch sw) { return sw.peek.total!("hnsecs").to!double / 1e+04); } double ms = swAsDouble(sw); This function, being a trivial one liner, doesn't really need to be in Phobos. It could be suitable for inclusion in the time package documentation as an example on how to get results in a floating point manner. [As a general philosophy, I oppose Phobos being filled with one liners, a mile wide and an inch deep. Phobos should be a small number of non-obvious, orthogonal, deep functions. As an extreme example, int add2(int i){return i+2;} should not be in Phobos.]It sounds as the rationale for depreciating the previous form of conversion is because the end user may incur floating point round-off error by performing mathematical operations on the double value. The user can still perform the conversion, but must go to greater effort. It sounds as if the other part of the rationale is that conversion is likely to be rare. In my experience, this is not the case.It is not the rationale I would use for this case. It's also true that floating point operations are a minefield with respect to precision and roundoff decisions. These sorts of decisions should not even be made by the time package, because they will always be wrong for some users, so they should rightfully be pushed to the user.
Nov 22 2017
On 22.11.2017 06:50, Walter Bright wrote:There is another, perhaps obsolete, consideration. Some CPUs do not have floating point units. C, for example, is carefully set up so that when you don't need floating point, it isn't required to have an FPU. This made C usable on cheap processors. It's sorta like "why is the GC linked in even though I never used it?"Why would the conversion function be linked in if I never use it?
Nov 22 2017
On 11/22/2017 1:41 AM, Timon Gehr wrote:Why would the conversion function be linked in if I never use it?Good question. It depends on how the code is written, and how the compiler represents it in the object file, and how the linker deals with unreferenced parts of object files. `format`, for example, dynamically decides whether to use floating point or not, so it is always linked in.
Nov 22 2017
On 11/22/2017 2:45 AM, Walter Bright wrote:On 11/22/2017 1:41 AM, Timon Gehr wrote:For another example, unreferenced virtual functions never get elided because a reference to them does exist - they're in the virtual function pointer table. And then, of course, everything that virtual function references is never elided. Another reason to be careful of "kitchen sink" abstractions.Why would the conversion function be linked in if I never use it?Good question. It depends on how the code is written, and how the compiler represents it in the object file, and how the linker deals with unreferenced parts of object files.
Nov 22 2017
On 2017-11-22 22:41, Walter Bright wrote:For another example, unreferenced virtual functions never get elided because a reference to them does exist - they're in the virtual function pointer table. And then, of course, everything that virtual function references is never elided.Yeah, that's one of the reason why the original Objective-C/D bridge resulted in a 60 MB Hello World executable. At that point we realized we need to add direct support in the compiler for linking with Objective-C. -- /Jacob Carlborg
Nov 23 2017
On 22.11.2017 03:22, Walter Bright wrote:On 11/21/2017 1:40 PM, Timon Gehr wrote:But this is orthogonal to my complaint. I don't care which Phobos module contains the conversion functionality. It can be part of std.conv.to, for example.I'm in general opposed to "kitchen sink" abstractions, preferring pluggable component abstractions.Computer clocks have discrete ticks, they are not continuous.That may be true, but the plotting library may still just expect a list of doubles. What's the point of removing the simple conversion function that was already available for such use cases? This is a breaking change with zero benefits.Floating point has no business being in a type that is represented as an integral type.Why would it need to be part of the type? I just want the obvious conversion functionality, to enable further processing where this is appropriate.There are no 0.3 clock ticks, the notion does not exist. ...(Great then. There also is no 0.3 float value. :P)The plotter or whatever other component consumes the timing data might not care about this.Time durations are always discrete quanta by the nature of the clock used. ...The behavior maps cleanly onto integral math,I'm not doing computations on times. I could just use Duration for that.The result is well-defined, it's just rounded. Whether that is exact or not depends on what you expected the result to be, it's not properly part of the floating point abstraction.Fuzzy as in inexact.not fuzzy fp math.There is nothing fuzzy about floating point operations,Integral time computations are always an exact multiple of clock ticks. ...The reason why floating point values are popular is that it is often enough infeasible or unnecessary to do the computation without rounding. The output of a computation might be inexact even if the inputs are not. There needs to be some way to move from one regime to the other.My claim is not that conversion from time to floating point values associated with a few natural units is "properly part of the time abstraction", just that it should exist. Do you agree with that?but still, yes, for some use cases, the tiny rounding error will just not matter.Whether the rounding error matters or not should not be decided by the time package, it should be decided by what the user decides to do with the time values. I.e. it is not properly part of the time abstraction.
Nov 22 2017
On 11/22/2017 1:38 AM, Timon Gehr wrote:My claim is not that conversion from time to floating point values associated with a few natural units is "properly part of the time abstraction", just that it should exist. Do you agree with that?I refer to my reply to Jon Degenhardt which has a substantial answer to that.
Nov 22 2017
Ok I understand why there is no conversion from Duration to float, but would be possible to make Duration.total not a member function? So insted of: static mytotal(string unit)(Duration dur) { return dur.total!unit; } alias msecs = mytotal!"msecs"; I could just add alias msecs = total!"msecs"; On Wed, Nov 22, 2017 at 11:48 AM, Walter Bright via Digitalmars-d < digitalmars-d puremagic.com> wrote:On 11/22/2017 1:38 AM, Timon Gehr wrote:My claim is not that conversion from time to floating point values associated with a few natural units is "properly part of the time abstraction", just that it should exist. Do you agree with that?I refer to my reply to Jon Degenhardt which has a substantial answer to that.
Nov 22 2017
On Wednesday, November 22, 2017 12:45:01 Daniel Kozak via Digitalmars-d wrote:Ok I understand why there is no conversion from Duration to float, but would be possible to make Duration.total not a member function? So insted of: static mytotal(string unit)(Duration dur) { return dur.total!unit; } alias msecs = mytotal!"msecs"; I could just add alias msecs = total!"msecs";How would that help anything? You can clearly create an msecs alias right now, and you could get the same effect using a free function named msecs instead of an alias. Also, core.time.msecs is already an alias for core.time.dur!"msecs", so creating your own symbol called msecs (be it an alias or a free function) could muck with your use of the one from core.time (though it's certainly possible to disambiguate between the two or to use dur!"msecs" directly). And regardless of this specific situation, in general, turning a member function into a free function risks breaking code, since instead of it being a member function that automatically wins out with UFCS, it could suddenly be in conflict with another function of the same name, meaning that the calling code would have to then disambiguate between them whereas it didn't before. So, in general, turning member functions into free functions isn't a great idea if you're not in control over all of the code involved or otherwise aren't concerned about the potential fallout. - Jonathan M Davis
Nov 22 2017
On 11/18/17 9:03 AM, Timon Gehr wrote:> TickDuration will soon be deprecated, and none of the other time stuff > supports floating point. Anyone who wants that functionality can calculate > the floating point values from the integral values that the types do > provide. It's not something that most code should be doing, but the API > makes it possible for those who care. "Not something that most code should be doing"? I have never used StopWatch and then /not/ wanted to do something like to!("seconds",double)! There seems to be no good reason to break my code beyond requiring a different import here. What are the perceived shortcomings of the to!("seconds", double) interface?My take on this, as someone who has argued extensively NOT to use double for timing calculations (I was responsible for adding the TimeSpan type in Tango (the equivalent of Duration) and marginalizing Interval (based on double) [1]): 1. All OS calls with timing requirements use non-floating point to represent how long to sleep. After all a CPU uses discrete math, and the timing implementation is no different. 2. Sometimes it is VERY important to use exact representation for everything. Example: I want to sleep for 1 microsecond, if you had a function that accepts a floating point value, and you pass in 0.000_001, you might actually sleep for 0 ticks, which is vastly different. 3. Sometimes it is not as important. Example: if you want to sleep for 1.75 seconds, having a function that converts the float representation of 1.75 into a Duration is useful, and reasonably accurate. It isn't going to ruin your application if the sleep passed to the OS is 1.749999999 seconds. Your sleep probably isn't going to be exactly accurate anyways, as most of use use non-real-time OSes. 4. There are many libraries, the most obvious one to me is Apple's core library, which use a double for representing time everywhere. So it's not without precedent. 5. Responding to Walter's one-liner resistance, if the one liner is trivial to get right, then sure, don't include it. It could even be written in-line. But if it's easy to get WRONG, or is annoying to have to write, then I think it's worth having, even if it's a one-liner. In my opinion, type conversion is one of those things that falls into that second category. How can I construct the most accurate Duration with a given double that is in the form of seconds? You'd have to know the representation of Duration as hectonanoseconds in order to get this right. While trivial to write once you *know* that, it's not trivial to write if you *don't*. Having a library function (even a one-liner) that says "I'll save you from the implementation details" is useful. related: https://github.com/dlang/druntime/pull/1927 Bottom line: one-liner-ness shouldn't be an automatic disqualifier. ----------- After having used Apple's SDK quite a bit, I've changed my opinion slightly since my Tango days. It is useful to have a floating point representation of time, and can be used to good effect. I would be fine with a mechanism to convert to/from double with a Duration in druntime (in fact, Tango kept this), but still want to have the representation be as accurate as possible when it comes to calling OS functions. All the public APIs of druntime/phobos should take/return only Durations, not doubles, and let the user convert if they want to use doubles elsewhere. -Steve [1] http://dsource.org/projects/tango/ticket/671
Nov 22 2017
On 11/22/2017 5:45 AM, Steven Schveighoffer wrote:1. All OS calls with timing requirements use non-floating point to represent how long to sleep. After all a CPU uses discrete math, and the timing implementation is no different.Microsoft has numerous COM APIs for time functions. One of them I had to deal with used doubles to represent seconds. This had to be interfaced with other time functions that used integers. The trouble came from round trips - there were cases where double=>integer=>double did not produce the same result. Even worse, double=>integer=>double=>integer=>double ... produced a creeping shift in the value! It took much time to come up with a method of preventing such drift, and even that was unreliable.5. Responding to Walter's one-liner resistance, if the one liner is trivial to get right, then sure, don't include it. It could even be written in-line. But if it's easy to get WRONG, or is annoying to have to write, then I think it's worth having, even if it's a one-liner. In my opinion, type conversion is one of those things that falls into that second category. How can I construct the most accurate Duration with a given double that is in the form of seconds? You'd have to know the representation of Duration as hectonanoseconds in order to get this right. While trivial to write once you *know* that, it's not trivial to write if you *don't*. Having a library function (even a one-liner) that says "I'll save you from the implementation details" is useful.Another solution is to put the one-liner not in Phobos, but in the documentation as an example of how to use it. The user will have to look up the function in the documentation anyway.Bottom line: one-liner-ness shouldn't be an automatic disqualifier.As always, use good judgement. You and I differ on where that line is, however. I prefer a small interface with a minimal number of orthogonal functions, from which I can assemble what I need. An interface with a blizzard of functions all doing overlapping things with unknown tradeoffs is cognitive overload. The documentation of such an interface should, of course, provide examples of how to assemble those minimal functions into commonly needed solutions. --- As an aside, Andrei has worked very hard trying to figure out how to break down the memory allocator into the smallest collection of orthogonal parts that can then be assembled *by the user* into whatever he needs. It is not obvious, and amazingly nobody has done it before. https://dlang.org/phobos/std_experimental_allocator.html He did the same thing with the checked int package, which blows away every other checked integer solution I've seen. I believe it's the future of How To Do Interfaces Right :-) https://dlang.org/phobos/std_experimental_checkedint.html The documentation for both is a bit intimidating, though. There should be a more tutorial oriented overview.
Nov 22 2017
On Wednesday, 22 November 2017 at 22:17:05 UTC, Walter Bright wrote:On 11/22/2017 5:45 AM, Steven Schveighoffer wrote:It's fixed point, not floating point, but this famous software disaster is a pretty dramatic example: http://www-users.math.umn.edu/~arnold/disasters/patriot.html +1 to using integer arithmetic for the low-level time APIs.1. All OS calls with timing requirements use non-floating point to represent how long to sleep. After all a CPU uses discrete math, and the timing implementation is no different.Microsoft has numerous COM APIs for time functions. One of them I had to deal with used doubles to represent seconds. This had to be interfaced with other time functions that used integers. The trouble came from round trips - there were cases where double=>integer=>double did not produce the same result. Even worse, double=>integer=>double=>integer=>double ... produced a creeping shift in the value! It took much time to come up with a method of preventing such drift, and even that was unreliable.
Nov 22 2017
On 2017-11-23 12:55, sarn wrote:+1 to using integer arithmetic for the low-level time APIs.and nobody is advocating to change this. it is about being able to use such result (duration) with non-time focused libraries/functions (eg. general maths/stats) expecting doubles. if this is not possible in an obvious/standard way (being to!... in D) this is the very moment all potential python-to-D converts will run away screaming. putting the solution for this common problem only in the docs will not appease them either but rather make them mock D. i still don't understand how problems could arise from a supported one-way conversion -> double. of course, double -> time or duration is something different and i tend to agree that this should be left for the user to implement. i for my part could live with just one supported to!double conversion resulting in seconds. (i guess i am biased as i prefer to use SI units only for all my calculations.) /det
Nov 22 2017