Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with:

Mom! Ben Broke My CFInterface!

Posted by Ben Nadel
Tags: ColdFusion

I just saw Dan Vega's tutorial on how to use the new ColdFusion 8 CFInterface ColdFusion component interface defining component. It was a good tutorial, but I can't say that I am very excited about this new feature. To me, it doesn't really hold any value because ColdFusion's highly dynamic nature allows just about everything to be changed at runtime. Take for example, the Interface for dog, IDog.cfc:

  • <cfinterface
  • hint="Defines the interface for a dog.">
  •  
  • <cffunction
  • name="Eat"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="Allows the dog to eat the given food.">
  •  
  • <cfargument
  • name="Food"
  • type="any"
  • required="true"
  • hint="The food to be eaten."
  • />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="Poop"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns some poop.">
  • </cffunction>
  •  
  • </cfinterface>

This tells us that at ColdFusion component instantiation time, any component that implements the above interface MUST define the Eat() and Poop() methods. For example, the following ColdFusion component representation of the dog, Lhasa Apso, implements this interface and therefore is required to have the above two methods:

  • <cfcomponent
  • implements="IDog"
  • output="false"
  • hint="Implements the dog actions for the Lhasa Apso.">
  •  
  • <cffunction
  • name="Eat"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="Allows the dog to eat the given food.">
  •  
  • <cfargument
  • name="Food"
  • type="any"
  • required="true"
  • hint="The food to be eaten."
  • />
  •  
  • <!---
  • You eating algorithm would be here; but, for
  • this demo, we are not going to worry about how
  • things actually work.
  • --->
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="Poop"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns some poop.">
  •  
  • <!--- Return the poop. --->
  • <cfreturn "poop" />
  • </cffunction>
  •  
  • </cfcomponent>

However, all of that nice contract validation occurs at instantiation time. But, when does something like this become important? It becomes important after instantiation, when the new CFC is passed to another method or component that has to interact with it. It is only at the time of interaction that this contact becomes important. But, that time, the time between instantiation and interaction, can be a long time, and lots of stuff can happen.

For example, let's say, mad scientist that I am, I want to get all Frankenstein on my dog and start adding methods to it that have no natural reason being there:

  • <!---
  • Create the Lhasa Apso dog (which implements the
  • dog interface).
  • --->
  • <cfset objDog = CreateObject( "component", "LhasaApso" ) />
  •  
  •  
  • <!--- Feed the dog. --->
  • <cfset objDog.Eat( "T-Bone Steak" ) />
  •  
  • <!--- Poop the dog. --->
  • #objDog.Poop()#<br />
  •  
  •  
  • <br />
  • <br />
  •  
  •  
  • <!---
  • Now that we have demonstrated that the Dog
  • works, let's define a random function that
  • returns some stuff and see if it works
  • with the dog.
  • --->
  • <cffunction
  • name="Talk"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Says something">
  •  
  • <!--- Return some speaking stuff. --->
  • <cfreturn "I like the way you look in that dress." />
  • </cffunction>
  •  
  •  
  • <!--- Assign the function to the instantiated dog. --->
  • <cfset objDog.Talk = VARIABLES.Talk />
  •  
  •  
  • <!--- Feed the dog. --->
  • <cfset objDog.Eat( "Porter House Steak" ) />
  •  
  • <!--- Poop the dog. --->
  • #objDog.Poop()#<br />
  •  
  • <!--- Converse with the dog. --->
  • #objDog.Talk()#<br />

As you can see above, we are instantiating our dog which implements the IDog.cfc interface. Then we are creating a ColdFusion user defined function and storing it in the dog. Then we execute that method within the context of the Dog. Doing so, we do NOT get any ColdFusion errors - we get the following output:

poop
poop
I like the way you look in that dress.

That last line is the dog successfully talking back to us, therein demonstrating that ColdFusion does not uphold the CFInterface definition throughout runtime, only at instantiation time. This basically means that just because a ColdFusion component implements a given interface, there is no real contract that any other part of your application can 100% rely on. And, we added a method, but you can just as easily delete a method:

  • <!--- Take away the ability for the dog to eat. --->
  • <cfset StructDelete( objDog, "Eat" ) />
  •  
  • <!--- Try to feed it now. --->
  • <cfset objDog.Eat( "Roasted Chicken" ) />

Running the above code will throw the following ColdFusion error:

The method Eat was not found in component

Basically, after the ColdFusion component is instantiated, all bets are off.

Now, you might say, "But Ben, no programmer is ever going to do something like that!?!?" Are you sure? But, even if no one would really do this, the fact that it can even be done really defeats the purpose of the CFInterface tag to begin with. Ok, sure, maybe it will stop a few more compile time / instantiation time errors... but is that really where the problem is? Maybe, maybe not. I would argue that the real problem is at the point of interaction, and CFInterface does nothing to uphold a contract at that point.




Reader Comments

Isn't the point that it implements at least the interface, but can also have more functionality... thus allowing it to implement multiple interfaces. Ex: Dog and BombSniffingAnimal. In your example it appeared that you didn't break the contract, justed added on functionality....?

Reply to this Comment

I did delete the Eat() method, which breaks the contact. But you are correct, my primary example is not that good - I am very tired today :)

Reply to this Comment

Interfaces are more useful for typechecks, not implementation validation. For example, passing an CFC instance of type IDog into a method that requires an IDog. Doesn't matter if it ultimately descends from AbstractCanine or if it's from FrankenDog, as long as it implements IDog, you've got what you want. That's not going to ensure that the interface-specified methods are going to exist, because as you say, you can delete methods at runtime. It does, however, protect you from passing in an object that isn't an IDog.

Why is this helpful? Say I have a subclass of AbstractCanine and I delete the 'eat' method and pass it to a 'takeToPark' method that expects an IDoc instance (but doesn't actually use the IDog type). Chances are good that nothing bad will happen, and the 'poop' method will be called successfully. Now if I delete the 'poop' method and pass it in, you'll get a method not found error. But most of the time I'm not going to be deleting methods willy-nilly.

Far more likely is that I'll end up fat-fingering something and passing in some other object that isn't an IDog (maybe IHuman, because I passed dog.getOwner(), instead of just dog), but still has a 'poop' method. That'll still likely work (because of the duck typing nature of CF), but it very likely represents a logic error that won't actually raise an exception. If your 'takeToPark' method explicitly requires an IDog instance, then an exception would be raised on first invocation. You can imagine how easily that logic bug would slip through testing, particularly if you never thought about the edge case where on the way to the part the dog sees some other dog and gets it's 'sniffThatDogsButt' method called (which IHuman doesn't have - or at least shouldn't).

Reply to this Comment

@Barney,

I see what you are saying. I guess my main problem is that that I have never worked on very large projects or with teams (at my work, its more the army-of-one mentality). As such, I always have my hands in all parts of the code, and I guess I just feel like this tends to solve a problem that I never run into.

As with all data / interface validation, I am sure this becomes increasingly more important the larger the project / team gets.

Reply to this Comment

@Ben - as you now know, interfaces are minimum requirements, so something that implements one can in fact implement more than one, and add extra functionality.

But, deleting is still a problem =)

I'm one of the ones who think its not really necessary. CF isn't Java or C#, and we have better constructs available to simulate multiple inheritance, and even still let you reuse code from one to another. (But, no sense really in getting into that debate).

@IInterfaces - I'm not fond of the IConvention in front of an interface. It kind of destroys the point of them, so I think you ought to be naming the implementors specially, and give the interface the name it represents. Its not just me, I know, but I can't think of a reference off the top of my head to point you to the discussion about why its not a good practice.

Reply to this Comment

@Ben - oh yeah, I wanted to congratulate you on the (paraphrasing here) it doesn't enforce anything at the point where it would be worthwhile to enforce comment. That's a great observation.

Reply to this Comment

I have to admit that it was like 1000 degrees in my apartment last night and I didn't really fall asleep... as such I am about to pass our right now, so I think it's a miracle I am even putting sentences together :D

Reply to this Comment

Heh. It's be funny if you called takeToPark() and passed it dog.getOwner() instead of dog, and then called the poop() method. "SIR!! You can't do that here!"

I agree on the useless interface part. People deleting a function may not be particularly likely, but imagine an interface that takes a dog, but you REALLY want to pass it a cat. Some enterprising individual is going to run into this and in their component do something like this:

Cat.cfc
<cfcomponent implements="IDog">
<cffunction name="init">
<cfset this.bark = this.meow>
</cffunction>

<cffunction name="bark">
<!--- Do nothing --->
</cffunction>

<cffunction name="meow">
<cfargument name="attitude">
meow!
</cffunction>
</cfcomponent>

Even if you feel that still fulfills the contract, it clearly does not do what the calling method is expecting when it calls bark(), which will cause exactly the type of problems that Interfaces are meant to avoid. And it also lets you change parameter signatures on the fly, which is where most people will abuse it, says I.

Reply to this Comment

@Jeremy- I can define a method

add(x,y) { return (x-y) }

And that is my problem for defining a lying cheating bastard of a method, not the interface's fault for declaring a method I need to implement if I want to be a type of that thing.

I don't see how interfaces were designed to avoid that at all. Interfaces (the type we are talking about, anyway) were designed as a way to have multiple inheritance, but without the implementation... or, a thing can be a type of many things.

Reply to this Comment

Yes, of course you're right. However, my main point, even though i don't think I expressed it well, was that you could effectively change the signature of the method, which would indeed subvert the contract. Interfaces are not just about what methods are available, but what they take as parameters and what they return. This can be changed at run-time and very easily so.

Reply to this Comment

Yeah, I'm definitely in the "why bother?" camp about interfaces.

I also dislike the ISomething naming that so many people seem inordinately fond of - smacks of Hungarian notation to me and it does not help readability.

I prefer to see interface names that end in -able, -er or -ing and which describe behavior you need in your object, e.g., Clonable, Runnable.

The problem is that most interface examples are inappropriate uses. An IDog interface does *not* describe a dog at all. It describe something - anything - that has a void eat(any) method and an any poop() method.

There are lots of use cases where CF8's interfaces just don't cut it in my opinion (I just posted a long response on cf-talk about some of the flaws).

About the only thing I might use interfaces for are "markers'. An empty interface that simply tags a class. I think the ColdSpring guys are considering going this way. In other words, using the interfaces purely as metadata.

Reply to this Comment

I'm with Sean on this. I think they're really only useful for marking classes for the runtime (if that's what he meant).

I could see CF providing some special interfaces like Comparable that you could implement the compare(a,b) method for and then you could use the CF operators to compare your components, or other such syntactic beauty. Then again they could just add an onCompare(a,b) special method too... I'm sure there are special cases where an interface makes sense... I'll just have to think about it.

Honestly, other than cases like that, I don't see them being terribly useful in projects. :/

Reply to this Comment

Ack, I read ColdSpring as ColdFusion. That's what I get for commenting at 2am. Sorry Sean!

Now that I think about it, interfaces as metadata for how the a framework should treat your component is interesting too.. but cfproperty would honestly work just as well.

Actually, since you can add random attributes to <cfcomponent>, you could just use interfaces in CF7 or CF6 too, and ignore the fact that there's a cfc file somewhere that has a <cfinterface> for CF8 users.

It is useful from a purely "catch idiot bugs" perspective though. Such as ensuring you have proper return values in functions. Much like adding a returntype now, which really is just as "strict" as interfaces since the returned component instance makes no guarantees about methods.

This really is a weird "feature" given how the runtime works when it enforces type checks.

Anyone have a good example of cfinterface being used for anything neat or exciting?

Reply to this Comment

With cfproperty (or adding attributes to cfcomponent) you would have to get the metadata and walk over the metadata. There is also the potential for conflict with other metadata-driven CF tools / frameworks. With cfinterface, adding a marker interface cannot conflict with anything else and CF8 automatically performs the "type check" for you. Overall, changing ColdSpring to use cfinterface is a much cleaner solution than metadata.

Personally, since they're doing this for bean-factory-aware objects, I think a simple test for structKeyExists(obj,"setBeanFactory") and isCustomFunction(obj.setBeanFactory) is cleaner still (and works on CFMX61 and CFMX7).

Reply to this Comment

@Sean

I was still thinking like CF7 where you'd need to get the metadata to figure out the inheritance, and totally forgot about isInstanceOf().

I suppose you could write an "adapter" for CF7 and below for CS that defines isInstanceOf() that scans the metadata for the implements attribute. Of course that assumes they don't set returntypes for functions with the interface values.

Reply to this Comment

@Elliott, I think you're missing the point. ColdSpring 1.5 will be the last version of ColdSpring compatible with CFMX7. ColdSpring 2.0 onward will require CF8.

Reply to this Comment

@Sean

Rather, I think you're missing my point Sean.

Not everyone can afford at the current time to upgrade to CF8. ColdFusion 7 has been around for how long? And we still have clients with 5, I was talking with a hosting provider who still has people on 4.5.

I don't really think it's reasonable to require CF8 for ColdSpring 2 when CF8 isn't even available yet.

If it was as simple as saying "hey, CF(n) is out, our framework will only work with that" the community could have moved FuseBox, Model-Glue, Reactor and many others to CF7 2 years ago.

There's a big reason to be backwards compatible, as shown by all the frameworks that still are. As far as I'm concerned it's one thing to abandon CF6.1 since it's two versions behind now, but it's something else entirely when it's one version behind.

How quickly do you really think hosting companies are going to be adopting CF8? How long did it take them all to get CF7?

Either way, I don't see anything wrong with writing adapters for ColdSpring 2 or porting code so you can get many (or all) of the benefits on CF7. You might not use it, but I bet other people who don't have the luxury of updating right away will. :)

Reply to this Comment

@Elliott,

Of course it's reasonable to require CF8 for ColdSpring 2. No one has to upgrade beyond ColdSpring 1.5 if they don't want to. This is a *roadmap*.

CF5 is six years old and CFMX6.1 has just been EOL'd (which came out four years ago). CFMX7 has been out nearly two and a half years now.

HostMySite is already offering CF8 as a beta and should be offering the final release very soon after release. I expect other hosting companies to be offering CF8 by year end - ColdSpring 2 won't be out until later in the year (at the earliest).

People who stay on CFMX7 can get all the great benefits of ColdSpring 1.5. Folks who upgrade can take advantage of CF8.

I think you'll see frameworks moving to CF8 much, much faster than previous version upgrades.

Reply to this Comment

The sad thing about the introduction of interfaces is that they make so little sense in ColdFusion. Now, I *love* interfaces in Java. When teaching Java, interfaces are where we *start* in the design of a system. And, because of Java's compilation phase, you get type-safety (a nicety) and your IDE can offer you help with the methods available. This is especially nice when doing method-chaining.

Without this compilation phase, there is no real type safety and the IDE can't offer you this kind of help. Now, type-safety is nice, but by no means necessary (ask the Smalltalk and Ruby folks).

Dynamically-typed languages have their own ethos for creating apps -- a very different one than for statically-typed languages. Treating a dynamically-typed language as though it were a statically-typed one (which is what interfaces do) can only lead to frustration -- and the deeper message is that statically-typed languages are "real" languages while dynamically-typed ones are only "script" languages, else why would we adopt methods suited only to statically-typed languages?

With the power of ColdFusion 8, is that really the message we want to endorse and spread? I certainly don't.

Reply to this Comment

OH SNAP! Hal Helms just commented on my site!

(Note to self: don't get too excited, it will make you look like a child)

I like Hal's point about the message that it might send to the people who are not in the know. In general, I have to default to other as I know so little about proper programming.

Reply to this Comment

I'm coming into this discussion with very little OO experience, and no experience whatsoever with interfaces. What I'm looking for is a single point of entry into my processing code.

For example, I might have a family.cfc, a planner.cfc, and a volunteer.cfc, all from an app I'm writing and all with distinct methods. As I understand it I could then have a single pointOfEntry.cfc which extends each of the other CFCs and details each method I'd use. But any call that I make to A CFC would get routed through the ointOfEntry.cfc. Is this correct?

Reply to this Comment

@Andy,

I am not sure if I fully understand what you are saying. A given CFC can only extend a single other CFC. I was not sure if you were talking about multiple inheritence or if those were suppose to be several interfaces that could all be extended independently?

Reply to this Comment

No...

I've been under the impression this whole time that an interface could essentially extend multiple CFCs. That it could essentially combine methods from more than one CFC into a single "interface". Then you'd only ever have to expose ONE CFC to the world.

For example, a facade design pattern for remoting calls. I might need to access methods found in multiple CFCs, but rather than expose ALL of those CFCs as remote, I'd expose their counterparts in the interface as remote and go from there.

Does it not work like that?

Reply to this Comment

No, Andy. An interface specifies what methods CFCs should implement.

A CFC implements one or more interfaces.

Interfaces can only extend other interfaces.

Reply to this Comment

@sean...

So would you say that an interface is more used to enforce app integrity and consistency? Given your explanation sean I can't think of a reason I'd ever use an interface.

Reply to this Comment

@Andy,

As far as I know, CFInterface is really only meant for people who are looking for the kind of Type checking that languages like Java have. I am not sure it adds much else beyond that.

Reply to this Comment

Yup, interfaces are to "enforce" a programming contract, stating what services are available on any object whose class implements the interface. They're not very useful in a dynamic language like CFML.

They show up a lot in Java because Java decided not to incorporate certain features from C++ (which does _not_ have interfaces, although it does have the concept of a "pure virtual" class which is fairly similar).

They also tend to show up in design pattern examples because many design patterns are about contracts and substitutability. However, it's worth noting that the two languages chosen to illustrate the "original" design patterns book - Smalltalk and C++ - do not support interfaces. Smalltalk is a dynamic OO language - and CFML has more in common with Smalltalk than with Java (which is why I don't like to see people trying to write CFML as if it is Java).

Reply to this Comment

I'm not sure if this has already been mentioned in anyone elses comments. There's a lot been said about there not being much benefit to interfaces and for the most part that is correct, unless you are using them in a specific way. Take the following...(using the same dog/cat idiom from a few comments ago).

<cfcomponent name="dog">
<cffunction name="speak">
<cfreturn "woof" />
</cffunction>
<cffunction name="eat">
<cfargument name="food" type="string" />
<cfif NOT StructKeyExists(variables,"belly")>
<cfset variables.stomach = [] />
</cfif>
<cfset ArrayAppend(variables.stomach,arguments.food) />
</cffunction>
</cfcomponent>

<cfcomponent name="cat">
<cffunction name="speak">
<cfreturn "mieow" />
</cffunction>
<cffunction name="eat">
<cfargument name="food" type="string" />
<cfif NOT StructKeyExists(variables,"belly")>
<cfset variables.stomach = [] />
</cfif>
<cfset ArrayAppend(variables.stomach,arguments.food) />
</cffunction>
</cfcomponent>

<cfcomponent name="person">
<cffunction name="feedPet">
<cfargument name="pet" type="dog" />
<cfargument name="food" type="string" />
<cfset arguments.dog.eat(arguments.food) />
</cffunction>
</cfcomponent>

Now if you want to do some type checking, as is implemented on the pet argument of the feedPet method before using cfinterfaces, you would not be able to pass the method a cat object. Even though it would be a valid object, as it would fail type checking.

However, if you set up an interface, which both objects would then implement and then check for the interface instead of the object, they would then both be valid.

<cfinterface displayname="pet">
<cffunction name="speak" />
<cffunction name="eat">
<cfargument name="food" type="string" />
</cffunction>
</cfinterface>

<cfcomponent name="dog">
<cffunction name="speak">
<cfreturn "woof" />
</cffunction>
<cffunction name="eat">
<cfargument name="food" type="string" />
<cfif NOT StructKeyExists(variables,"belly")>
<cfset variables.stomach = [] />
</cfif>
<cfset ArrayAppend(variables.stomach,arguments.food) />
</cffunction>
</cfcomponent>

<cfcomponent name="cat">
<cffunction name="speak">
<cfreturn "mieow" />
</cffunction>
<cffunction name="eat">
<cfargument name="food" type="string" />
<cfif NOT StructKeyExists(variables,"belly")>
<cfset variables.stomach = [] />
</cfif>
<cfset ArrayAppend(variables.stomach,arguments.food) />
</cffunction>
</cfcomponent>

<cfcomponent name="person">
<cffunction name="feedPet">
<cfargument name="pet" type="pet" />
<cfargument name="food" type="string" />
<cfset arguments.dog.eat(arguments.food) />
</cffunction>
</cfcomponent>

It is generally used to be able to swap out one object with another without breaking the internal code of the objects that use it. Very useful for large projects and large development teams.

Reply to this Comment

That's the Java way of thinking. It's not how developers work in dynamic languages (Ruby, Groovy, Smalltalk etc). It's a circular argument for CFINTERFACE - it's useful because Java does it that way. Java has interfaces because it refused to accept multiple inheritance (like C++) and programmers needed compile-time mixins.

Trying to program CFML in a Java style is very limiting and I wish CFers would get over that and learn the more powerful and expressive approach possible in dynamic languages - learning from Ruby, Groovy and the grandaddy of all dynamic OO languages, Smalltalk...

Reply to this Comment

One of the classic knocks about CF is that it promotes spaghetti code...queries, html, cf tags, and javascript everywhere and anywhere...usually in the same template...well since cfc's have come along we now have spaghetti cfc's with objects being created seemingly without rhyme or reason, inheritance overuse (along with the weakening of encapsulation) because composition is not well understood, and methods that don't know what they are returning as illustrated by the large number that I see using "any" as a returntype. If you are part of a large development team the applications you end up with can be a mess...maintenance is a nightmare and debugging worse...architecting applications correctly is critical to easing code maintenance as well as allowing that code to be updated easily in response to changing business requirements. I see cfinterface as another tool in my OOP belt that allows me to create apps that are maintainable while taking advantage of important constructs like polymorphism...and instead of avoiding or dismissing some of the concepts of typed languages like Java or ActionScript, we as CF developers should be embracing them...I find myself constantly thinking about what a component should be doing and limiting the responsibilities of a component...I have seen components written that have an inordinate number of responsiblities instead of the 1 - 3 they should have...I think about the typing of arguments and method returntypes when I code...these aren't bad things in CF they are good...this way we can have the best of both worlds...CF users have an obligation to learn OOP constructs as much as possible...but it seems like many voices in the CF community downplay these constructs so in the end we have the same problems we had prior to MX...increased spaghetti code and unmaintainable apps....leaving users of typed languages who view our messes with the same impression of CF that they had before: That CF is not ready for prime time...

Reply to this Comment

@Larry,

If you are dealing with polymorphism, most of the time, you are dealing with some sort of base-class that has actual functionality; in that case, I would say that you can just return the concrete base type class, rather than using an Interface type. Granted, I am not a traditional programmer, but it seems like most of the time, there is rarely a need for a purely definitive Interface class. Of course, if there is, use it.

More than anything else, though, I think the use of "any" as a return type has to do with ColdFusion path requirements for CFCs. To me, this is the limiting factor. Since you cannot use relative pathing for CFCs, your class inheritence paths have to be full from the root of the server. When your DEV and Production environments change, I find that this is not possible without special path mapping (which to me seems to be too much overhead to be useful much of the time).

Anyway, just some thoughts; not arguing for or against CFInterface, just saying that I personally haven't found a need for it yet. And yes, I work on teams of 1 or 2 people.

Reply to this Comment

Hi Ben...No doubt you can use inheritance to define your interface and just add a cfthrow to the base class if someone tries to implement it (the base component) instead of overriding it with a concrete class (component)...but to me if you're on a CF 8 box using an interface construct like cfinterface is just more elegant. And in complex applications interfaces allow you to define common methods and datatypes that all classes must implement...so if you know how to use one component that implements that interface you know a lot about other components that implement that same interface...I guess I just like the structure of it all...and even tho CF is dynamically typed...there may be a programmatic reason to specifically type variables with components that implement an interface so that components can be swapped out at runtime...various design patterns are effective because they don't depend on a class...they depend on a type...in this case, an interface type...and as CF becomes more robust in the things it can do and if it becomes event driven then, this may be something that could be of even more use in the future. I would say that if an application is being architected for the first time the development team may want to consider cfinterface as a way to more closely adhere to OOP constructs and to allow multiple developers to work on the app at the same time...in any event...I guess all of this really depends on your comfort level and understanding of OO programming...while CF mitigates (to a large extent) the need to be well versed in OOP constructs (to the detriment of the CF community I believe)...I think that code that closely adheres to fundamental OOP principles is better code in terms of maintainability, performance and (possibly) reduction of bugs...

Reply to this Comment

@Larry,

"instead of avoiding or dismissing some of the concepts of typed languages like Java or ActionScript, we as CF developers should be embracing them"

I think this is a narrow world view. I think that we as CF developers should be embracing concepts from Smalltalk, Ruby, Groovy and other powerful OO weakly-typed, dynamic languages.

CFML is *not* Java and many Java idioms are simply not applicable to CFML.

Reply to this Comment

@Sean, very well put IMO on CFML is not Java. This is a hard concept for many to absorb. Java is good and the other languages are good. Each has their own good. Likewise CF has many good features and we should foremost embrace CFML when coding in ColdFusion.

Reply to this Comment

@Larry,

While I agree with what @Sean is saying, I think you are right that it does come down a bit to what you are comfortable with. I am not a good OO programmer, so OO concepts escape me.

Reply to this Comment

@Ben and all:

I really enjoyed this discussion as it has opened my eyes in the idea of interfaces. I am much more of a CF developer than a Java developer, but I feel I do like the concept of interfaces for structure reasons.

For example, a project I am working on now requires me to create feeds for services like Google Products, Amazon, Shopzilla, etc. This is my idea of the structure I would like to follow:

Feedable.cfc - my feed interface
AmazonFeed.cfc - implements Feedable
GoogleFeed.cfc - implements Feedable

Following this design style, I will know that AmazonFeed and GoogleFeed will have the methods and data types that I require. Of course, this assumes that the object is not altered after instantiation. What would be the pros/cons of developing with an interface in that scenario?

Lastly, I have been looking at some code of another developer who seems to be following the idea of interfaces, but is actually using inheritance by extending objects rather then implementing.

For example, there may be a "ShipperInterface.cfc" which is a component, NOT an interface. Then, other components such as ShipperUPS.cfc, ShipperFedEx.cfc, etc extend the "ShipperInterface.cfc". In this case, if an object doesn't have a specific method defined, it can still be called based on inheritance. Likewise, if the method is defined in the object, it overrides the inherited methods.

My problem is that I can see why this developer would design that way, but I also think a true interface would be more appropriate.

Hopefully you all can shed some light on my thinking.

Reply to this Comment

@Tristan,

Rather than asking about the Pros, I would say to ask yourself if there any CONS to not using CFInterface (at the practical level). If there are, then you should use it. If not, then just carry on as is.

Plus, if you are going to be extending base objects (ex. Feedable) that do have functionality, you might question whether having a base object AND an interface is really what you feel you need to do.

Reply to this Comment

@Tristan Lee,

Much is going to depend on whether there is a suitable "default implementation" for a method. If there is, it's reasonable to provide a base component and extend it to override / add other functionality. If there isn't, an interface might be appropriate.

Personally I think interfaces are highly overrated in a dynamic language like CFML since you can modify a component's API at runtime. Also, onMissingMethod() - which is immensely useful - isn't taken into account when a component "implements" an interface so you have to have explicitly defined methods that exactly match the interface (you can't even add optional arguments!). I seem to recall that at one point the argument names had to match, which is ridiculous (is that still the case? I haven't checked lately because, well, I don't use interfaces in CFML!).

Reply to this Comment

Post A Comment

?
You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.