Class Property Instance Variable

Propose new features and changes
RFM
Posts: 28
Joined: 21 May 2016, 12:50

Class Property Instance Variable

15 Feb 2017, 00:31

Hello,

I've been a software engineer for decades, done a lot of OOP programming. I've done a lot of programming with AutoHotKey as well, very useful tool. I decided to take a look at AutoHotKey's implementation of OOP. Though much is standard, one thing I found was very disappointing. Maybe I'm missing something, but I could not find the answer.

Static variables of a class and instance variables of an instance of a class should never be directly accessible from outside the class or instance thereof. They should only be accessible from within a method or property. Only methods and properties should be accessible from outside the class or instance thereof. That's the great thing about classes, they allow its author to protect the internal static and instance variables from external manipulation.

A property allows the class author to limit the values the user of the class can assign to a class static or instance variable. But, if the user of the class can bypass the property and method protections given it by its author, properties become useless. Methods are useless as well. By useless, I mean in guarding the integrity of the values of the static and instance variables.

Now, perhaps I've missed something, and there is a way to declare variables within a class that cannot be directly accessed from outside the class but accessible by its properties and methods, but I have not found it. Here is an example that demonstrates what I mean:

Code: Select all

class _C
{
	static G := {}
	;The following only have values when an instance of the class is instantiated:
	Var1 := "Non-static variable Var1"
	Var2 := "Non-static variable Var2"
	Var3 := "Instance Var3 used by property"
	
	Set(name, value)
	{
		return This.G[name] := value
	}
	
	Get(name)
	{
		return This.G[name]
	}
	
	Delete(name)
	{
		if G.Haskey(name)
			G.delete(name)
		return
	}
	
	SetVar1(value)
	{
		This.Var1 := value
		return
	}
	GetVar1()
	{
		return This.Var1
	}
	
	Var3Property
	{
		get
		{
			return This.Var3
		}
		set
		{
			This.Var3 := value
		}
	}
}

	C1 := new _C
	C2 := new _C
	_Cset := _C.Set("Hi", "Hello there!")
	_Cget := _C.Get("Hi")
	_Cdir := _C.G[name]
	C1.SetVar1("Value for Var1 of C1")
	C1.Var2 := "Value for Var2 of C1" ; Direct access (Bad!)!
	C2.SetVar1("Class C2 value for Var1")
	C2.Var2 := "Class C2 value for Var2" ; Direct access (Bad!)!
	C1.Var3Property := "Property Var3 of class 1"
	C2.Var3 := "C2 class property instance variable Var3" ; Direct access (Bad!)!
	
	c =
	(
C1 := new _C
C2 := new _C
_Cset := _C.Set("Hi", "Hello there!")
_Cget := _C.Get("Hi")
_Cdir := _C.G["Hi"]
C1.SetVar1("Value for Var1 of C1")
C1.Var2 := "Value for Var2 of C1" ; Direct access (Bad!)!
C2.SetVar1("Class C2 value for Var1")
C2.Var2 := "Class C2 value for Var2" ; Direct access (Bad!)!
C1.Var3Property := "Property Var3 of class 1"
C2.Var3 := "C2 class property instance variable Var3" ; Direct access (Bad!)!
	)
	
	m := "Code: `n" . c . "`n`nResults:"
		 . "`nClass _C:"
	   . "`n`t_C.Get(""Hi""): """ . _C.Get("Hi") . """"
		 . "`n`t_C.G[""Hi""]: """ . _C.G["Hi"] . """ Can be accessed directly (Bad)!"
		 . "`n`t_C.GetVar1(): """ . _C.GetVar1() . """"
		 . "`n`t_C.Var2: """ . _C.Var2 . """"
		 . "`n`t_C.Var3Property: """ . _C.Var3Property . """"
		 . "`n`t_C.Var3: """ . _C.Var3 . """"
		 . "`n"
		 . "`nInstance C1:"
	   . "`n`tC1.Get(""Hi""): """ . C1.Get("Hi") . """"
		 . "`n`tC1.G[""Hi""]: """ . C1.G["Hi"] . """ Can be accessed directly (Bad)!"
		 . "`n`tC1.GetVar1(): """ . C1.GetVar1() . """"
		 . "`n`tC1.Var2: """ . C1.Var2 . """Direct access (Bad)!"
		 . "`n`tC1.Var3Property: """ . C1.Var3Property . """"
		 . "`n`tC1.Var3: """ . C1.Var3 . """Direct access (Bad)!"
		 . "`n"
		 . "`nInstance C2:"
	   . "`n`tC2.Get(""Hi""): """ . C2.Get("Hi") . """"
		 . "`n`tC2.G[""Hi""]: """ . C2.G["Hi"] . """ Can be accessed directly (Bad)!"
		 . "`n`tC2.GetVar1(): """ . C2.GetVar1() . """"
		 . "`n`tC2.Var2: """ . C2.Var2 . """Direct access (Bad)!"
		 . "`n`tC2.Var3Property: """ . C2.Var3Property . """"
		 . "`n`tC2.Var3: """ . C2.Var3 . """Direct access (Bad)!"
	
	MsgBox %m%

guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Class Property Instance Variable

15 Feb 2017, 01:49

RFM wrote:That's the great thing about classes, they allow its author to protect the internal static and instance variables from external manipulation.
please tell me why thats a 'great thing'. all you've shown is that to set a value, you have to jump through the overhead of a setter method instead of just assigning directly

RFM
Posts: 28
Joined: 21 May 2016, 12:50

Re: Class Property Instance Variable

15 Feb 2017, 04:02

It appears that you have not done much, if any, work with mature object oriented languages. The greatest advantage of a class is encapsulation. Have a look: https://en.wikipedia.org/wiki/Encapsula ... ogramming)

Encapsulation ensures that no outside code can set values that are unacceptable to your class. Every value set inside your object gets inspected by your code to ensure is integrity and acceptability. Encapsulation prevents a lot of support time dealing with those that have not clearly read the instructions and/or abide by those instructions, or simply made a mistake, and assigned values in your object that your object was not meant to handle. When forced to use a method or property to set a value, that method or property can inspect the incoming value to ensure it is within the specified limits, and if not, throws a meaningful error message, thereby, greatly reducing support calls. If you have not encountered situations where the values of variables must be within certain ranges or limited to certain values, then you have not done much sophisticated or technical programming, such as engineering in all fields.

Take for example that your class works on different measuring systems and therefore has a variable that contains a conversion factor between the two measuring systems, and the value is different depending on which is the base measuring system and the one being converted to. So, you have three variables, one that indicates the base measuring system, one that indicates the target measuring system, and one for the conversion factor. Of course, your class, when instantiated as an object, reads from wherever you store user preferences those chosen measuring systems, and if no user preferences found, defaults to whatever measuring systems you choose. Three variables are instantiated in your object, the base measuring system, the target measuring system, and the conversion factor. You have two properties that allow the user of your object to change either the base or target measuring system. When either of those properties are called with a value, that value is verified to be the value that represent a valid measuring system. Then that property looks at the other measuring system and chooses the correct conversion factor. If the user of your object attempts to pass in a value that does not represent a valid measuring system, your object throws and error message clearly explaining the problem and possible solutions. This alone, greatly reduces support calls from those using your class and either deliberately or accidentally passing to your property an invalid value. However, if the user of your object can directly change the conversion factor, the results will be incorrect, and your support calls will increase. There are always those that will test the limits of your code and there are always mistakes. It is much better to have your object handle the error at the time it occurs, than for you to get a lot of support calls.

Another example is, suppose you have a car object. That object only allows for a certain number of doors, wheels, whether front or rear wheel drive, whether automatic or manual transmission, just to name a few of the many properties an automobile has. Have you ever used Kelly's Blue Book online? If not, give it a try. When you enter a make, it present you with models, when you enter a model, it presents you with whatever valid options there are for that year, make, and model. Now, if your object looked up data in a database and filled in variables with the appropriate data entered through the properties, you have tight control over what those values will be, and will only contain appropriate values. But, if you allow someone to use your object, and they are able to directly change the values of variables, for example, suppose they change the year to a value in which a particular make wasn't made or was before a make and model had four door capability. Or the user of your object directly changes the variable holding the number of doors to 5, when that year, make, model can only have 2 or 4 doors. Had they used a property or method to assign the year or number of doors, your object would have thrown an error with explanation that that year is invalid or that car cannot have 5 doors. But, because the user of your object bypassed the integrity properties and methods, and directly assigned the variables, the results are not going to be correct. And you will get support calls. Calls that could have been prevented had they used properties and methods to make the proper assignments.

The are many examples, suppose you need a diamond object that has a property for carats. There are only certain values that are acceptable, a property or method would ensure an acceptable value is entered. I could go on and on. Properties and methods make the job of error prevention much much easier and much much easier to debug and most importantly, reduces support calls by a large factor.

I hope this helps.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Class Property Instance Variable

15 Feb 2017, 06:41

RFM wrote:It appears that you have not done much, if any, work with mature object oriented languages.
That is some next level deduction :crazy:
RFM wrote: The greatest advantage of a class is encapsulation. Have a look: https://en.wikipedia.org/wiki/Encapsula ... ogramming)
That is funny,
Wikipedia wrote: In programming languages, encapsulation is used to refer to one of two related but distinct notions, and sometimes to the combination[1][2] thereof:
  • A language mechanism for restricting direct access to some of the object's components.[3][4]
  • A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.[5][6]
I guess AHK-classes is number two :thumbup:
RFM wrote: When forced to use a method or property to set a value, that method or property can inspect the incoming value to ensure it is within the specified limits, and if not, throws a meaningful error message, thereby, greatly reducing support calls.
Keyword: forced, in AHK, you are not forced, that is a good (convenient) thing in some situations, and not so good in others. If you have not realised that there are advantages and disadvantages in all programming languages, you probably havn't worked with many different languages.
RFM wrote: The are many examples, suppose you need a diamond object that has a property for carats.
You can protect incompetent users from themselves to some extent, by using set get.

Code: Select all

d:= new diamond(2,1)
d.carats:=5				; Set a new value
MsgBox, % d.carats		; Show it, 5
d.carats:=-5			; Value not accepted, you are told
MsgBox, % d.carats		; The old value is kept	
d.cost()				; The cost calculated
d.c:=""					; Being stupid
d.cost()				; You get an error.
class diamond{
	__new(weight, carats){
		this.weight:=weight
		this.carats:=carats
	}
	carats{
		set{
			if (value<=0){
				MsgBox, % "Carats need be postivie"
				return
			}else{
				return this.c:=value
			}
		}
		get{
			if !(this.c>0){
				throw "Carats need be postivie"
				return
			}else{
				return this.c
			}
		}
	}
	cost(){
		try
			MsgBox, % "Cost: " this.weight*this.carats
		catch e
			MsgBox, % "Cost not calculated, reason: " e
		
	}
}

Finally, I'm not against things such as optionally declaring variable/methods as private. Also, it would be great if one could assume local, for both functions, methods and classes, eg

Code: Select all

global ctr:=1
b:= new a
b.method()
msgbox, % ctr ; should show 1
class a{
	local
	method(){
		ctr:=37
	}
}
; or
f(){
	local
	ctr:=37
}
Maybe that is planned for v2?

Good luck, Cheers!

Edit: I saw you did some set get in your first post, sorry.
Edit 2: English :oops:
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Class Property Instance Variable

15 Feb 2017, 10:32

RFM wrote:It appears that you have not done much, if any, work with mature object oriented languages.
...
I hope this helps.
lol. so basically you want to prevent stupid people from doing stupid things. this is only useful if you are sharing your class with others, since presumably you would be smart enough to use your own class properly. for sharing, just document the API you want your users to use

AHK doesn't use class-based OOP, it uses prototype-based. you don't "instantiate" classes in AHK. each 'class' is already an instance of the object in itself (as you should know by your references to the "_C" object directly in your original post). using the new keyword doesn't "instantiate" anything, it rather creates a new object with the base/prototype/'parent' being the existing class object instance. the AHK terminology of 'class' and related docs was chosen to assist users like you coming from other OOP types, but i think it makes it more confusing, not less. thats jmho. you might think that only "class"es can have instances, but you'd be wrong about that too. you can also create "instances" of "an instance of a class"

prototype-based OOP also allows you to modify the objects directly at runtime. meaning you can add/remove variables and methods at will. you would call this sloppy, others would call this powerful. then we might as well just debate strict vs loose typing as well. most people who share scripts with classes don't use the base class instance either, and instruct users to create new 'instances'. thats fine, but you could also say thats a sloppy misuse of memory

as far as i know, JavaScript, the most popular programming language in the world, also uses this same type of OOP.

finally, there's these tricks:
https://autohotkey.com/boards/viewtopic ... 631#p42631
https://autohotkey.com/boards/viewtopic.php?t=7072

RFM
Posts: 28
Joined: 21 May 2016, 12:50

Re: Class Property Instance Variable

15 Feb 2017, 14:41

guest3456 wrote:so basically you want to prevent stupid people from doing stupid things.
There are those, but there are also mistakes made that a truly encapsulated class will catch.

guest3456 wrote:just document the API you want your users to use
Have you even thoroughly read all the documentation for "AutoHotKey"? And, even if you had, do you still make mistakes? In other words, do you ever have to go back and modify your code? (These are all rhetorical questions)

guest3456 wrote:you don't "instantiate" classes in AHK.
Funny thing, as "New" is used to instantiate a class as an object. That is why it is called an "instance". Lets take a look at the example you referred to:
Here we see:
HotKeyIt wrote: Instance := New BaseClass()
He used "New" to instantiate and "Instance" of "BaseClass()"

guest3456 wrote:each 'class' is already an instance of the object in itself (as you should know by your references to the "_C" object directly in your original post
That is how it is supposed to work, except you should not be able to access static variables directly. The class holds the instance of all properties that are the same to all instances "instantiated" from it. The class is, in AutoHotKey terms, the "SuperGlobal". As is clearly shown in my example program, none static variables, which are instance variables, cannot be accessed from the _C class itself. So, unless I'm mistaken, that proves that the capability to hide variables in a class is possible.

guest3456 wrote:as far as i know, JavaScript, the most popular programming language in the world, also uses this same type of OOP.
This is a rather Naive statement. Since it is the only language recognized and run by all browsers and therefore everyone that programs for the internet must us it, it is by default the most popular language. You have no other choice. Not until all popular browsers support a different language that is superior to JavaScript will it lose its popularity.

Not only that, you don't use JavaScript to do any non-browser non-internet based sophisticated programming. Though attempts are being made for web based versions, they are far less robust and much slower, for programs that do things that AutoCad, PhotoShop, and a host of other sophisticated programs do.

Those only semi-protect one variable. You have to do the same thing for every single variable, what a hassle. And, they do not work anyway. Without modifying either class nor its "instantiation", I easily show how you can reach into the class and make it so that you can change variables that were supposedly protected:

Code: Select all

Class ReadOnlyClass {
	__GET(key){
		return this[""][key]
	}
	__SET(p*){
		MsgBox % "The Class is ReadOnly so Key " p.1 " must not be changed`, Program will exit now!"
		ExitApp ; replase with return if program should not exit
	}
}
Class BaseClass {
   static A := {(""):[False, False, False], base:ReadOnlyClass}
}
Instance := New BaseClass()
MsgBox % "Before: " . Instance.A.1 ; RFM added!
Instance.A := {(""):[False, False, False], base:"ReadOnlyClass"} ; RFM added!
Instance.A.1 := true
MsgBox % "After: " . Instance.A.1
If you cannot protect "A", you certainly cannot protect "A.1".


As far as the second example goes, posted almost 2 years ago with none making any comments regarding it, he doesn't even "New" (instantiate) an object. It does nothing useful. I have yet to see any implementation of a class and it's instantiated objects that are able to protect variables. Only attempts that prove the futility of it all.
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Class Property Instance Variable

15 Feb 2017, 15:11

RFM wrote: ...hard headed stubbornness...
ok. wasted my time writing that last post. you've made ridiculous and outright false statements, but you clearly have no desire to learn anything new. you just want to condescend. feel free.
RFM wrote: I have yet to see any implementation of a class and it's instantiated objects that are able to protect variables.
because its not possible in AHK. thats why i offered you some 'tricks' to help you and your users not make your dreaded 'mistakes' that you're oh so worried about. perhaps you should go back to Java. i'm sure you hate the fact that everything in AHK is a string

just me
Posts: 9458
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class Property Instance Variable

15 Feb 2017, 16:48

guest3456 wrote:... because its not possible in AHK.
That's why this topic has been put into "Wish List". :roll:
RFM
Posts: 28
Joined: 21 May 2016, 12:50

Re: Class Property Instance Variable

15 Feb 2017, 18:55

guest3456 wrote:
RFM wrote: ...hard headed stubbornness...
Nowhere have I made the statement you quote me as having said. That is extremely dishonest. Making claims someone said something they did not say is extremely immature and is being an outright liar. Because you have revealed yourself to be such a person, I'll be making no more replies to your comments.

guest3456 wrote:you clearly have no desire to learn anything new.
You have not shown me anything I have not already been aware of.

guest3456 wrote:thats why i offered you some 'tricks' to help you and your users not make your dreaded 'mistakes' that you're oh so worried about.
You offered no tricks at all, you only referred to those that attempted, but failed, to do what I was looking for. And I proved it with the code I provided. I'm not worried about anything in regards to AHK.

guest3456 wrote:perhaps you should go back to Java.
Though I've programmed in more languages than most likely the number of years you are old, "Java" is one language I've never programmed in. One who presumes to know is one who will never make a very good programmer.

guest3456 wrote:i'm sure you hate the fact that everything in AHK is a string
Not one bit, every language stores its content in one form or another. Though most of the languages have standardized. However, your statement is not entirely true. Though strings seem to be how it saves the data in memory, that is not how you have to store them in a file. Look that these AHK Commands: RawWrite, RawRead, WriteNum, ReadNum


Again, I'll be making no more replies to you.
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Class Property Instance Variable

15 Feb 2017, 19:46

sounds good.

4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: Class Property Instance Variable

15 Feb 2017, 20:27

RFM wrote:Now, perhaps I've missed something, and there is a way to declare variables within a class that cannot be directly accessed from outside the class but accessible by its properties and methods
There is no private or protected attributes in AHK if that's what you were looking for.

I even tried to filter the callers with __Call and __Set with no success ( but its not like I spent days on that so there might be a way after all )
RFM
Posts: 28
Joined: 21 May 2016, 12:50

Re: Class Property Instance Variable

15 Feb 2017, 22:41

4GForce wrote:There is no private or protected attributes in AHK if that's what you were looking for.
I'm aware of that, that is why my post is in the "Wish List". The way I see it, all instance variables in a class should automatically be private. One should have to declare them as protected so that they are accessible to those classes the are derived from said class. Instance variable should never be public. Methods and Properties should automatically be protected and have to be declared public to be accessible outside said class or private so that even classes derived from said class cannot see them. Static variables are accessible to the class itself without said class needing to be instantiated, but of course are accessible when instantiated as well. They are also protected so that only classes derived from said class can access them. A Static variable cannot be declared public or private. That's my view of things at this time.

General (not cast in stone) definitions:
Static: Variable declared as static.
Instance: Variable not declared static.
Property: A method with no parameters with getter and setter(value) functions. If you want parameters, us a method.
Method: A function that is a member of a class.
Private: Only accessible to code within defining class.
Protected: Only accessible to code within the defining class and classes derived from (Extends) defining class.
Public: Accessible anywhere.

Code: Select all

Item        Default      Available
---------   ----------   --------------------------
Static      Protected    Protected
Instance    Private      Private, Protected
Property    Protected    Private, Protected, Public
Method      Protected    Private, Protected, Public
lexikos
Posts: 9592
Joined: 30 Sep 2013, 04:07
Contact:

Re: Class Property Instance Variable

16 Feb 2017, 04:39

I think that access controls on class members would be entirely out of place in AutoHotkey, where (for instance) variables don't need to be declared, or even assigned a value, before use. Variables aren't typed, including the this variable (which is nothing more than a parameter/local variable), so the program only knows which member of which class is being accessed at the last moment. Any erroneous references to private members would go unnoticed until they are evaluated, which makes it much less useful than in a statically typed language with a proper IDE.

I don't believe it would be of much value to the majority of AutoHotkey users, but more to the point, I'm not interested in implementing it myself. You're welcome to do so (here's the source code) and see how much interest there is in adopting it.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Class Property Instance Variable

16 Feb 2017, 12:10

The good thing about OOP is the fact that you create modularized Interfaces that you can reuse. The good parts have nothing to do with being able or unable to access the content in a certain way. In fact that is a step to force the user to write OOP. Personally I don't see the point. If you can't differ between a function call and accessing a Variable instead then maybe becoming a developer was the wrong choice of career. However the dynamic way of AutoHotkey allows several new Forms of describing your Interface ( e.g. inter-object-relationships are annoying in OOP and can be solved in a better way in AutoHotkey )
Recommends AHK Studio
RFM
Posts: 28
Joined: 21 May 2016, 12:50

Re: Class Property Instance Variable

16 Feb 2017, 12:19

lexikos wrote:I don't believe it would be of much value to the majority of AutoHotkey users
Probably not, its mostly used to quickly make their tasks of using other programs easier.

lexikos wrote:I'm not interested in implementing it myself. You're welcome to do so ... and see how much interest there is in adopting it.
As there have been attempts already to hide class variables, there are those that would like it. If it was implemented, it will most likely reduce the need to resort to another language to do particular things. I have already written programs in AHK that have nothing to do with making things easier using other programs, they are stand alone programs. A good example of a stand alone program is "AHK Studio", though it does use a third party DLL, but still, an excellent AHK stand alone program.


Thanks for your work already in AHK, it is a very powerful tool. Powerful enough to give other languages competition, and even more so if certain things were implemented.
RFM
Posts: 28
Joined: 21 May 2016, 12:50

Re: Class Property Instance Variable

16 Feb 2017, 12:48

nnnik wrote:The good thing about OOP is the fact that you create modularized Interfaces that you can reuse.
Exactly, and, what seems to be not considered, is that it can be used by others. And, if you cannot control how others use it, they get results they don't like, and that results in them wasting your time by contacting you with their problem with your modularized product.
nnnik wrote:If you can't differ between a function call and accessing a Variable instead then maybe becoming a developer was the wrong choice of career.
You are clearly missing the point. The problem is not the author of the class using his own class. It is others using his class incorrectly that causes a waste of his time supporting his product. An encapsulated class where the author has full control of what is allowed in and can post appropriate error messages when values passed into the class are not appropriate, reduces greatly the support time.

Again, this has nothing to do with the author of the class using his own class, it is the support time savings he will gain when his class is used by others. This is the whole point of class encapsulation, it forces others to use it correctly and not be able to cause it to malfunction, which is easy to do with AHK classes. In an example I gave above, regarding a conversion factor, if the user of the class can do class.ConversionFactorVariable := <SomeInappropriateConversionFactor>, your class will produce incorrect results and he will contact you, especially if he is an inexperienced programmer. However, if he cannot directly reach that variable, but must set it via a Method or Property, that Method or Property can check the validity of that conversion factor and if inappropriate, can post an error message explaining the problem and possible solutions. This can be built into the class, and the class can take care of supporting itself.

It is, as you say, the "modularized Interfaces that you can reuse", and more importantly, reused by others, that makes class encapsulation important.

nnnik wrote:Personally I don't see the point.
Hopefully, perhaps now you can see the point.
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Class Property Instance Variable

16 Feb 2017, 12:59

And what's wrong with Helgef's example using ahk class properties? Why did you ignore his posted solution? The only downside is that if one of your users tries to modify his .c variable, but that variable isn't exposed anywhere within the constructor and is completely non descript. If your users are tinkering around and looking up variables INSIDE your class, then such a user clearly doesn't care about just blindly using your excapsulated class: they are interested in doing deeper stuff as is

It would be beneficial for you to provide some real-world "support requests" as you are claiming will happen. I'm not saying its not possible. But perhaps there are other ways around it (including the aforementioned better documentation of your wares)

User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Class Property Instance Variable

16 Feb 2017, 18:06

guest3456 wrote:And what's wrong with Helgef's example using ahk class properties? Why did you ignore his posted solution? The only downside is that if one of your users tries to modify his .c variable, but that variable isn't exposed anywhere within the constructor and is completely non descript. If your users are tinkering around and looking up variables INSIDE your class, then such a user clearly doesn't care about just blindly using your excapsulated class: they are interested in doing deeper stuff as is

It would be beneficial for you to provide some real-world "support requests" as you are claiming will happen. I'm not saying its not possible. But perhaps there are other ways around it (including the aforementioned better documentation of your wares)
Helgefs solution doesn't work with OOP.
RFM wrote:
nnnik wrote:If you can't differ between a function call and accessing a Variable instead then maybe becoming a developer was the wrong choice of career.
You are clearly missing the point. The problem is not the author of the class using his own class. It is others using his class incorrectly that causes a waste of his time supporting his product. An encapsulated class where the author has full control of what is allowed in and can post appropriate error messages when values passed into the class are not appropriate, reduces greatly the support time.

Again, this has nothing to do with the author of the class using his own class, it is the support time savings he will gain when his class is used by others. This is the whole point of class encapsulation, it forces others to use it correctly and not be able to cause it to malfunction, which is easy to do with AHK classes. In an example I gave above, regarding a conversion factor, if the user of the class can do class.ConversionFactorVariable := <SomeInappropriateConversionFactor>, your class will produce incorrect results and he will contact you, especially if he is an inexperienced programmer. However, if he cannot directly reach that variable, but must set it via a Method or Property, that Method or Property can check the validity of that conversion factor and if inappropriate, can post an error message explaining the problem and possible solutions. This can be built into the class, and the class can take care of supporting itself.

It is, as you say, the "modularized Interfaces that you can reuse", and more importantly, reused by others, that makes class encapsulation important.
That's one of the arguments I never understood.
If you want to use a OOP library from another person you need to understand OOP. If you understand OOP why would you try to access any member directly?

Anyways back to topic. I think it's not completely impossible to create a piece of code within AutoHotkey that can emulate the kind of behavior that you are searching for.
Currently AutoHotkeys Objects/Classes etc. directly expose their contents. ( may it be functions, numbers strings etc... )
OOP Objects ( at least the one you described ) protects parts of itself and only exposes some parts of itself towards the outside.
I think it could be possible to recreate OOP behavior in AutoHotkey by using a indirect/hidden reference from a interface object towards a containing hidden backend.

However rewriting code for that would be a hassle to do every time you want to create a class.
Recommends AHK Studio
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Class Property Instance Variable

16 Feb 2017, 19:17

RFM wrote:As there have been attempts already to hide class variables, there are those that would like it.
This is the sort of things I like to try to solve, I don't really want to use this myself, this is my initial attempt, basically, it lets you make a class where the user cannot set and get or call whatever method it wants. It's a quick write-up I'm sure I made some mistakes.
Consider this, first make your class

Code: Select all

class protectedClass{
	arrayA:=[1,2,3] 
	varA:="A"
	varB:="B"
	
	__new(C){
		
		this.varC:=C 	
		this.varD:="D" 	
	}
				
	setVarC(newC:=""){
		if (newC!="" && newC<0)
			MsgBox, % "C cannot be negative"
		else
			this.varC:=newC
		return
	}
	
	getVarA(){
		return this.varA
	}
	
	getArrayA(){
		return this.arrayA	; This is not safe
	}
	
	conc(comment:=""){
		msgbox, % comment ": " this.varA . this.varB . this.varC
		return 
	}
}

then you make a function, where you have one instance of the class as a static variable, then delete the class. Now the user cannot access the class MyProtected. The user never gets a real reference, just a number to the index of a static array, where the references are kept. The function controls what you can call and not, and calls it for you if appropriate.

Code: Select all

p(n:="",op:="",var*){
	static f:= new protectedClass
	static delete:=(protectedClass:="")
	static instances:=[]
	if (op="new")
		return instances.Push(new f(var*))			; You get back a number, you have no reference to the object. It is stored in the static variable instances.
	else
	{
		if (op="__Set" || op="__Get") ; Any methods you don't want the user to be able to call, put here.
			return
		fn:= ObjBindMethod(instances[n],op,var*)
		return fn.Call()
	}
	return 
}
Then you just need a super simple wrapper class for the user to use, all methods in this class pass the number and which function to call and parameters for that function.

Code: Select all

class myUI{
	__new(c:=""){
		this.n:=p(0,"new",c)
	}
	
	setVarC(val){
		p(this.n,"setVarC",val)			
	}
	
	getArrayA(){
		return p(this.n,"getArrayA")			
	}
	
	getVarA(){
		return p(this.n,"getVarA")			
	}
	
	conc(v:=""){
		p(this.n,"conc",v)
	}
}
So, you give your users the user interface myUI, and include the rest.
The whole script with some test code, to run

Code: Select all

MsgBox, % IsObject(protectedClass)
myp:= new myUI("Q")
myp.conc("Hello")
myp.setVarC(-1)
myp.conc("Hello B")
myp.setVarC(37)
myp.conc("Hello C")
MsgBox, % myp.getVarA()
a:=myp.getArrayA()	; If you return an array, the user can change it and it will be changed for all instances, like a static variable of sorts.
a[1]:=37
msgbox, % a[1] " " a[2] " " a[3] 
myp2:=new myUI("number 2")
b:=myp.getArrayA()
msgbox, % "b: " b[1]


p(n:="",op:="",var*){
	static f:= new protectedClass
	static delete:=(protectedClass:="")
	static instances:=[]
	if (op="new")
		return instances.Push(new f(var*))			; You get back a number, you have no reference to the object. It is stored in the static variable instances.
	else
	{
		if (op="__Set" || op="__Get") ; Any methods you don't want the user to be able to call, put here.
			return
		fn:= ObjBindMethod(instances[n],op,var*)
		return fn.Call()
	}
	return 
}

class myUI{
	__new(c:=""){
		this.n:=p(0,"new",c)
	}
	
	setVarC(val){
		p(this.n,"setVarC",val)			
	}
	
	getArrayA(){
		return p(this.n,"getArrayA")			
	}
	
	getVarA(){
		return p(this.n,"getVarA")			
	}
	
	conc(v:=""){
		p(this.n,"conc",v)
	}
}

class protectedClass{
	arrayA:=[1,2,3]
	varA:="A"
	varB:="B"
	
	__new(C){
		
		this.varC:=C 	
		this.varD:="D" 	
	}
				
	setVarC(newC:=""){
		if (newC!="" && newC<0)
			MsgBox, % "C cannot be negative"
		else
			this.varC:=newC
		return
	}
	
	getVarA(){
		return this.varA
	}
	
	getArrayA(){
		return this.arrayA	; This is not safe
	}
	
	conc(comment:=""){
		msgbox, % comment ": " this.varA . this.varB . this.varC
		return 
	}
}

I would never use this (method) :lol:
I think set{}get{} is good enough, it should be able to handle most user mistakes.

Note: You cannot really use static in your class, instead use an Object where all instances has a reference. (I think)

Good luck.

Edit
nnnik wrote:Helgefs solution doesn't work with OOP.
What does that mean? (I do not mean the abbreviation)

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 53 guests