Why the change of heart? Well, with all the OO ColdFusion I've written, I must admit that I haven't really missed interfaces. At first I did, but then I started to use type="any" or type="WEB-INF.cftags.component" and that is actually more powerful. How can a "weaker" type be more powerful? Simply because you can pass any object that is able to respond to the necessary methods - those objects don't need to be part of a rigid single-inheritance tree!
I'm not the only person who thinks this way... Michael Smith just interviewed Hal Helms about his talk at CFUNITED 2006 and here's a little clip from that:
Michael Smith: So, you're going to argue that Adobe should add interfaces to ColdFusion?Hal's talk is about "duck typing" which is only really possible in languages that have dynamic type systems (where a variable's type is determined at runtime based on its contents).Hal Helms: No! What good would that do us developers in the trenches who face these problems right now? Besides, that's exactly the wrong solution. The reason that C# and Java need interfaces is that they are statically typed -- that is, data types get determined prior to run time. But ColdFusion doesn't suffer from this restriction: it's dynamically typed. What we need is to embrace the fact that ColdFusion *is* dynamically typed. And we haven't even started to talk about mixins! There are all kinds of new possibilities!
Smalltalk programmers are used to this, as are Ruby programmers and others. With all the enthusiasm around Ruby these days, ColdFusion programmers might do well to embrace some of Ruby's strengths which are also ColdFusion's strengths - including dynamic typing.
it doesn't worry you that you won't know you've picked the wrong CFC (or even the wrong method to call in that CFC) until runtime?
I take your (previous) point that CF doesn't really have a "compile-time" to check types and signatures but I'm knee-deep in a .NET app at the moment where interfaces are proving to be a real help (I know, comparing apples to oranges...)
just curious that's all...
What guarantee do you have that the object passed in to your method implements the behaviors you're executing on that object inside your method?
Also, if I want to use your CFC, I'd have to thoroughly read through your method's code to understand exactly what type of object I could pass to your method.
One of the great advantages of OO languages like Java is classes a have an easily understood public "interface (understanding)" that is enforced at compile time. This enforcement is partly based on static typing.
Interfaces enable programmers to lessen coupling between classes, while also ensuring runtime success. If my class implements interface Foo then my class can be used anywhere type Foo is required. Interfaces are the agreement between my class and your class that guarantee we can work together without either of our classes really knowing what's going on inside the other.
I personally think static typing and interfaces lead to better written code, improved integration among classes, easier code re-use, and simpler application expansion.
If we are going use object oriented patterns in our ColdFusion application designs, then interfaces are just one of several improvements to the ColdFusion language that will help us.
For example, if ColdFusion had interfaces my Service CFCs could include an instance of a a CFC that implements the DAO interface instead of coding my Service CFC to contain a concrete DAO object.
Most patterns recommend coding to an interface rather than a concrete type. Interfaces make expansion and modification much simpler.
I do agree 100% that in a dynamically-typed language like CF that you can't be very specific with interfaces and they're not as powerful, though I do think they serve an important organizational purpose that can help clear up the murkiness of a large/complex class hierarchy.
> What guarantee do you have that the object > passed in to your method implements the > behaviors you're executing on that object > inside your method?
What guarantee do you have about ANY CFC method parameter? Without a compilation phase and static typing the only thing that is guaranteed is that CF will throw an exception if you pass in an invalid parameter. Either you specify a type and provice an instance of that type, or you specify type "any" and provide an object that implements the required methods. Either way, runtime exceptions are your only way to catch bad data.
Cliff: I agree with your points on interfaces serving an important organizational purpose. I really do enjoy dynamicaly typed languages like CF and Ruby but I always worry about losing track of which objects depend on which methods of other objects. Still, if I had to choose I'd choose the additional flexibility.
Bruce, ColdFusion is not Java. There is no compile-time type-checking. At runtime, ColdFusion throws exceptions when things don't match. Interfaces would not change that. Not all OO languages have interfaces as a language construct and yet they are still good OO languages that support those design patterns.
Cliff, I agree that without an interface you still have to document the requirements. However, an interface means you have to read the source code anyway unless there is good documentation to say not only what methods you must implement but also what pre-conditions, invariants and post-conditions are assumed - an interface never provides that information so documentation is necessary anyway!
Keith, agree. Seth, agree too.
I converted from pro-interface to "only-on-paper" interface last spring, and I'm still feeling pretty much the same. After talking with some others, I *do* think it could be handy to "mark" CFCs as being of a particular interface, but that the checking should be very little if existant at all. It seems like nice compromise between strong, compile time type checking and the "You mean I have to read all the code of the DuckProcessor to figure out how a 'Duck' should work?" trap that I think pure, "Ask for forgiveness later" Duck-typing could lead to, especially in cases where documentation is slim.
We can still notate the Interfaces in the domain model with our class diagrams. But in development, we know we just need provide those methods. Even in .NET and Java, you still have code the method in the class. The Interface only acts a traffic cop and a template for required methods. ColdFusion doesn't need a traffic cop, because strong typing is NOT required. Besides, don't we 'all' test out code in the run-time before deploying it production?
I've taken Hal's class. We banged our heads for most of one day thinking of ways around it. In the end, I totally missed the point of interfaces because I was so blinded by trying to solve the problem that I forgot what the problem was. Afterwards, I asked myself, what's the point of the Interface and started looking at Java and .NET for why they exist and what you still have to do to accomplish it. It was a no brainer, the strong typing of the language has the need for Interfaces. Interfaces provide sub types for an object strongly typed languages. Dynamically typed languages can let sub types slide as long as the method to be called exists.
What might be a useful function from the ColdFusion team, is the ability to test an object for the existance of method before executing the method.
All this talk of strong typing in CF is getting silly... because no matter how hard you work to implement it in CF you're not going to get the error until runtime. End of Story. In other words, whether you get a runtime error about an invalid type or unimplemented interface or you get a runtime error about a missing method (which is really more helpful anyway) or an argument type mismatch, you're still going to get runtime messages.
Johnathan, you can already use cfif structKeyExists(Object,"myMethod") to determine if a method exists, and can therefore check for the correct "interface" before calling it. In fact this is being used extensively in MG and ARF to call setters for event variables only if the setter exists:
<cfset eventData = arguments.event.getAllValues()> <cfloop collection="eventData" item="item"> <cfif structKeyExists(myBean,"set" & item)> <cfinvoke component="#myBean#" method="set#item#"> <cfinvokeargument name="#item#" value="#eventData[item]#" /> </cfinvoke> </cfif> </cfloop>
So you can already handle interface checking and you can throw custom errors if the interface is missing methods. You can rely on CF's more descriptive missing method exception instead of "doesn't implement x" ala Java, you can dumb your types down, but you can still use inheritance to make sure that an object is derived from a particular inheritance tree... without recreating any of the platform.
Let's not keep trying to reinvent the wheel... while CF's underpinnings are in J2EE, CF itself is NOT J2EE. Accepting that is the first step toward understanding just how powerful CF can be when you use it as CF instead of trying to wrap it in Java/C++/.NET concepts.
Aside from that, all the arguments I've seen for strong typing and interfaces in CF have been based on things that are entirely under the developer's control. How do you know your object is the right object if it can't implement interfaces? Well, you write the application so that it sends the right objects... sometimes it strikes me as shortsightedness or even laziness that drives the call for this.
Anyway... just my $.02.
Laterz!
Defending ColdFusion Against Java: "Great, so, ColdFusion simplifies Java development, and ColdFusion applications are no less Java than applications written in low-level Java directly. But simplicity and abstractions require sacrificing power, right? Wrong! ColdFusion applications can (and should) leverage Java; Java APIs, Java classes, Java beans, JSP tags, you name it, ColdFusion can leverage it because ColdFusion itself is Java. It's that simple."
ColdFusion converts CF code into Java bytecode, and it runs on the server as Java... but the rules of the language, the way the objects work, and how it does what you tell it to do is not Java. Java is the end result, but the path to getting there isn't the same. It's a lot closer to JSP, but even JSP requires a String to send data to the output buffer...
Mostly, JSP/Java is a waste of time when creating web applications because HTTP is stateless and typeless. CF is a bridge between the stateful and strongly typed world of Java and the stateless/typeless world of HTTP (at least as far as developing browser-based websites is concerned). Add to that the fact that it works with FTP, SMTP, POP, webservices, LDAP, RDBMSs of many kinds, text, numbers, Java, ad infinitum... and you have one very powerful platform that can get a great deal of work done very, very fast.
It's like Jython - that's the Python language (which is not Java) but you're using it to build Java apps in effect.
If folks keep trying to add Java-like features to ColdFusion, they'll end up with Java.
Make sense?
but on simplistic level, CF isn't fully typeless either - we still have dates, numbers, cfc references....(semi-typed?)
with all this talk about "Mystic" + the next release of CF, at what point does CF start to run out of steam/get left behind?
back in 1999, Microsoft went far beyond their vbscript classes (similar to CFC's - continers for functions with public + private structs) and an interpreted language (ASP classic) which eventually gave birth to ASP.NET. Sure they had other reasons to do so (like giving their old VB programmers a new life)...but they saw a need to do so.
So what's left for improvements for CFC's since there'll never be strong typing of the language and no interfaces? Where to from here?
or is that it? we've got all we'll ever have?
What "improvements" to CFCs do you actually need in order to get your job done?
ColdFusion's power comes from its ability to quickly and easily bridge a wide variety of technologies and problems and new features have almost always focused on solving problems that developers face - at a conceptual level rather than at a language syntax level: easy-to-use database code, protocol support (LDAP, FTP, SMTP/POP etc), web services, PDF generation, report building, complex form management, asynchronous data/process integration etc etc. I expect ColdFusion to continue evolving, providing more high-level solutions to problems, allowing developers to build better systems faster.
Your final point, however, is where you prove you've actually MISSED the point entirely. Strong typing in CFCs, and interfaces, are NOT IMPROVEMENTS. They're inhibitors... they're why I don't like writing in Java, because they shackle my creativity and create excess work. You say "why can't I have strong types??" and I say "Why should I have to cast anything manually??" Seriously, other than to satisfy the minds of those who can't handle a relaxed language, there's absolutely no reason to provide them that I can see.
I *do* see the point: it's either have an OTT language where you can nit-pick to the n'th degree or have a RAD language that bypasses all that for the sake of simplicity and effectiveness: "if you want all that stuff, use Java", etc.
but what you're also saying is that CFC's are at the end of their development cycle**, not the start. There's no room for anything else and there never will be.
yes?
** with the exception of a few "tweeks" like serialisation, perhaps?
Over the last few releases and updates, we've seen the addition of all sorts of web services control added to CFCs, Application.cfc, event gateways (based on CFCs). All sorts of things keep getting added.
To me, it's as if you're complaining that arrays and structs are at the end of their development cycle without offering suggestions of improvements - and justification for those improvements.
CFCs do a great job. I don't find there are any major pieces of functionality missing - in real world situations - although there are a number of small "tweaks" I'd like to see that might just make my life as a developer more convenient. I used to think interfaces were the big, missing piece but I no longer think that. If CFCs are stable and do their job, then the end of their development cycle should be exactly where they are, yes?
But, I don't think I understand where you're going with the whole concept of CFCs being at the end of their development cycle. Is there a problem with them being "finished"? If the intention was to create an OO construct, why does that have to change, and why do they need to fall in line with the Java view of OOP? That's where we're having a disconnect. I know you want NULL, interfaces and strong typing, but they're all contrary to the nature of the platform.
It's time for people to drop the expectation that CF will conform to the C-based languages, or Java, and start looking at CF as something new, something unique, and something empowering. ColdFusion gives the common man cheap access to incredible amounts of power... ooh! I like that! But it's never going to have null because it can't. It's never going to be strongly typed because it deals with value, not nature, anyway. And it's never going to interfaces because the amount of benefit is so small relative to the amount of work it would take to make it work that it's not worthwhile.
Then again, watch the CF team prove me wrong. What interfaces would give is a smile, and a degree of comfort, to Java developers. That's about it. Nobody else really cares about Java-style interfaces, especially in the context of a late-binding language with no real concept of types.
So... you seem to be lamenting the fact that CFCs are "at the end of their development cycle", so could you clarify why? I don't really see the problem, because if the construct has been fitted to the platform, they SHOULD be done and adding a lot of extra stuff would be wasteful. I'd rather see the CF team focus on enhancements to UI generation tools like XHTML compliance in htmlParagraphFormat() than see them spend a lot of extra time on these other issues.
Can you clarify?
We keep hearing that ColdFusion doesnt need these features and benefits by not having them - Also this "weakness" is in fact a strength, either now or in future releases
The easiest way to settle this debate is by coming up with new features ColdFusion *could* have that are enabled by this lack of traditional OO functionality
I'll start the ball rolling
Runtime generated CFC's - I currently have build tools that spit out CFC files, would be cool if this generation of CFC's could be done dynamically at Runtime.
Dynamic modification of Objects/CFC's - Add/Remove methods and attributes dynamically at Runtime, a slight extention of this would be the ability to merge two object together to form one object
I have no idea how I would use these but they would be powerful features.
I'd be curious to see a ColdFusion version of Aspect Oriented Programming - I know little about AOP except that it's a buzz word like "Ruby-on-rail" and often you need a modified Java Runtime or have to endure the powerful yet frighting nightmare that is JBoss
These are some of my ideas, I'm sure the readers out there can come up with more
That could be very handy.
But... as far as dynamically modifying the methods and properties of a CFC, that's already there. CF treats methods as struct keys, so you can create a UDF in a page, create an instance of web-inf.cftags.component, then do cfset Object.myMethod = myUdf and it works just fine. Using that technique you can create an adapter method that gets you access to the variables scope of a CFC. Handy but dangerous.
It's what we've been calling "Behavior Injection" or "Method Injection" and it's the foundation for things like ARF.
And while I haven't used it, ColdSpring allows AOP already using CF so you can do things like trap calls to CFCs, modify their behaviour, then let the call finish executing.
While I haven't needed it, I'm sure many, many people would be happy to see CFCs able to be replicated across members of a cluster. I think that async calls from within CF would also be handy (i.e. cfthread or something...) but I'm drawing a blank when it comes to other advanced features that would be nice.
Anyway... it's a good question.
Barry... what WOULD you like to see done that isn't there yet?
I also appreciate this discussion very much. There's seems to be a general perception out there that if ColdFusion doesn't fully implement all OO constructs, it's not the real thing. I'm glad to see that questioned in an intelligent, down to earth way.
Also, we seem to have veered off-topic a bit but since there's such a good discussion going I thought I'd toss in my thoughts for improving CFCs sans interfaces:
1) I second Bruce's thoughts on a dedicated constructor method. The init() convention works well but I would prefer an official language feature if possible.
2) Automatic var scoping of local function variables. Despite tons of blog posts and documentation entries about this issue people are STILL not doing this and being bitten by it. I'd much the default behaviour be local variables and have to manually specify when I want a global rather than the reverse.
It would be functional the same as specifying "WEB-INF.cftags.components" - just formalized.
I was also going to suggest your #2, automatic var scoping of local function variables. But i chickened out at the last minute. ;) I don't know the language inside and out so thoroughly that i can think thru all the consequences properly.
Nevertheless, from my little corner I think it makes MUCH more sense to have to manually specify variables-scoped variables. This way, it's immediately obvious if you forget (whoops, that variable isn't defined ... why not?), instead of the consequences being hidden. In my mind, it seems to be a mistake that it was done that way and should be fixed.
In addition to developers not being aware of this hidden issue, it's also hard to remember each and every time.
If backwards compatibility is a big concern of the CF product team, and maybe it should be, then i can envision a setting that would allow a developer to switch the default behavior from "auto var scoping" back to "manual var scoping", if they want to, rather than clean up their code.
Small thing, but it would make a big difference on the ground.
Strong typing and interfaces need not necessarily go together. You can still have interfaces in a dynamic, weakly-typed language such as CF to provide a blueprint or contract for implementing functionality. Think of it this way... interfaces allow one class to "inherit" from multiple "abstract classes" in a language that doesn't allow traditional multiple inheritance... although you only get methods, not properties or constants.
The arguments against strong typing just don't apply to interfaces. Asking for strong typing in CF is silly because it'd break backwards compatibility with everyone's CF code base. On the other hand, it looks as though interfaces could easily be added to the language without impacting anyone previously written code. Interfaces wouldn't inhibit you in any way... if you don't like them or don't see their value, just don't use them. Simple problem, simple solution!
With that said, the portions of discussion about CFC future features are spot on. I 2nd, 3rd, 4th, whatever the call for a true constructor and cleaning up the variable scoping. The 'crossing of variable scope' or searching various scopes as CF does has always bothered me as it tends to inject more errors than fix them. Personally, I would like to see method overloading allowed as well.
Think about it this way: lets say I want two versions of foo(), one that accepts an integer and a string and one that accepts two strings. What happens if I do this:
foo("3", "test")
Which version is called? If CF decides a variable's type according to its value it would consider the first argument numeric, but what if I actually *wanted* to pass the string representation of 3?
Without strong typing I don't see how method overloading could be implemented properly.
If the consensus is "use duck-typing", then CF needs to provide another way for me to specify the contract inferred by that argument or returntype. It needs to be part of the language, not on some sheet of paper. Those that work in a distributed enviroment with team members that come and go know exactly why interfaces/contract programming are generally a good thing. Those that work on small projects in a silo probably do not. I do both, and for the small projects, there's no need for anything like an interface (consider the concrete class the contract and you're done). For large projects, being able to implement an interface and KNOW that I didn't break any of the thousand or so dependencies is quite nice.
Method overloading is great for maintenance b/c you can overload a method by adding a parameter, thus changing the type signature, and just have to test the new method. This ensures backward compatibility and prevents the need for regression testing since the original method hasn't been touched.
I just feels like there should be some middle ground out there b/w strongly typed and no type and since CF appears to be in this world today why not actually finish the job.
There are times also when I want method-overloading. You can do clumsy work arounds by having a parent method to a number of child methods that handle the individual function handling, but this is clumsy at best. This is the method I am using for my ColdFusion Humane Interface Package (inspired by Python & Ruby), but the more I play with it the less I am not so sure about it. But I don't know of any other way to do what I am trying to do.
We don't have the ability to create code on the fly unless we write to disk (something ColdSpring AOP does, as well as several of the new ORM frameworks). Perhaps that could be more convenient but the write-to-file-then-invoke method works pretty well (assuming you're creating new objects once per application, not once per request).
Overloading is not really feasible in a dynamic language - overload resolution would have to happen at runtime and it's effectively an O(n*m) algorithm (for n arguments and m candidate methods). Besides, since you can manually test at runtime what type an argument is, you can always have a method that takes type="any" and dispatch internally based on the actual runtime type of that argument.
NULL. If you use duck typing, you don't really need NULL since you can call isObject(obj) which will return false if obj is 0 or "" or whatever you want to use for NULL. With a real NULL you'd still have to test (obj is not NULL). The only benefit of NULL would be the ability to still specify returntype="component" rather than returntype="any". Given the rest of this discussion, I'd categorize that as syntactic sugar.
Constructors. Huh? If you work with Java objects in CF, you have to explicitly call init() to invoke constructors that take arguments. Why not just continue to use init() in CFCs? What would "real constructors" get you that init() does not? Pure syntactic sugar!
Auto-var-scope. OK, this is a good one. I agree that it would be nice to somehow be able to tell the compiler that unscoped variables should automatically be declared 'var' instead of defaulting to 'variables' scope. It would need to be a "compile-time" flag and probably on a per-file basis so you could mix'n'match old and new code without breakage. Perhaps a cfprocessingdirective flag?
For a while I was using a setup function and then a configure function to "construct" my CFC objects. Then I stumbled across a blog post about using init() and discovered that's what many other developers are doing.
If constructors become a standard part of CF then we can avoid confusion among developers and also ease the transition for the hoards of Java and .net programmers migrating to CFMX development.
If the constructor method has the same name as the Component, then the existing code base that uses init() would still work.
Also, for all those CFC's that currently don't have a constructor CF would just add a default empty constructor. Those all the existing CFCs should work.
WIth Java, you can call new Object(param1,param2), so you're STILL calling a method. CF has no such technique... createObject() is it... and since Java requires you to import any class you're going to instantiate anyway, it conflicts with the whole concept of runtime binding. You're free to name the method the same as the object instead of init, but there's no practical non-hack way to make this work.
So runtime binding and createObject/cfobject make it impossible for CF to have "genuine" constructors (although an argument could be made for init() BEING a genuine constructor, at least by convention). The limited concept of type make overloading nearly impossible. The fact that CFCs are loosely bundled structs-on-steroids make abstract classes worthless unless you're going to parse a lot of text.
Where does that leave us?
Or a better, more relevant question: How do you propose implementing "genuine constructors" in CF? Under the current circumstances, it's impossible... so how do you make them work?
Bruce / Nando, feel free to respond to Jared, Brian and myself on this one - I just can't see any benefit to changing how "construction" is handled since today CF and Java objects are treated so similarly.
Also bear in mind that New Atlanta introduced a cfconstructor tag but then later dropped it because there wasn't any worthwhile benefit.
My CFC named Foo has a constructor method named foo () with arguments firstName and lastName
Using <cfinvoke> method attribute is given the value of foo, the returnvariable is the name for my CFC object since foo() returns a reference to a Foo object. I can use method arguments, the argumentCollection, or the <cfinvokeargument> to pass the values to my constructor arguments.
Using <cfobject> tag all CF would need to add would be an optional argumentCollection attribute, the constructor would be called by default and be passed the argumentCollection.
Using createObject again CF would need to add an optional argumentCollection attribute. The constructor method is called automatically and passed the argumentCollection.
I don't see any of the above as a hack.
My key reason for proposing constructors be added to CF is to standardize in the language how CFC objects are created and how their properties are provided initial or default values.
Most developers have realized the need for a constructor method so why not make it a documented feature of the language?
The number one CFMX book (Ben Forta's CMFX 7 Web App Construction Kit) doesn't even mention using init() in its chapter on CFCs (chap 23) since it's not a documented feature of CFCs. Thus most developers learning CFMX and CFCs don't start out using init(). Maybe they discover this "practice" or maybe (like me) they come up with their own work around.
Having a standard, documented constructor feature for CFCs helps all developers learn the same techniques and leads to better code reuse.
Of course Im not a CFMX expert, but I did stay at a Holiday Inn Express last night :).
See my post above on how I'd implement constructors in CF.
As for your argument that CF should not add constructors because we have to call init() when creating a Java object and we want object create (either CFC or Java) to be similar -
CF adds an optional argumentColletction to createObject. The argumentCollection is passed to an appropriate constructor defined in the Java class. If no argument Collection is provided, createObject automatically calls the class's default constructor.
Thus, how I create a Java object or how I create a CFC object remains similar.
BTW, since "init()" is expected to return "this", you can do all in one object creation *and* initialization (aka construction) by simply calling "init()" instead of using createObject() / cfobject:
[cfinvoke component="Thing" method="init" argumentCollection="#myConstructorArgs#" returnvariable="myObj"]
That's the same as setting myObj to createObject("component","Thing") and calling init(argumentCollection=myConstructorArgs)
BTW, what AS has are type <em>hints</em>, not types.
More importantly, I'd like the constructor to be called automatically when an object (CFC or Java) is created and also allow argument values to be passed into the constructor.
I can think of one reason, I suppose... createObject(), cfinvoke, and cfobject don't involve themselves with the specific workings of the objects, they're just tools to access code other than CFM files... so involving them in the details of instantiation is outside the scope of their current responsibilities. Once you give CF the priviledge of dictating the content and structure of your objects, though, you start to restrict the usability of your platform. That creative expression is what I love about CF and the lack of it is what I hate most about Java... and I balk dreadfully at the thought of making CF more Java-like.
Incidentally, I already use init(argumentCollection=someStruct) to pass a whole collection of arguments in... so adding it to createObject() saves you 7 characters and gives CF the privilege of controlling things it doesn't need to, dictating programming style and enforcing the way my objects work for me. It causes CF to do things behind the scenes that obfuscates how things work (which makes it even harder for noobs). And it breaks with how the whole process works from the very foundation of the CFC concept.
Plus it's been tried and failed to be useful in the case of BlueDragon.
I just remain unconvinced. It might be handy for you, but for the platform, the language, and in the overall scheme of things, I can't see it being a terribly good thing... but feel free to keep trying to convince people, maybe you'll hit on something.
Laterz!
Note however that the way Java objects are handled is subtle: createObject("java","SomeClass") does *not* call the default constructor; createObject("java","SomeClass").init() *does* call the default constructor. This is to allow Java classes to be loaded and manipulated (e.g., accessing static methods) without forcing construction. In particular, you do not want to call *both* the default constructor and a specific constructor:
createObject("java","SomeClass").init("foo")
that should be equivalent to new SomeClass("foo"). It's hard to reconcile createObject("java","SomeClass") automatically calling the default constructor (e.g., new SomeClass()) which is what you are asking for with the backward compatibility of calling a specific constructor.
Note also that if you do not explicitly call init() on a Java object, the default constructor is called automatically by CFMX the first time you try to access an instance method. In other words, CFMX defers construction to either (1) a call to init(), optionally with arguments or (2) the first instance-based use of the object.
I don't think constructors as you envisage them can be implemented without breaking that backward compatible guarantee (so I don't think 61875 will ever be implemented).
And a bit redundant :)
Ditto... there's all sorts of reasons this is a bad idea, and the reasons are starting to troop into my head. :) I like when that happens.
CF doesn't work like Java. In CF you can create an object without instantiating it, which is incredibly powerful for doing method injection, introspecition and stateless objects. It's how CF gets around the lack of static vs instance methods... createObject() doesn't do anything but read the CFC and prepare for calling methods on it... whether it becomes an instance of that class or is just used as having static methods is up to the developer.
People rant and rave about not using frameworks because of "the overhead" (which is pretty silly anyway) but when it comes to introducing "features" which absolutely add extra processing to CFCs, it's all good. Bruce, it may be good for how YOU use CFCs... but CFCs are so far beyond anything Java can do and restricting them to simple instantiation/method calls is selling them way short.
Think of this: createObject() creates a usable object in memory, and some methods require instance data while others do not. If I want to createObject("component","addition").add(2,2) and have it work, then having createObject() first call a constructor is a total waste of clock cycles. I'll grant you that's an extremely simplified example, but there are many out there that are more complex and yet just as true.
Just a few more thoughts... :)
Since I do both CF and Java development (and love both languages) please explain..
"but CFCs are so far beyond anything Java can do and restricting them to simple instantiation/method calls is selling them way short"
Hadn't considered the static method angle. However, I don't thinkt that the CFC methods are really static methods (otherwise they could not access instance fields [ variables or this scope ] ).
What if the <cfinvoke> tag just created the CFC object using a default constructor and then called the method - similar to how it works now. I could still call any method I wanted without concern about object instantiation.
I think CF is really creating a an object and calling the method, then dumping the object when you use <cfinvoke>.
Since a static Java method can be called using an object reference, having createObject call the default constructor and then call the static Java method doesn't break anything.
Bruce
tmp = createObject("component","TheComponent");
tmp.someMethod();
Now, one thing nobody has pointed out in this thread is that createObject() (and cfobject) both actually do execute the "default constructor" - what is more usually called the pseudo-constructor.
Any code inside the cfcomponent tags but outside any cffunction tags gets executed automatically when a CFC is created.
In other words you can already do exactly what you want:
[cfcomponent]
... write your default constructor code here ...
[cffunction ...] ... [/cffunction]
...
[/cfcomponent]
Then when you call createObject() (or cfobject) that inline default constructor code will be executed automatically.
As for static methods, I'm talking about Java, not CFCs. But the point is that you do not want the behavior to be gratuitously different between how CFMX handles Java objects (deferred calls to the default constructor, or explicit init() calls) and how it handles CFC objects.
I can't help thinking that some of the requests being made for "Java-like" features to be added to CFMX stem from a lack of understanding of some of the power of a dynamic language (CFMX)...
(be warned, ithe pseudo-constructor code is also executed if you use the CFC Explorer since that has to create an instance in order to get the metadata to display)
I guess it's just a matter of them being distinctly different animals, CFCs and Java classes. CFCs allow you to do all sorts of creative things, like adding attributes to the cfcomponent tag and then accessing them thru getMetaData(myInstance) (which I've been working on as a way to create "interface definitions" in CFCs, btw) and treating methods as struct keys (which enables Behavior Injection where you actually inject the method into the CFC), accessing the default local scope from within a running function (via the PageContext object)... in other words, if you can come up with a viable reason to use any given technique there's almost nothing you can't do with CFCs.
A CFC is a base class composed with separate classes for each "method" which are basically UDFs. Based on observation, it looks like an instantiated CFC is basically a page context that hosts 3 other page contexts... super, this and variables. "THIS" is actually available from within variables by a default struct called THIS (so variables.this.something works the same as this.something) and, since there are no rules about typing other than content-type checking you can literally do ANYTHING (including cfreturning cfcatch as a struct from an error, or setting a method as a property on another method, or...)
So a CFC bears almost no relationship to a Java class other than the fact that they're both OO constructs that handle polymorphism, encapsulation, and inheritance.
That's what I meant. :)
HTH...
Without interface - cffunction name="SomeFunc" cfargument name="arg1" type="WEB-INF.cftags.component" required=true Do all validations about methods in arg1, their arguments and data types /cffunction
With interface - cffunction name="SomeFunc" cfargument name="arg1" type="SomeInterface" required=true No need to perform validations on methods in arg1, arguments and types /cffunction
So you can either choose to do all validations about methods of the component yourself or leave it to the language to do that.
Of course, there are other advantages of the interface. By requiring interface data type of an argument, you, as a framework developer are sure that your method is not called unless component passed to your method implements all the methods you expect. Without interfaces also you will get error about non-implemented functions, but you come to know that within your function, may be after performing some operations on the component. With interface, object creation will fail if it does not follow the contract - which means that you will find about missing method much earlier, not later in your function.
Interfaces will let you associate multiple and different behaviors with the component by allowing multiple inheritance. Good example is Serializable in Java. By implementing this interface you all the object to be serialized.
Interfaces also communicate required contract to the developer very concisely. You don't need verbose document about what the user of your program should do.
In your example, interfaces would give you a runtime error that "argument 2 does not implement interface foo" at the calling site, for example. Without interfaces, any attempt to use the argument in a way that the argument didn't support would give you a runtime error that "method bar not found in arguments.obj" at the use site. Either way, you get a runtime error.
I'm also not convinced the interface error is likely to be able to give better debugging info than the use error...
Interfaces make a lot of sense in a statically typed, compile everything first language (like Java, C#, C++) but they make a lot less sense in a dynamically typed, compile at runtime language (like ColdFusion).
aCfc = CreateObject("component", "CFC1"); foo(aCfc);
if CFC1 does not implements all the methods in CFI1 properly, CreateObject will fail. So 'foo' will not get called with invalid component.
Also, as I mentioned earlier, you don't have to perform validations like if CFC contains a method, that takes perticular arguments of perticular type etc.
Should we as developers in practice use the concept of an interface? I my opinion yes. Using the concept of an interface provides a clear contract between a class and its subclasses which is a good thing. It's really no different than implementing a design pattern. Maybe just call it an architect pattern that you can choose to (or not to) use.
But CF **isn't** a strongly typed language, which means we can't evaluate it using the same metrics as we do Java or C++ or others.
This discussion IS NOT about which is better: dynamic typing or strong typing. Its about whether or not interfaces should be added to CF *even though* dynamic typing and late binding means they will be a documentation tool more than anything else.
I don't see a lot of ADDED value between saying method foo implements bar versus adding a hint to foo that says "Passed object must implement a bar1() and bar2() method".
If the feature were there I would use it but I don't think its critical by any means.
The strong type fanatics simply want interfaces. If ColdFusion had interfaces, then the init() constructor could be forced by requiring that method in the WEB-INF.cftags.component. I say, give them interfaces, maybe the disscussion can then turn to more about how to accomplish dynamic typing in ColdFusion.
Take a look at the BIG names in the ColdFusion community. For a few years (or least since CF MX 6) both Sean and Hal have been big proponents of interfaces and the biggest voices for it for a long time. Now they see a different possibility. So now all us strong typers should take a minute, get into the zen of it, and see what the possiblities are of dynamic type and how to do it in ColdFusion.
The more techniques you learn, the more rounded and better programmer you are. Even if you prefer strong typing over dynamic typing. After you would want a surgeon operating on you with tools and techniques of the 1970's would you?
I think this has been a very interesting discussion. It's clear that a significant number of people feel strongly that interfaces would add value to ColdFusion and if interfaces were added those folks would then be able to evaluate whether or not the added value is real. There are also a significant number of people who are happy with the status quo and are comfortable pursuing a more dynamic approach to typing.
ColdFusion is already a general purpose, multi-paradigm language, allowing all sorts of applications to be built in either a procedural style or an OO style or some middle ground. Adding interfaces would increase the paradigm range without negatively impacting those folks who aren't ready to use them (or who wouldn't want to use them).
Thanx for all your input and I would strongly encourage the "strong-typing / pro-interface" camp to explore the broader possibilities of dynamic programming if they haven't already...


