Tables and functions

Find quick help here to get you started with Hollywood
Post Reply
GMKai
Posts: 158
Joined: Mon Feb 15, 2010 10:58 am

Tables and functions

Post by GMKai »

Code: Select all

cart = {items = {}, numitems = 0}

Function cart:AddItem(n$, p)
    self.items[self.numitems] = {name = n$, price = p}
    self.numitems = self.numitems + 1
EndFunction

Function cart:RemoveItem(n$)
    For Local k = 0 To self.numitems - 1
       If self.items[k].name = n$
         RemoveItem(self.items, k)
         self.numitems = self.numitems - 1
         Return
       EndIf
    Next
EndFunction

Function cart:CheckOut()
    Local total = 0

    For Local k = 0 To self.numitems - 1
       NPrint(self.items[k].name, self.items[k].price)
       total = total + self.items[k].price
    Next

    NPrint("Your total is", total)
EndFunction

cart:AddItem("DVD", 10)
cart:AddItem("Blizzard PPC", 1000)
cart:AddItem("AAA Chipset", 100000)
cart:AddItem("68070", 500)
cart:CheckOut()
cart:RemoveItem("Blizzard PPC")
cart:CheckOut()


ForEach(cart, DebugPrint)
The ForEach also prints the functions defined above.
What would be a favourable way to get the functions removed from the table?
Bugala
Posts: 1390
Joined: Sun Feb 14, 2010 7:11 pm

Re: Tables and functions

Post by Bugala »

You should do the Foreach for self.items basically.
Bugala
Posts: 1390
Joined: Sun Feb 14, 2010 7:11 pm

Re: Tables and functions

Post by Bugala »

Now I have a bit better moment to answer.

what you are doing is that you are checking every item that "CART" holds, this includes all those functions as example.

What you should do is check through "Cart.Items":

Code: Select all

ForEach(cart.items, DebugPrint)
This way It should display only the items.
GMKai
Posts: 158
Joined: Mon Feb 15, 2010 10:58 am

Re: Tables and functions

Post by GMKai »

Good points.

Maybe the example was misleading...

Think about a table with more data-attributes and even more functions.

Would you advise to nest it like this:

Code: Select all

cart = {data = {items = {}, numitems = 0}}
This would nest every attribute under cart.data

Should be nicer than removing functions from cart or whatever to have a "good" object.
User avatar
jPV
Posts: 734
Joined: Sat Mar 26, 2016 10:44 am
Location: RNO
Contact:

Re: Tables and functions

Post by jPV »

How about having cart items at integer indices, and functions and other data at string indices?

Then you could use ForEachI() to iterate just items and not functions or other data.

So that it would look like this basically:

Code: Select all

cart = {
    additem = function,
    removeitem = function,
    {name = "first item", price = 111},
    {name = "second item", price = 222}
    etc.
}
Bugala
Posts: 1390
Joined: Sun Feb 14, 2010 7:11 pm

Re: Tables and functions

Post by Bugala »

Well, instead of thinking where to put that Items part, you could look the whole problem from a different angle. Since this is in newbie question section, I assume you might be wanting even an answer like this:

Now, lets say you have

Code: Select all

Enemy = {X=1, Y=2}
Now usually you would use it simply:

Code: Select all

Enemy.x = Enemy.x + 1
or

Code: Select all

CurrentX = Enemy.x
But, quite many programming books show instead of doing this, to have so called Setter and Getter Functions:

Code: Select all

Enemy = { X=1, Y=2}

Enemy.SetX = Function(Val)
Enemy.X = Val
EndFunction

Enemy.GetX = Function()
Return(Enemy.X)
EndFunction

Now this might seem bit silly to do such a heavy way, like using it now is:

Code: Select all

CurrentX = Enemy.GetX()
NewX = CurrentX + 1
Enemy.SetX(NewX)
Clearly not as handy as simply using Enemy.X, and I ignored this for years, but during last two years I have started to appreciate this approach, as I have finally got the idea better.

Now using it for something like Enemy.X might well be overkill, as often times thin like that is simple enough to make it better to use simply Enemy.X, but in your Items case for example, using getter function probably makes a lot of sense.

Bit of Example:

Code: Select all

Cart.GetItems = Function()
Return(Cart.Items)
EndFunction

Cart.AddItem = Function(Item)
	Local Items = Cart.GetItems()
	InsertItem(Data, Item)
EndFunction

Cart.RemoveItem = Function()
	Local Items = Cart.GetItems()
	...
EndFunction

Cart.CheckOut = Function()
	Local Items = Cart.GetItems()
	Foreach(Items...)
	...
EndFunction

Now suppose you decide to change the location of the items to, as you suggested:

Code: Select all

cart = {data = {items = {}, numitems = 0}}
What do you need to do now to change the code back to working?
Change just one line:

Code: Select all

[code]Cart.GetItems = Function()
Return(Cart.Items)
EndFunction

Into:

[code]Cart.GetItems = Function()
Return(Cart.data.items)
EndFunction
And every other function works like they used to.

Or lets suppose you decide that those items are kept somewhere completely elsewhere than In cart, like

Code: Select all

Shopper.ItemsAboutToBuy
What needs to change on the original code? Once again, just one line of code:

Code: Select all

Cart.GetItems = Function()
Return(Shopper.ItemsAboutToBuy)
EndFunction
By using getter function to get the Items, you don't really need to worry much about where you are storing the items, since if you come to conclusion they be better somewhere elsewhere, just change the location and change that one line of code, and everything works as they should.
GMKai
Posts: 158
Joined: Mon Feb 15, 2010 10:58 am

Re: Tables and functions

Post by GMKai »

Thanks alot.

The idea that had to emerge is the separation of functions and data.

Having Setters/Getters ist definetly the way to go.

Having an object with a designated spot for attributes is also handy.
Bugala
Posts: 1390
Joined: Sun Feb 14, 2010 7:11 pm

Re: Tables and functions

Post by Bugala »

One more notice about this.

In getter Function I was simply using

Code: Select all

Return(Items)
And like in the AddItem situation:

Code: Select all

Local Items = Cart.GetItems()
InsertItem(Items, Item)
This works and might be exactly how you want to do it even.

Point being, that although "Items" in AddItem part is Local, meaning it gets destroyed after you leave that function, it however works since Local Items is actually a reference to the Original Cart.Items, which means that whatever you do to that Local Items, will also happen to Cart.Items (or technically speaking, there is only one copy of Cart.Items, and since Local Items is a reference to Cart.Items, it means that it changes Cart.Items only, but since Local Items is like another name how to use Cart.Items, you can see everything with Local Items too).

This might be what you want, and then you don't need a separate Setter function at all for the Cart.Items.

But, there can be situations where you might want to get the Cart.Items as a Local copy, so that you can change the Local copy into something different, without affecting the original Cart.Items.

For example, maybe you have different ways to Sort the items, in that case you maybe want a temporal copy of Items that you can sort into any order you want, while original Cart.Items remains unsorted.

To do this, you have two options:

1.
You use:

Code: Select all

Local CartItems = Cart.GetItems()
Local Items = CopyTable(CartItems)
Or, if you want to make more sure to not accidentally mess things, you change the Getter Function into following:

2.

Code: Select all

Cart.GetItems()
Return( CopyTable(Cart.Items) )
EndFunction
In which case the returned Items is an independent copy of that table instead of reference to the cart.Items table.

But if you use this approach, which helps you avoid accidentally changing Cart.Items, you then need to use Setter Function when you do want to make changes, like in Cart.InsertItem, after you have inserted the item, you need to use

Code: Select all

Cart.SetItems(Items)
Which requires a Setter Function:

Code: Select all

Cart.SetItems(Items)
Cart.Items = Items
EndFunction
Post Reply