What to use AddMapElement for?

Everything else that doesn't fall into one of the other PB categories.
User avatar
jacdelad
Addict
Addict
Posts: 2010
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

What to use AddMapElement for?

Post 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?
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
Quin
Addict
Addict
Posts: 1133
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: What to use AddMapElement for?

Post 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().
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

Re: What to use AddMapElement for?

Post 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.
User avatar
jacdelad
Addict
Addict
Posts: 2010
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: What to use AddMapElement for?

Post 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.
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
Quin
Addict
Addict
Posts: 1133
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: What to use AddMapElement for?

Post 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.
User avatar
skywalk
Addict
Addict
Posts: 4218
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: What to use AddMapElement for?

Post 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.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

Re: What to use AddMapElement for?

Post 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).
User avatar
skywalk
Addict
Addict
Posts: 4218
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: What to use AddMapElement for?

Post 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?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
jacdelad
Addict
Addict
Posts: 2010
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: What to use AddMapElement for?

Post 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?
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
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: What to use AddMapElement for?

Post 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.
User avatar
STARGÅTE
Addict
Addict
Posts: 2232
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: What to use AddMapElement for?

Post by STARGÅTE »

  1. 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.
  2. 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 moreTypeface - Sprite-based font include/module
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: What to use AddMapElement for?

Post by ChrisR »

Good to know, thanks :)
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.
#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: What to use AddMapElement for?

Post 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)
User avatar
idle
Always Here
Always Here
Posts: 5896
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: What to use AddMapElement for?

Post 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)
User avatar
Bisonte
Addict
Addict
Posts: 1313
Joined: Tue Oct 09, 2007 2:15 am

Re: What to use AddMapElement for?

Post 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    
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
Post Reply