Manage dictionaries better with Dictionary++(module system)

It’s on GitHub!
It’s open source under MIT!

What is Dictionary++?

Well, Dictionary++ is a module that introduces 11 functions to the standard dictionary. Take for instance the limitations of the regular dictionary in Luau.

local foo = {
    bar = 1,
    car = "red",
    orange = {
        tasty = true
    }
}

print(foo.red)
print(foo["bar"])

Oh well…all you can do is just access it from it in a very 1-dimensional way and if you were to try to simply access “tasty” from “orange” you would be required to type out “foo.orange.tasty” which is fine at first, but what about larger scaled dictionaries? It gets tedious!

This is where Dictionary++ comes into play!

Simply download the module from the website or manually import it from GitHub, and then place the module in ReplicatedStorage(or anywhere else it doesn’t matter) and type out:

local dictionaryPlusPlus = require(game.ReplicatedStorage:WaitForChild("Dictionary++"))
local dictionary = dictionaryPlusPlus({
    A = "A",
    B = 2,
    C = {
        D = true,
        E = {
            F = 1
        }
    }
})

print(dictionary:get("A")) --prints "A"

Now, why would this be more practical? Isn’t that just more typing? Yes and no. Currently its more typing and if you simply wanted to use a dictionary in this sense you can use a normal dictionary but this is where it gets cool. Let’s get into the first of the 11 functions…

YourDictionary:get(key)
This function would automatically scan every single portion of the dictionary until it finds a match for the key you have provided! 2 things are improved with this!

  1. it will get and find your key from anywhere in the dictionary making it so much faster to retrieve keys! No more typing “dictionary.C.E.F” simply type out dictionary:get(“F”). Only disadvantage is that currently you can not have an element be named the same as another one and expect dictionary:get(key) to work properly. You can still access it by typing “dictionary.UserContent.blahblahblah” though!
  2. It will never return nil! Why is this a bonus? Well it means your code won’t break automatically, but don’t worry! It still gives you a warning in the output that it did not find the element you wanted!

And as an added bonus you don’t pass “key” correctly capitalized! It will still find your element. “oRange”, “Orange”, "orange, etc., all work the same!

YourDictionary:set(key, value)
Like the name implies, it sets the key to the value you wanted.

YourDictionary:descendValues()/YourDictionary:descendKeys()
A function similar to GetDescendants!

YourDictionary:add(key, value)/YourDictionary:remove(key)
Of course you can type out “dictionary[key] = value”/“dictionary[key] = nil” so these are more so syntax sugar functions!

YourDictionary:wipe()
Like the name implies it wipes the dictionary clean. No history, no takebacks. Wiped forever.

YourDictionary:convertKeys()/YourDictionary:convertValues()
Now this one is in my opinion the most interesting. It allows you to either convert all the values(or keys) into an array! Take for instance you had a dictionary

local dictionaryPlusPlus = require(game.ReplicatedStorage:WaitForChild("Dictionary++"))
local dictionary = dictionaryPlusPlus({
    foo = 1,
    bar = false
})

print(dictionary:convertKeys) -prints [1] = "foo" [2] = "bar"
print(dictionary:convertValues) -prints [1] = 1 [2] = false

YourDictionary:count()
Returns the count of all the elements in your dictionary(very useful!)

dictionary:replicateEverything()/dictionary:replicatedCreated()
Another interesting one. So under the hood when you create a dictionary with Dictionary++ it actually looks more like this

local dictionaryPlusPlus = {
    UserContent = {
        --Your Actual Key/Values
    },
    --Functions such as get(), set(), replicateEverything(), etc.
}

So when you call YourDictionary:replicateEverything() it returns back EVERYTHING including the default functions. Likewise, YourDictionary:replicateCreated() will only return your custom key/values!

Finally why the name? Why Dictionary++?
Well…it’s referencing the popular programming language C++ which began as just a better version of C. Why the ++? Well because in a lot of programming language(not Lua/Luau) “integer++” is shorthand for “integer += 1” or “integer = integer + 1”. So it’s more like Dictionary + 1!

Woah! That was a lot but I’m finished!
I hope people will benefit from this module!
If you have any questions/concerns just reply to the post and I’ll try to get back ASAP.

6 Likes

I really don’t see the purpose of this, It brings nothing new. It just makes using dicts a little more “aesthetic”.

I don’t think it gets tedious with larger tables at all, Lua comes with many functions that help you deal with large tables and sort them out.

Also, your get functions are simply looping not the best, what If you have the same Index under another table? Example:

local dict = {
A = { B = "B"},
C = {C = "C"},
}
3 Likes

Documentation is poor right now but there is use. You mention there being “many functions” yet for dictionaries there is none. No functions at all. Want to get the size of a dictionary? Can’t. Want to get a key/value nested really low? Can’t(easily), etc… My point is, at least for dictionaries, there isn’t any functions. This module fixes that. And as for your question of “What if you have the same index under another table?” I’m glad you asked! Yes, in this moment of time it would just return the first table, but this will be fixed in a future release and you’ll be able to choose how far down it will “dig” for your element!

1 Like

There are quite a handful of functions that come with Lua, However, yes some of the functions you created are useful, however, we also have a library that is made for this called TableUtil.

3 Likes

You (or anyone who requires such functions to operate on dictionaries) can simply just create a library (or use an existing one; there’s a lot of them out there already) containing all these functions rather than create a “custom dictionary”–type object wrapper without real need.

2 Likes

Those two are for tables not dictionaries! They wouldn’t work for dictionaries

local _table = {1, "Hello, World!", true, false, -1)
local dictionary = {
  Key = "Value"
}

Well it’s not inherently a wrapper as it only makes use of dictionaries for the player to create their “object”. It’s more so a class. Plus, that’s exactly what I did and just thought that I would share it because it wouldn’t hurt to :D. But yes, this will not be for everyone and I could see why you wouldn’t use it. For me though, I’d have rather have the functions there already!

1 Like

Some of the Lua functions do work with dictionaries. Same with TableUtil if you take a look at their documentation you are able to see that they are using dictionaries.
image

2 Likes

I did not know that! I will look more into the documentation of TableUtil but I believe what sets my module and theres apart is that mine is more so like a class in C#(my “main” language) and this is more like a wrapper! Not saying it’s bad just it appears mine and theirs are different!

1 Like

Yes, but the downfall of using your module really is every time you return an Item from a table it clones that Item. So it’s really not that much of an efficient class.

1 Like

I have thought about that while originally writing it. Although I haven’t really been able to think of another way for the script to retrieve the data back other than using return. Kind of like a “Oh, there’s more functions to it but I will be sacrificing so and so” somewhat of a trade-off. Of course, in the state that the module is in right now there’s not “too” much that would maybe make someone other than me who did write it to my needs for my own game use it, but I do have plans to add onto it to make it more “worth while” I guess!

1 Like

I suggest taking advantage of the metatable methods that you are able to use with metatables here is a link to the documentation to it, you should be able to see it once you scroll down a little bit.

1 Like

I have some questions to ask but would you like to move this to Discord because I guess filling up this post isn’t the best idea haha

1 Like

Go for it! frames#4888
Character Limit

1 Like

All right! I sent a friend request!

Thanks. Thats all i can say.
i have to do long waitforchild shit or .blah.blah.blah, now all i can do is this:

local dictionaryplusplus = require(path.to.dictionaryplusplus)
local replicatedStorage = game:GetService("ReplicatedStorage")
local replicatedDescendants = replicatedStorage:GetDescendants()
local moduleWithVeryLongPath = dictionaryplusplus:get("module")
1 Like

This just “overcomplicates” dictionaries in my opinion.

if you have a time complexity of O(n) to find a key value pair, something has gone wrong and, the extra method call overhead is unneeded, why do dictionary:get(“A”) instead of just doing dictionary[“A”] (+ if you need to look through every table within the table that is being looked through, there is almost certainly a better solution with a lower time complexity).

Why use dictionary:set(key, value) instead of dictionary[key] = value, it’s just uneeded extra method call overhead + lua function call overhead.

dictionary:descendValues() seems interesting and may have legitimate functions but, it doesn’t justify using this in my opinion, a simple function with a loop would suffice but, I could see actual uses for this method.

dictionary:add and dictionary:remove don’t really improve the syntax in any way in my opinion, it’s much faster and cleaner to just do dictionary[key] = value dictionary[key] = nil.

dictionary:wipe() is unnecessary in my opinion, why not just assign a new table to some variable instead?
This results in extra method + function call overhead.

dictionary:convertKeys seems like it’d have some nice uses but, I don’t think it justifies using this module due to the overhead but, if someone needed a function like this, they could probably use a simple function but, a method call is also pretty nice too.

dictionary:count() seems really useful.

dictionary:replicateEverything() and dictionary:replicatedCreated() also seem really useful but, I don’t know how well this will scale to larger servers (it is a really nice function regardless).

This entire resource is basically a copy from TableUtil from the NevermoreEngine.

Hey! I have not heard of nor used TableUtil until last night. I haven’t been able to read the documentation yet so would you mind explaining how it is a copy of it? Thanks!

dictionary:get(key) was made only for the intended purpose of lightly to deeply nested directories! You say that there is “almost certaintly a better solution with a lower time complexity”, would you mind giving an example to one?

Again this is really only meant to be used for lightly to deeply nested directories.

And yes, you’d be correct. These functions solely existed just to make it “look” better but serve no “real purpose”. I’ll potentially just remove them(or give them an actual reason to exist) in an update to it. I guess for now the only reason I have them is because like I stated in the documentation, when you create a “Dictionary++” it’s like “Main dictionary with functions → user content → your actual key/value” therefore to actually add a new key/value you would have to do “dictionary.UserContent[key] = value”

Thank you! And yes, if you’re only using the library for that method then it wouldn’t really be of use I suppose.

Again this really just exists because if you were to do “dictionary = {}” it would remove every function so “dictionary:wipe()” is more like “dictionary.UserContent = {}” if that makes sense.

Thank you!

Now. Does this really justify using it? I think that just comes down to personal preference. For some people it’ll be more useful than it will be to others.