-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
table.mgetOrPut
without default val
#22994
Conversation
checked failed js test locally - looks ok: u@DESKTOP-H ~/Nim (mgetorput_with_default)> ./bin/nim js -d:release --run tests/js/t11353.nim
Hint: used config file '/home/u/Nim/config/nim.cfg' [Conf]
Hint: used config file '/home/u/Nim/config/config.nims' [Conf]
Hint: used config file '/home/u/config.nims' [Conf]
Hint: used config file '/home/u/Nim/tests/config.nims' [Conf]
Hint: opt: speed; options: -d:release
41513 lines; 0.351s; 37.875MiB peakmem; proj: t11353; out: t11353.js [SuccessX]
Hint: /usr/local/lib/nodejs/node-v20.10.0-linux-x64/bin/node --unhandled-rejections=strict /home/u/Nim/tests/js/t11353.js [Exec]
{}
{}
u@DESKTOP-H ~/Nim (mgetorput_with_default)> node --version
v20.10.0 |
mgetOrPut
without default val
What's the benefit over |
To avoid additiomal initialization of the default(B) in case if key is already in table It is applicable to any function instead of default because it is evaluated before mgetOrPut |
Why would it do that? |
because of function call and params evaluation order. I expected it works the same for any f() at the place of the default(B) if not special optimizations here |
Sorry, but please show the benefit of this with a benchmark. |
I agree that it is good point and it is not very clear if About more complicate objects you can find result here: Code:import criterion
import tables
const R = 100
type
U = object
c: seq[string]
d: seq[string]
e = 100
f = 200
j = 300
h = 400
T = object
a: int
b: array[100, U]
c: seq[string]
d: seq[string]
e = 100
f = 200
j = 300
h = 400
let cfg = newDefaultConfig()
benchmark cfg:
var xOld = initTable[int, T]()
var xNew = initTable[int, T]()
proc defaultOld() {.measure.} =
for _ in 1..10:
for i in 1..R:
xOld.mgetOrPut(i, default(T)).a.inc
proc defaultNew() {.measure.} =
for _ in 1..10:
for i in 1..R:
xNew.mgetOrPut(i).a.inc |
Almost 300x faster is a pretty big difference. FWIW, I think tim or its library counterpart emin is less off track for this kind of measurement than It still seems to me like a { There are actually even more general cases.. E.g., where the "key" itself is an integer offset into a string buffer that needs growing on puts, but not gets. Those seem out of scope for the current design, though. } |
@c-blake
That is why I decided to start with something simple, but which can cover most of the cases (default insert, probably, is the most popular case), but it covers lazy evaluation (not like template/macros, but a bit more than nothing) + it looks back-compatible Even without perf gains, it would be good to have |
I'm ok with your new overload, and mostly for the reasons you enumerate. I just think that in N years someone will also want the template anyway to cover more cases. :-) |
@c-blake Totally agree. And the reason I did not make it template at the moment because of the stopper with |
I also don't see a problem with a new name for the One other thing I could say possibly constructively is that, from the caller's perspective, I think of { This is really just to respond to your rationale. As said, I don't have a problem with the new overload. } |
Thanks for your hard work on this PR! Hint: mm: orc; opt: speed; options: -d:release |
By the way, in case no one else noticed there is a strong ambiguity here in terms of extending the existing naming convention. This PR drops an argument from No Nim release has happened yet to this very fresh merge. So, if some future |
@c-blake mget-or-put(with-default) or mgetordefault(and it means put too, mget is not just get) I am not sure and I am bad in naming, but I like less new functions :) |
It's a somewhat tricky situation and neither choice is very wrong. On the one hand, this new operation is a lot like Arguably, |
Another thing I am afraid, of mgetOrPut will be macros one day - mgetOrDefaults will be needed to be deprecated, but not mgetOrPut |
A "fourth consistency" I neglected to mention is higher-level. This module uses
Eventual obsolescence of this Anyway, it's not a huge deal as |
RFC: nim-lang/RFCs#539
mgetOrPutDefaultImpl template intotableimpl.nim
to avoid macrosTable
,TableRef
,OrderedTable
,OrderedTableRef
tests/stdlib/tmget.nim
tests update