Bug 10828 – datetime toString functions should accept sink
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-08-15T12:59:01Z
Last change time
2018-02-17T17:25:52Z
Assigned to
No Owner
Creator
monarchdodra
Comments
Comment #0 by monarchdodra — 2013-08-15T12:59:01Z
Basically, all datetime functions' "toString" signature are:
"string toString();"
There should be an overload which accepts a sink (eg:)
"const void toString(scope void delegate(const(char)[]) sink);"
Without this, code such as:
writeln(currentTime)
Will needlessly allocate a string.
This is an issue for this user:
http://forum.dlang.org/thread/[email protected]#post-ypgppdursxtwljhkjoed:40forum.dlang.org
Who wants to log the time at which destruction happens. This leads to a:
core.exception.InvalidMemoryOperationError
Due to an allocation during a collect.
Implementation should be "trivial"*, since the implementation of "toString" is basically "return format("%%%%", args)".
So this can "easily" be changed to:
"formattedWrite(sink, "%%%%", args)"
Comment #1 by Marco.Leise — 2014-04-08T09:21:09Z
The problem will move on to the checks of the format specifiers, which want to throw exceptions, which means the GC could in turn throw InvalidMemoryOperationError.
Now one could fix the GC to allow exceptions to be thrown from ~this(), but basically if the dtor really fails, your program is possibly in an invalid state.
Maybe my thinking is wrong, but I'd say it should either complete or terminate the application like AssertError, InvalidMemoryOperationError or OutOfMemoryError do.
That said, the logging should be wrapped in a try-catch here: It is more important that the rest of the dtor succeeds. About the GC, I don't know what to do. It would be best if the implementation could allow further allocations while the collection is running. Like when you create a new pool for the allocations and join it with the old one after collection.
Comment #2 by monarchdodra — 2014-04-08T10:06:58Z
(In reply to comment #1)
> The problem will move on to the checks of the format specifiers, which want to
> throw exceptions, which means the GC could in turn throw
> InvalidMemoryOperationError.
An exception is only thrown if the format string is invalid. Furthermore, there *is* a toString which simply does not take format. So *that* should never throw (though it might not actually be nothrow, due to UTF).
Besides, GC and destructors is only one aspect of the issue. Having a `toString` that takes a sink is just good design overall. Avoids gratuitous allocations.
Comment #3 by issues.dlang — 2014-04-09T10:45:34Z
Regardless of whether this fixes that particular user's problem, it's certainly the case that there should be to*String overloads in std.datetime which take sinks, because that's what we should be doing with all toString functions.
Comment #4 by monarchdodra — 2014-04-09T10:52:07Z
(In reply to Jonathan M Davis from comment #3)
> Regardless of whether this fixes that particular user's problem, it's
> certainly the case that there should be to*String overloads in std.datetime
> which take sinks, because that's what we should be doing with all toString
> functions.
@jmdavis: Are you still working on the re-packaging of datetime? What's the status on that?
Comment #5 by issues.dlang — 2014-04-09T12:50:10Z
> @jmdavis: Are you still working on the re-packaging of datetime? What's the status on that?
Enough has changed that I'm going to have to redo it, and I'm short on time these days. It's currently my plan to make a series of smaller pull requests to clean up the code further prior to splitting the module so that I don't have to do as much cleanup when splitting it.
Comment #6 by bugzilla — 2014-11-12T21:03:56Z
I object to creating a same-only-different design instead of using Output Ranges.
Comment #7 by hsteoh — 2014-11-12T21:13:30Z
But a sink *is* an output range!
Comment #8 by monarchdodra — 2014-11-12T21:34:05Z
(In reply to Walter Bright from comment #6)
> I object to creating a same-only-different design instead of using Output
> Ranges.
That's the way it is designed though:
http://dlang.org/phobos/std_format.html#.formatValue
It's documented, does not allocate, supports unicode but does not decode, and is already rolled out on lots of data types, including (but not limited to) things like complex. complex even supports custom format flags.
There's a wiki entry:
http://wiki.dlang.org/Defining_custom_print_format_specifiers
And I also believe there are stack overflow articles about how awesome this design is.
Also, it's not "same-only-different" design, as end users shouldn't actually be calling "toString": This function is merely a hook for higher order functions like "format", "to!", "writeln" etc...
So we'd really be doing:
`string toString()` => `void toString(scope void delegate(const(char)[]) sink)`
The old function would be replaced, so there'd be no duplicate function.
At this point, objecting to this change is objecting to Phobos' entire user defined type to string mechanism.
Comment #9 by github-bugzilla — 2018-01-25T16:13:00Z