-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allocation free printing: remove write(a: varargs[string]) #197
Comments
Hrm, that PR creates quite a significant breaking change. Besides, what about similar procedures, like |
In my opinion there is no way around allocation free printing other than evading the |
Allocation is expensive compared to string conversion, but it is cheap compared to writing a file. Writing to a file is done is buffered way anyway. You allocate a buffer, fill in the buffer and you flush the buffer when it is full. This RFC needs at least some evidence that performance will be greatly improved by making this breaking change. |
Well, writing to a But even if allocation would always be orders of magnitudes faster than writing to any |
I like the proposal but your PR does much more than just removing the hurtful The motivation is also a bit poor, fragmentation depends on the allocator and is only a problem once it was detected to be a problem (rarely!). But a printf that is low level enough to be useful inside Nim's GC or on embedded devices that hardly have any memory at all etc would be a welcome improvement. |
Well when I remove the hurtful
Because that would break real existing code.
Well what I had in mind when I was writing that was this talk: https://youtu.be/1faaOrtHJ-A?t=1950
Well that is another argument I will put in in the description. |
But your RFC is about removing this one write overload that is harmful, so it's about a breaking change. Which is fine but we can handle the code breakage differently, say via a |
My PR only breaks code that hypothetically somebody could have written. That is a difference to "it breaks nimble packages".
Didn't you just say to not mix refactorings with bugfixes? Anyway, I am not against moving But regarding being able to use macros. This is the standard library, we don't need to use macros. If macros are not available we can always move things behind a magic proc instead. import macros
macro distributeTemplateVarargs(call: untyped, args: varargs[untyped]): untyped =
call.expectKind nnkCallKinds
result = newStmtList()
for arg in args:
let call = copyNimTree(call)
call.add arg
result.add call
template forward(args: varargs[untyped]) =
distributeTemplateVarargs(echo(" --> "), args)
# test it
forward(1,2,3, "foobar", "abc")
# output:
# --> 1
# --> 2
# --> 3
# --> foobar
# --> abc I would probably introduce a magic proc that does the same as the macro |
Yeah. And it's got nothing to do with an RFC process and the begin of an implementation.
For me it is though because I've seen your PR and it's currently full of bad code like emulating a varargs mechanism. |
There is a way to implement almost allocation-free printing, but it requires a more significant departure from the current design. It's the mechanism I'm using in Chronicles. Each Each parameter of the Finally, after all the parameters are written, the entire buffer of the stream is sent to Chronicles will support this model of printing with any format supported by our serialization library. The human-readable text representation produced by |
@zah What you are describing is technically the same or at least very similar to what I implemented in the PR. But instead of the new |
Here is my plan, and I think it actually aligns well with yours. We remove the io part of the existing system.nim and make people write an explicit |
This RFC is stale because it has been open for 1095 days with no activity. Contribute a fix or comment on the issue, or it will be closed in 7 days. |
Allocation is expensive. The costs are in allocation, deallocation, memory fragmentation (mostly a problem for long running server applications) and in garbage collector activity. Therefor I have a big interest to keep my main loop and especially tight loops free of allocations. Yet almost all string conversion and printing functions rely on temporary intermediate string objects (allocation). What I would like to have is a flexible printing mechanism, that does not allocate by construction.
There is a family of procs already existent in Nim that is almost already what I would like to have. The family of
proc write*(f: File, r: float32)
inio.nim
. It works on overloads for different types, therefore it is extendable for custom types (unlikefprintf
in C), it is implemented usually though withfprintf
from C, which is completely allocation free. There is one big problem though:proc write*(f: File, a: varargs[string, `$`])
exists. This means expressions such asstdout.write(x)
that would normally have no allocation at all, now might resolve to thevarargs[string, `$`]
overload without providing feedback to the programmer that this has happened. Variables of a custom types that do have an overloadproc write*(f: File; a: CustomType)
might still secretly resolve to thevarargs[string, `$`]
overload, because nim-lang/Nim#11225 has not been resolved yet.Another big advantage of
write
overecho
is, when it crashes when half of the line is printed, that half of the line is actually sent to stdout/stderr. Unlikeecho
where nothing is printed at all.So my proposal is to remove
proc write*(f: File, a: varargs[string, `$`])
from io.nim to have a style of writing to files and stdout that is free of allocation by construction.Here is the PR for this RFC: nim-lang/Nim#13277
There is a related RFC targeting fewer allocations for string conversations:
#191
The text was updated successfully, but these errors were encountered: