ID:266016
 
I was thinking about it, and I was wondering if anyone ever tried using accessor methods in BYOND. For those not familiar with them, in many languages, rather than directly accessing the variables of objects, you call a method on them. So, if I had a player defined as:
mob
var/HP,Gold

The standard DM way of modifying these variables would be something like:
proc/luckyDay(mob/M) 
M.HP += 5
M.Gold += 5


Whereas, with accessors you'd define more functions and the same method would look like this:
mob/proc
getHP()
return HP
setHP(_HP)
HP = _HP
getGold()
return Gold
setGold(_Gold)
Gold = _Gold
proc/luckyDay(mob/M)
M.setHP(M.getHP()+5))
M.setGold(M.getGold()+5)


Now, this looks like a waste of code, which was certainly what I thought when I first learned other languages (since I learned DM first), but in reality there are some benefits. Like having control over the possible values for variables. You could put an if statement in the setGold to check that Gold isn't negative.

Now, obviously, I think some people do use these sort of functions in DM, but I've never heard of someone defining accessors for virtually all of their variables. Would it be worth all the extra functions for the peace of mind that each variable isn't going to have some strange value?

Another random thought is that it might be useful if there was a way to call these functions generically, and I'm not sure that's possible. Is there really a programmatic way to call functions in DM? Assuming you kept to a naming convention for the accessors, otherwise it'd be next to impossible.
Chessmaster_19 wrote:
Now, this looks like a waste of code, which was certainly what I thought when I first learned other languages (since I learned DM first), but in reality there are some benefits. Like having control over the possible values for variables. You could put an if statement in the setGold to check that Gold isn't negative.

I feel like this could be better done by doing something like this, but really, I only like that approach in DM (it seems more fitting than accessors, because we don't have private/public). I agree with you on stronger variable control, but that can be wrapped up in a nice datum.
Now, obviously, I think some people do use these sort of functions in DM, but I've never heard of someone defining accessors for virtually all of their variables. Would it be worth all the extra functions for the peace of mind that each variable isn't going to have some strange value?

I don't think so. In a language where you can go Object.getMyVariable().variableMethod(), I find it beneficial. Since DM doesn't let you, it just doesn't seem worth it, since you have to typecast it, or store it somewhere before you can use it, in the case of an object type.
Another random thought is that it might be useful if there was a way to call these functions generically, and I'm not sure that's possible. Is there really a programmatic way to call functions in DM? Assuming you kept to a naming convention for the accessors, otherwise it'd be next to impossible.
I think you can use call() to call procs with arguments -- call("proc")("procarg1","procarg2") if I'm not mistaken.
In response to DivineTraveller (#1)
DivineTraveller wrote:
Chessmaster_19 wrote:
Now, this looks like a waste of code, which was certainly what I thought when I first learned other languages (since I learned DM first), but in reality there are some benefits. Like having control over the possible values for variables. You could put an if statement in the setGold to check that Gold isn't negative.

I feel like this could be better done by doing something like this, but really, I only like that approach in DM (it seems more fitting than accessors, because we don't have private/public). I agree with you on stronger variable control, but that can be wrapped up in a nice datum.

Now, obviously, I think some people do use these sort of functions in DM, but I've never heard of someone defining accessors for virtually all of their variables. Would it be worth all the extra functions for the peace of mind that each variable isn't going to have some strange value?

I don't think so. In a language where you can go Object.getMyVariable().variableMethod(), I find it beneficial. Since DM doesn't let you, it just doesn't seem worth it, since you have to typecast it, or store it somewhere before you can use it, in the case of an object type.
Another random thought is that it might be useful if there was a way to call these functions generically, and I'm not sure that's possible. Is there really a programmatic way to call functions in DM? Assuming you kept to a naming convention for the accessors, otherwise it'd be next to impossible.
I think you can use call() to call procs with arguments -- call("proc")("procarg1","procarg2") if I'm not mistaken.

Your link is good, but I suppose I really am interested in doing it dynamically. I mean, yeah, any system works as long as I call it manually. But, it'd be nice to have some sort of automatic system that can work dynamically.
My main issues with this are editing. The game has an edit verb, but there's no way to restrict what staff use as values, so sometimes variables get pretty seriously broken.

As for doing it dynamically, I've never messed with call()() it just looks a little messy, but eval() actually works (even though its not documented). But I don't know if it'd be such a good idea to use eval...
In response to Chessmaster_19 (#2)
Perhaps I don't see what you mean by "automatic" then?
In response to DivineTraveller (#3)
I think he's looking for some sort of syntax for generics in DM. It would be nice to be able to use generics, abstract classes, and interfaces in DM but sadly it's not part of the syntax.
I've grown a little more lenient, but I generally use accessors if there's any worry of conflicting data types. It's how I was taught in college. I've also found it handy for updating skins as values change.
For many variables, that's how you should be doing it. Health, for example, or experience. Especially if you have interface displays that need to be updated to reflect the new values.

Everything that gets affected by changing a value gets done in that value's setter. It's unwise to have, in every place that changes health, a modification to health, a check for the health's range (is it above max? below 0 for death?) and all that.
// bad
mob/verb
punch(mob/M)
M.hp -= 1
if(M.hp <= 0)
M.die(src)

kick(mob/M)
M.hp -= 1
if(M.hp <= 0)
M.die(src)

// and a bunch of other things that do damage

// good
mob/proc/heal(amount, cause)
hp = min(max(0, hp+amount), max_hp)
if(!hp)
die(cause)

mob/verb
punch(mob/M)
M.heal(-1, src)
kick(mob/M)
M.heal(-1, src)

Most people seem to be doing it the bad way. Not only does doing it the good way make your own life easier, but later on when you are making your game even cooler, and you have an updateHealthMeter() function, you don't have to change your code in 100 different places! If you do it the bad way, you have to go back to every single place that you change health and put updateHealthMeter() after it. The good way, you go to heal() and insert the line in one place right there.

Same for experience, with the only difference being that gainExp() might end up calling levelUp() instead of die(), oh, and obviously the bounds checking is slightly different than the min(max()) for health.

It is always a good idea to set things up correctly the first time.

That said, setHP(getHP()+5) is not necessary. You don't need a literal getter and setter for every value. Figure out what types of actions values are likely to have, and give them appropriate functions. For example, you are not likely to ever use a setExp() function, so setExp(getExp()+10) is stupid. Instead, just make a gainExp().

One of the reasons for getters and setters in other languages is that they can help to make code safe. In Byond, we don't have any of the same notions of privacy that other languages have. For example, we cannot make variables private or protected, they are all always public.

As long as the application is single-threaded, which your Byond games are, it is never dangerous to read a value, it can only be possibly hazardous to write to a value. So getValue() especially is not necessary in Byond. setValue() functions are useful though, as pointed out above.