-1

In Coldfusion, why do we expose private CFC variables to the world, using setters & getters?

Now, I know this question may sound dumb, because every expert, in this field, advocates such an approach, but I would like to understand why? Surely, if one sets 'variables.name' in a CFC, it should remain private. Looking at this the other way around, why don't we just set 'this.name', and then we don't have the overhead of having to create a setter & getter method. Although, I realise that Coldfusion has improved this issue by providing us with implicit setters & getters, this still doesn't answer the fundamental question.

I keep being told that this breaks the golden rule of encapsulation. But doesn't exposing a private CFC variable via a public method, break this rule, anyway?

Then, other people have told me that it is about controlling access. But how is this controlling access, when public setter & getter methods, are exposed to all & sundry?

Accessing a private CFC variable value via a public method, seems like a lot of hard work to me, especially if you have hundreds of private variables. Why not just access a public CFC variable directly?

Inside user.cfc:

<cfset this.name = "foo" />
<cfset variables.name = this.name />
<cfset var name = this.name />

Outside user.cfc [another CFC or CF template]

<cfset user.name = "foo" />
<cfset variables.name = user.name />

Any help on this issue, would be much appreciated...

Charles Robertson
  • 1,760
  • 16
  • 21
  • 2
    Possible duplicate of [Why use getters and setters?](http://stackoverflow.com/questions/1568091/why-use-getters-and-setters) – Twillen Sep 06 '16 at 13:38
  • I have read this, but I have to say that in the context of Coldfusion, very few of the points within the accepted answer, apply to Coldfusion. I have never seen any extra logic placed inside an explicit getter or setter for tracing/debugging purposes. The only point that I found interesting, was the fact that a getter/setter might be overridden by a sub class, but again I have never seen this done in CF. In fact, I would actually say, that exposing a private variable in this way, breaks OOP. I would rather see a public [this] variable inside a getter, for creating an interception point. – Charles Robertson Sep 06 '16 at 15:01
  • Inside of getter/setter methods, it is entirely possible you will have more than just a simple `return` statement. I frequently have logic in my getters and setters that determine what is set in a setter or what is returned in a getter. – Scott Stroz Sep 06 '16 at 16:16
  • In response to your question 'Why not just access a public CFC variable directly?': Because it breaks encapsulation. – Scott Stroz Sep 06 '16 at 16:17
  • @ScottStroz Thanks for the reply. Could you define encapsulation? I think this is what I need to understand. Because I have head this response many times & even when I read about it, it seems to be more of a philosophical rather than practical paradigm. The bottom line, is that a private CFC variable is exposed publicly. This seems a little illogical, and maybe this theory works better in more traditional OO languages? – Charles Robertson Sep 06 '16 at 17:19
  • 1
    Having public mutators for a private variable in a CFC (or any other kind of programming 'object') is not the same as having a 'public variable'. Here is a pretty good definition of 'encapsulation' https://en.wikipedia.org/wiki/Encapsulation_(computer_programming) – Scott Stroz Sep 06 '16 at 17:33
  • 1
    By its own definition, a 'private' variable in a CFC cannot be exposed publicly - if it was, it would be a 'public' variable. Having mutators (getters/setters) is how we manage that private variable using publicly accessible methods. – Scott Stroz Sep 06 '16 at 17:35
  • @ScottStroz My main issue is not with the getter & setter methods, themselves, because they are good for injection. My issue is with the scope of the variable within. Why not get & set the variables inside each method in the CFC public 'this' scope? – Charles Robertson Sep 06 '16 at 17:35
  • @ScottStroz Thanks for this link. I will have a read. I am wondering why we need to mutate in the first place, when we can just set public CFC variables within... – Charles Robertson Sep 06 '16 at 17:38
  • Then it would not be a 'private' variable - and you would not be able to put any logic in place to potentially limit what gets done when a getter or setter is called for this variable. – Scott Stroz Sep 06 '16 at 17:39
  • 'I am wondering why we need to mutate in the first place, when we can just set public CFC variables within' - because it breaks encapsulation. ;-) I have worked on code where the getters or setters do more than simply return or set a variable. If I used public variables, this would not be possible. – Scott Stroz Sep 06 '16 at 17:41
  • @ScottStroz What I mean Scott, is why do we not create a method that sets a variable in the 'this' scope, and another method that retrieves it. So, keep the methods, which you can use as interception points for further logic, but just use public variables inside them? – Charles Robertson Sep 06 '16 at 17:54
  • @ScottStroz I think I am understanding what you mean. So, by setting the variable in the private scope, access from outside the CFC, can only set the variable via the setter method, which ensures that the variable is only processed within the rules defined by the setter method. If it was set in the 'this' scope, outside access could change the variable without using the setter method, which could lead to disasterous consequences. Thanks for your help Scott:) – Charles Robertson Sep 06 '16 at 18:16
  • 2
    If you did that, then the variables can be changed without using the mutators. I can tell you from a troubleshooting standpoint, this can be a nightmare. – Scott Stroz Sep 06 '16 at 18:17
  • 1
    Yes...exactly..... – Scott Stroz Sep 06 '16 at 18:18
  • 1
    You may also want to read this Q&A [When are getters and setters justified](http://programmers.stackexchange.com/questions/21802/when-are-getters-and-setters-justified). When designing your class, you may not want to directly have a `setName` and `getName` like method for every data point. This is a large topic with a lot of opinions on how to do it correctly. – Twillen Sep 06 '16 at 18:26
  • @ScottStroz It seems to me that these private variables actually become 'protected' variables, once inside the getter & setter. Accessible publicly, but control is maintained by the method. – Charles Robertson Sep 06 '16 at 19:20
  • *these private variables actually become 'protected' variables* Why do you say that? (BTW, are you talking about simple or complex objects? Given that complex objects are typically passed by reference, yes .. unlike they can technically be modified by external methods, unless the getter returns a deep copy). – Leigh Sep 06 '16 at 19:28
  • CF does not "expose" whatever, and getters/setters are not unique to CF. so this question does not make sense. – Henry Sep 06 '16 at 19:42
  • @Leigh I am talking about complex objects. Like getting/setting components... – Charles Robertson Sep 06 '16 at 22:12
  • What did you mean by "..seems to me that these private variables actually become 'protected' variables..."? – Leigh Sep 06 '16 at 22:13
  • @Henry Where did I say getters/setters were unique to CF? But I am trying to get answers that relate to CF setters/getters, because this information would be more useful to me... – Charles Robertson Sep 06 '16 at 22:15
  • @Leigh In a language like objective c, a protected variable [@protected] is available to its class & sub classes. Private variables are not available in sub classes. In CF, private variables are accessible in sub classes. I am thinking, that setters/getters in CF, that are accessed from outside the target component, simulate this behaviour. – Charles Robertson Sep 06 '16 at 23:00
  • 1
    @CharlesRobertson - Gotcha. Yes, I remember finding it a little odd when comparing to java. They are visible to sub-classes, but not other components in the same "package". So I guess they are not *completely* "private" or "protected". IIRC, setters/getters are public by default. – Leigh Sep 07 '16 at 18:29

2 Answers2

2

Thanks for your help Scott.

Rather than talking about encapsulation, I will attempt to answer my own question with a code example:

GOOD:

foo.cfc

<cfcomponent displayname="foo">

  <cffunction name="init">
    <cfreturn this />
  </cffunction>

  <cffunction name="getName">
    <cfreturn variables.name />
  </cffunction>

  <cffunction name="setName">
    <cfargument name="name">
    <cfset variables.name = "">
    <cfif ListFindNoCase("foo",arguments.name)>
      <cfset variables.name = arguments.name>
    </cfif>
  </cffunction>

</cfcomponent>

BAD:

bar.cfc

<cfcomponent displayname="bar">

  <cffunction name="init">
    <cfreturn this />
  </cffunction>

  <cffunction name="getName">
    <cfreturn this.name />
  </cffunction>

  <cffunction name="setName">
    <cfargument name="name">
    <cfset this.name = "">
    <cfif ListFindNoCase("bar",arguments.name)>
      <cfset this.name = arguments.name>
    </cfif>
  </cffunction>

</cfcomponent>

test.cfm

<cfoutput>

<cfset foo = CreateObject("component","foo").init()>

<cfset foo.setName("foo")>
<cfset foo = foo.getName()>

#foo#

//foo

<cfset foo.setName("bar")>
<cfset bar = foo.getName()>

#bar#

//[empty string]

<cfset foo.name = "foo">

//ERROR

<cfset bar = CreateObject("component","bar").init()>

<cfset bar.setName("bar")>
<cfset bar = bar.getName()>

#bar#

//bar

<cfset bar.name = "foo">
<cfset foo = bar.getName()>

#foo#

//foo

</cfoutput>

Setting a mutator [setting a private [variables scope] CFC variable in a public CFC method], allows one to control what business rules are applied to variable processing via a setter.

Using the public CFC scope [this] inside a setter, would allow outside access to change the value of the variable without calling the setter method. This could be potentially dangerous.

Charles Robertson
  • 1,760
  • 16
  • 21
1

Firstly, as I remember, ColdFusion 8+ has support for implicit getters and setters, which reduces the amount of code.

Generally encapsulation is about controlling access to the underlying object data. This is to provide safeguard the way that data is operated on in concurrent and multi-threaded applications. In a ColdFusion apps most people never worry about this, even though CF7+ has provided CFThread and ColdFusion 4+ has support for CFLock, thus enabling the application developer to control the level of thread safety across an application or CFC library.

William Greenly
  • 3,914
  • 20
  • 18
  • Thanks for the comments, but it really doesn't answer the question. I know all about setters & getters, both explict & implicit [synthesized accessors], but I cannot understand why a private variable should be exposed publicly, by this methodology. For many years, I have just blindly followed this paradigm, but now I want to know why? – Charles Robertson Sep 06 '16 at 14:47
  • And one other point. It is not a good idea to use implicit setters for initialising other CFCs. If a component is set implicitly inside the constructor, there is a danger that it may lose scope when trying to access another component that uses an explict getter/setter. In fact, I have a case study that demonstrates this principle. But, I am going slightly off topic here... – Charles Robertson Sep 06 '16 at 15:18