What to use AddMapElement for?
What to use AddMapElement for?
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?
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?
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: What to use AddMapElement for?
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?
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.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]
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?
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.
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: What to use AddMapElement for?
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.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.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Re: What to use AddMapElement for?
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
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?
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?
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?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Re: What to use AddMapElement for?
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?
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?
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: What to use AddMapElement for?
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.
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?
- 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: What to use AddMapElement for?
Good to know, thanks 
At the same time, the behavior shouldn't be like that if it's not 100% reliable.

At the same time, the behavior shouldn't be like that if it's not 100% reliable.
Last edited by ChrisR on Thu Oct 31, 2024 8:05 pm, edited 1 time in total.
Re: What to use AddMapElement for?
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.
<edit>
also note: it can create problems if the passed key comes from an expression or function call (multiple evaluations)
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)
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?
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
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?
so you mean, this one should be Threadsafe without LockMutex ?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)
Code: Select all
If Not FindMapElement(Clients(), key)
*MapElement.myStructure = AddMapElement(Clients(), key)
If *MapElement
*MapElement\ID = clientID
*MapElement\lock = CreateMutex()
EndIf
EndIf