ID:133535
 
While it might have been mentioned before in topics such as the public variable (though is very different), I thought I would try bringing it up again if it wasn't mentioned before about private.

I know it's nice to be able to modify any object as long you have a reference to them, but why not also a way to make certain variables private? That way, they're only modified if you call their procedures and prevents unwanted outer modification. Could work out like this:

mob
var
a = 1 // this variable is considered public
b = 2
private // private modifier
c = 3 // this variable cannot be modified unless one of it's procedures were called.


Reason why I would like to see such a feature is to make sure unnecessary modification doesn't occur unless you modify it through inside of the any of the owner's procedures.

Do ya show support for this idea?
It seems to me that if you don't want an outside proc to modify a variable, just don't program it that way. I honestly don't understand how this would be a good thing. It seems to me that it would likely cause people to accidentally leave a variable in the private zone, causing problems on down the line. Perhaps you can give us an example as to how this would be used in a way that is helpful to a programmer.
In response to Danial.Beta
Here's one of the possible library code I'm working on:

/*

DyMem C++ DM

*/


DyMemVar
var
memaddr = null
private // this is what I'm talking about
size = 0
New(n)
n = round(n)
if(isnull(n))
n = 1
else if(!isnum(n))
CRASH("Attempt to use strings.")
if(n > 0xFFFF)
CRASH("Attempt to go over 65,535 bytes.")
else if(n < 0x0001)
CRASH("Attempt to go below 1 byte.")
size = n


This library is supposed to allow the use of dynamic memory through C++ (using DLL or SO files). While I haven't completed the library yet (just started last night), the comment I put in there is temporary to point out the possible use for a private modifier.
In response to Danial.Beta
Danial.Beta wrote:
Perhaps you can give us an example as to how this would be used in a way that is helpful to a programmer.

If a class is only designed to have a variable of the values -1, 0, or 1, for example, you could give it a SetVarValue(x) proc that checks the value of x to make sure it fits the proper domain before assigning it. This way you (or someone else if it happens to be a library) don't accidentally modify its value to -2.

Sure, you could check in every proc that uses that value if it's ok, but compare:
someClass
var/private/someVar = 0

proc
SetVar(x) // Makes sure x is -1, 0, or 1
if(x==1 || x==-1)
someVar = x
else someVar = 0

// Procs can assume someVar integrity:

UseVar()
var/blah = someVar

UseVar2()
var/blah = someVar

UseVar3()
var/blah = someVar


someClass2
var/someVar = 0

proc
UseVar()
var/blah = (someVar==1||someVar==-1 ? someVar : 0)

UseVar2()
var/blah = (someVar==1||someVar==-1 ? someVar : 0)

UseVar3()
var/blah = (someVar==1||someVar==-1 ? someVar : 0)
In response to Danial.Beta
I can see it being useful in a "don't screw up your own code" sort of way. One of those Dream Maker articles that I don't remember who wrote mentioned not modifying an object's variables outside of an object's proc as a way to keep your code organized. I've been trying to put that into practice, and being able to restrict access to certain variables would b a good way to make that easier.
In response to Foomer
Indeed. In object oriented programming, these 'private' variables are accessed and modified using accesors and mutator methods. This practice essentially makes it almost impossible for the programmer to screw something up internally if done correctly.

A DM practice I've seen some libraries use was to name private variables that were not meant to be externally modified or read with an underscore before it (ie. var/_doNotTouchMe).

On the other hand, if something like this ever gets implemented, I'd like to see a protected keyword as well.
Bandock wrote:
While it might have been mentioned before in topics such as the public variable (though is very different), I thought I would try bringing it up again if it wasn't mentioned before about private.

I know it's nice to be able to modify any object as long you have a reference to them, but why not also a way to make certain variables private? That way, they're only modified if you call their procedures and prevents unwanted outer modification.

The problem with that is, the language isn't at all built for this and we'd be talking about a fairly major modification. While I've been getting a lot more familiar with the compiler, I ain't Dan, and I think this is a change even he would be loath to make.

The case could also be made that this kind of change would be pushing BYOND in the wrong direction, making the language more like the overly technical gobbledygook that one has to deal with in C++ and Java than the simplicity of, say, Python. And in compiled languages, accessors can be compiled as inline functions by an optimizing compiler, whereas BYOND does absolutely no optimization in the compilation phase. In C++, GetVar() and SetVar() are merely short bursts of assembly code with no function call actually involved (except in the case of virtual functions), but the same would not be true in BYOND--in other words, you're looking at a performance hit for the sake of making code marginally more structured.

All that said, this might be doable, but there are various problems with it that would need to be researched and may turn out to be intractable. For instance, if you can only modify a private var when src is the object being changed, what happens if src is altered? Right now src can be changed just like any other var.

It just seems to me the benefit/work ratio is pretty close to zero since the usefulness of private members is questionable in the first place, and in BYOND it would represent a guaranteed loss of performance.

Lummox JR
In response to Bandock
Your code is incorrect, since you're not allowing n to be 0 even though 0 would fit in one or two bytes. There's also a question as to how you'd handle negative values.

Lummox JR
In response to Lummox JR
Off-Topic Reply:

Whoops, thanks for pointing that out. I forgot that the offset system works in the 16-bit range from 0x0000 to 0xFFFF. I'm correcting the maximum value possible for n to 0x10000 (since the minimum of 0x0001 would've turned into 0x0000 and 0x10000 to 0xFFFF for offsets).

I'll correct that in my source code. Microsoft Visual C++ is weird when it comes to arrays though. The maximum size for an array in 32-bit Windows is 0x7FFFFFFF instead of 0x80000000 (which would've converted to 0x7FFFFFFF offset wise). 1 byte reserved?
In response to Bandock
The reason you would want private access to variables is also to prevent the client from accessing data members that should be restricted. If all variables are public then the client has access to modify any variable which could lead to cheating. For instance the client could simply change the mob.health variable to whatever the user wanted.
In response to Bdrx
I believe only the server has access to variables, except for a few such as usr.contents, and then only the server can change them?
In response to Lummox JR
Lummox JR wrote:
It just seems to me the benefit/work ratio is pretty close to zero since the usefulness of private members is questionable in the first place, and in BYOND it would represent a guaranteed loss of performance.

Just my 2 cents and no offense to Bandock (it is a nice encapsulation feature to have - if the compiler was already structed for it):

I think, like Foomer is doing, this is better as a matter of discipline on the part of the programmer. Of course, it doesn't solve the problem of variable hiding when someone uses your library code, but since most libraries in DM give you access to the source that's kinda moot anyway (IMO). For that, I'd probably suggest linkable, compiled libraries (like I think Kuraudo suggested a while back), but that would probably be a similarly sized hassle for JR. Hell, I'm not even sure you could do partial compilation with DM.

The case could also be made that this kind of change would be pushing BYOND in the wrong direction, making the language more like the overly technical gobbledygook that one has to deal with in C++ and Java than the simplicity of, say, Python.

Yea, the so-called safety principle can be a pain and really seems (to me) to create as much overhead as it solves. I did want to point out, tho, that I use DM because it has a sweet spot (in most respects) in that spectrum.

It could be argued that the dynamic typing of DM creates just as much overhead (on my side) in defensive programming than a language that has strict type checking in the analyzer.

All said, I'd rather have youse guys err on the side of C than RPG maker (but you probably knew that).
In response to Bdrx
A client, or generally any object can't automagically access and edit vars (which doing so would of course require access to the only machine actually running and managing the game world, the host; a player wouldn't be able to illegitimately affect anything from his computer directly, since the world and its vars aren't maintained on his computer), vars are generally only accessed if you program some code, or function, to do so.
In response to Kaioken
Kaioken wrote:
A client, or generally any object can't automagically access and edit vars (which doing so would of course require access to the only machine actually running and managing the game world, the host; a player wouldn't be able to illegitimately affect anything from his computer directly, since the world and its vars aren't maintained on his computer), vars are generally only accessed if you program some code, or function, to do so.

I'm actually pretty sure this isn't correct at all. Anything maintained by the client is by definition at least potentially vulnerable to being edited. And the client *has* to have references to things like where it is.
In response to Alathon
Alathon wrote:
(...)And the client *has* to have references to things like where it is.

Whatever happens to a variable on the client should not matter to the server at all if Dan/Tom didn't completely drop security issues and allowed for direct remote access.
In a good, stable and secure client-server architecture the server will certainly tell the client about the variables needed, but won't allow the client to remotely edit these.
In response to Alathon
Alathon wrote:
I'm actually pretty sure this isn't correct at all. Anything maintained by the client is by definition at least potentially vulnerable to being edited. And the client *has* to have references to things like where it is.

But it doesn't maintain those; it's simply sent this information. It doesn't send it back for the server to replace with its own value it maintains, or write to those vars... as Schnitzel implied, such a possibility wouldn't make any sense. Also, vars like the mob.health Bandock mentioned aren't even really sent to the client.
In response to Kaioken
Kaioken wrote:
But it doesn't maintain those; it's simply sent this information. It doesn't send it back for the server to replace with its own value it maintains, or write to those vars... as Schnitzel implied, such a possibility wouldn't make any sense. Also, vars like the mob.health Bandock mentioned aren't even really sent to the client.

But the client still needs to keep track of certain things to do with location and client-side evaluated command expansion. These things have to be potentially exposed? I don't know enough about this to give a definitive answer, but I'd love it if someone who has taken an in-depth look at things has an answer (Slurm, Hobnob, Lummox or Tom?)
In response to Alathon
Alathon wrote:
But the client still needs to keep track of certain things to do with location and client-side evaluated command expansion. These things have to be potentially exposed?

Sure, but I don't see why the client would ever have or need to have an ability to dictate such vars. I'd guess it's just something to the extent of it being sent info about atoms in its view, mob.contents, screen, images, and other stuff it needs to know, but it'd of course be on a read-only kind-of basis.
In response to Alathon
Alathon wrote:
But the client still needs to keep track of certain things to do with location and client-side evaluated command expansion. These things have to be potentially exposed? I don't know enough about this to give a definitive answer, but I'd love it if someone who has taken an in-depth look at things has an answer (Slurm, Hobnob, Lummox or Tom?)

The location and appearance data is exposed to the client and the client can certainly change these values locally, but any changes that they make only appear to that client and do not effect the server side values in any way. No updates to variables come from the client, only player input.

It is however very important that you double check the validity of targets for any action the client initiates. For instance:
obj/item/verb/get()
set src in oview(1) // evaluated client side; could be spoofed

if(!(src in oview(1))) // server verification
return // abort!

if(src.Move(usr)) viewers << "<span class=action>[usr] gets [src]."


Without the server verification, people could modify location values to make the client think they are near an object and pick it up even though it is actually across the map surrounded by laser defense screens.

Even if they aren't cheating, there are situations where a client may think it has access to an item that it should not. For instance, two people near an object try to get it within the same tick. Both clients see it as in view, the first player picks it up. The second client's get command arrives but server-side the item is no longer within oview(1). Without verification, the second client would take the item away from the first player.
In response to Shadowdarke
That's a kind of exotic example. :P A more probable one could be a lagging player holding down an 'attack' (or 'get') macro, and with the 'client current awareness' worsening due to latency and command-queuing, by the time such a command executes on the server the item might no longer be next to the player (as a result of the player moving or something) or the monster isn't (as a result of it moving or being sent to oblivion by a previous 'attack' command).
You're right you'll essentially want to validate anything (especially things like Topic() calls which could be very easily spoofed), but it's definitely somewhat of a headache to do everywhere. Why not have BYOND (or just Dream Maker) do this for you, on your preference? I guess that has been requested before?