Page 1 of 1

[Tutorial/trick] "Encapsulating" so-called private methods/p

Posted: 01 May 2015, 11:25
by Coco
Firstly, this demo is merely subjective and can be considered as more of a convention rather than the "best"/"only" solution with regards to achieving the goal.

Normally, when writing classes, especially ones that are meant to be used as lib, there are cases that you would need to define so-called "private" methods which act as helper subroutines for some of the public methods exposed by the API. Commonly, to imply that these method(s) are for internal use only, the dev would usually use naming conventions(underscore prefix, etc.), "warning" comments and omit the usage of these methods from the documentation. These usually are enough but just for fun, I will be demonstrating a way to define so-called "private" methods and/or properties in a manner that it would be easy for the dev to maintain/organize the code and most importantly encapsulate the subroutines from the caller(be it a person or object(instance/class)). You may have noticed in the documentation under function objects(not to be confused with Func objects) -- (I can't provide a link, it seems that the online doc is temporarily unavailable), a way to define custom callable objects. This method has always been available prior v1.1.20, however, with the introduction of Func.Call(), we can say that there is now a more standardized way of defining custom "function objects". The trick is to convert the "public" methods which use/call the "private" methods into nested classes, implement these nested classes as callable objects by putting its routine in the .Call() method and then define the "private" helper methods as methods of these nested callable classes. But before you do this you would first need to define a base object from which all your "callable" objects will derive from. The base object should be defined as follows(similar to the one in the AHK documentation):

Code: Select all

class Callable
{
	__Call(method, args*)
	{
		if IsObject(method) || (method == "") ; object when used as method and "" when invoked via %obj%(args*)
			return method ? this.Call(method, args*) : this.Call(args*)
	}
}
You can put this as a nested class of your class if you plan to use it for the that class only.

Now that we have the base object, we can define our "public" and "private" method as follows:

Code: Select all

class Foo
{
	class Public extends Foo.Callable
	{
		; instance.Public(args*) invokes .Call()
		Call(self, args*) ; instance is passed as second argument(self), 'this' is actually Foo.Public class
		{
			; main routine of Foo.Public() goes here
			
			this.Private(self, args*) ; call a private subroutine, pass instance('self') if needed/required
		}

		Private(self, args*) ; private method callable only from within Foo.Public()
		{
			; you may omit 'self' if you don't need the reference
		}
	}

	class Callable ; base object for all callable objects
	{
		__Call(method, args*)
		{
			if IsObject(method) || (method == "")
				return method ? this.Call(method, args*) : this.Call(args*)
		}
	}
}
Notes:
  • If multiple "public" methods need to call the same "private" method, you can have them extend from the nested class which contains the "private" method.
  • If you plan to use this for __New make sure that .Call() returns self.
Pros of using this approach:
  • Code is easy to read, maintain and document as you can see which helper subroutine(s) a particular method uses.
  • Class instance(s) have no direct way of calling the "private" methods avoiding possible invalid calls that may compromise the script
In normal cases, there is no need to use this convention, however, it comes really handy with large and complex classes.

Re: [Tutorial/trick] "Encapsulating" so-called private methods/p

Posted: 31 Dec 2016, 06:58
by iPhilip
Hi Coco,

I would be interested in seeing an example of this "encapsulation" approach, including its use for the __New method.

Thank you.