Page 1 of 2
What to use AddMapElement for?
Posted: Thu Oct 31, 2024 1:33 pm
by jacdelad
Hi,
I'm using maps for quite a time now and it's no witchcraft (in fact they are very useful). Creating elements is "automatic" due to creating them when accessing them. However, there's a command "AddMapElement", but when should I use it? I understand what the help says, but especially in combination with "#PB_Map_NoElementCheck" I don't see a usecase. Interesting enough, searching for "AddMapElement" in the search here in the forum spits out 30 pages of results.
Can someone enlighten me, please?
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 1:48 pm
by Quin
I personally choose to always use AddMapElement(), because I very strongly dislike the recently introduced behavior of auto-creating keys as you access them. That is *not* how a hashmap should work in my eyes, because if I typo a key name when trying to access something, it just won't complain at all and will just make a new element silently. So I always use AddMapElement() and FindMapElement().
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 2:10 pm
by PBJim
Quin wrote: Thu Oct 31, 2024 1:48 pm
I personally choose to always use AddMapElement(), because I very strongly dislike the recently introduced behavior of auto-creating keys as you access them. That is *not* how a hashmap should work in my eyes [snip]
Agreed, I curse the auto-create feature all the time, it's so easy to accidentally access a map with Map("KEY") and not realise that it *could* have an unwanted outcome in edge cases.
Something I'm currently at work on, adding FindMapElement() really increases the size of my code. In some cases, to try to keep my code simple, I've left it as a bug but later cleaned-up any empty map elements.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 2:59 pm
by jacdelad
Thanks for the answers, but how "recently" was the autocreation introduced? I'm using PB since 5.21 and can't remember it was not like that in any of these versions.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 3:04 pm
by Quin
jacdelad wrote: Thu Oct 31, 2024 2:59 pm
Thanks for the answers, but how "recently" was the autocreation introduced? I'm using PB since 5.21 and can't remember it was not like that in any of these versions.
It was done in
6.00, more specifically beta 2.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 3:07 pm
by skywalk
Quin wrote: Thu Oct 31, 2024 1:48 pm... I very strongly dislike the
recently introduced behavior of auto-creating keys as you access them.
This has
always been the case with Maps. I ran afoul of this long ago. My issue was the default element created by an inadvertent MapKey creation had to be #EmptyString and not a #Null. Else, my code would crash on any string access to a #Null element, but continue on for an #EmptyString. Certainly using FindMapElement() is important.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 3:58 pm
by PBJim
The below thread suggests that the map behaviour was changed in PB 6, but there is a comment that prior to PB 6 the behaviour was inconsistent.
viewtopic.php?t=79815
STARGÅTE » Thu Sep 15, 2022 8:34 pm
And yes, the bug (that sometimes no element was created and some times an element was added) is now fixed (more consistent).
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 4:16 pm
by skywalk
Of course, if you attempt to access the same MapKey("foo"), no new elements are added.
In my experience, any comparison like | If myMap("blah") Then | an empty element for "blah" would be added.
Maybe it depended on the underlying type of Map defined?
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 4:18 pm
by jacdelad
Ah yes, hopping from one thread to another makes me vaguely remember that there was something to discuss about.
So more specific: What would I use AddMapElement in 6.12 for? Can it be considered as deprecated? Also, with the parameters seen in the help, there's some kind of temporary-overwrite-mode?
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 7:10 pm
by ChrisR
Personally, even if I know that the key is automatically created,
I often prefer to use AddMapElement, as it's easier to read afterwards
Also, it's a good thing there's FindMapElement, otherwise it would be so easy to make a mistake and create a key you didn't want.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 7:42 pm
by STARGÅTE
- AddMapElement() is the only way to check if the element was really created.
If you have a Map with elements of huge sizes, it could be, that adding a new element fails.
Then, AddMapElement() returns 0, creating the element on-the-fly would result in an IMA at this line.
- With AddMapElement() you can be sure that the map element is newly initialized, regardless of whether it already existed or not.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 7:57 pm
by ChrisR
Good to know, thanks

At the same time, the behavior shouldn't be like that if it's not 100% reliable.
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 8:05 pm
by #NULL
You could add some inline check. Not sure if you would want to. Adds bloat, reduces readability and is specific for a single map unless you want to pass a map every time, but maybe its useful in some cases.
Code: Select all
NewMap m.i()
CompilerIf #PB_Compiler_Debugger
Macro mSafe(key)
m(Left(key, Len(key) + 0 * Bool(FindMapElement(m(), key) <> 0 Or DebuggerError(~"invalid map key: m(\"" + key + ~"\")") ) ) )
EndMacro
CompilerElse
Macro mSafe(key)
m(key)
EndMacro
CompilerEndIf
m("a") = 10
m("b") = 20
mSafe("a") + 1
mSafe("c") + 1
d.s
ForEach m()
d + MapKey(m()) + ": " + m() + #CRLF$
Next
MessageRequester("m()", d)
<edit>
also note: it can create problems if the passed key comes from an expression or function call (multiple evaluations)
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 10:27 pm
by idle
Also worth mentioning Maps aren't 100% Thread safe.
The current element could potentially change if the map is being accessed across threads.
so if there's any uncertainty use an appropriately scoped mutex or you might end up mixing an elements fields with another
Code: Select all
LockMutex(MapMutex)
If Not FindMapElement(Clients(),key)
If AddMapElement(Clients(),key)
clients()\ID = clientID ;these could be corrupted without mutex
clients()\lock = CreateMutex()
EndIf
EndIf
UnlockMutex(MapMutex)
Re: What to use AddMapElement for?
Posted: Thu Oct 31, 2024 10:55 pm
by Bisonte
idle wrote: Thu Oct 31, 2024 10:27 pm
Also worth mentioning Maps aren't 100% Thread safe.
The current element could potentially change if the map is being accessed across threads.
so if there's any uncertainty use an appropriately scoped mutex or you might end up mixing an elements fields with another
Code: Select all
LockMutex(MapMutex)
If Not FindMapElement(Clients(),key)
If AddMapElement(Clients(),key)
clients()\ID = clientID ;these could be corrupted without mutex
clients()\lock = CreateMutex()
EndIf
EndIf
UnlockMutex(MapMutex)
so you mean, this one should be Threadsafe without LockMutex ?
Code: Select all
If Not FindMapElement(Clients(), key)
*MapElement.myStructure = AddMapElement(Clients(), key)
If *MapElement
*MapElement\ID = clientID
*MapElement\lock = CreateMutex()
EndIf
EndIf