Inline Components

Hi all

I wonder what you all think about the ability to create components inline?

Something like in person.cfm you could create the class/component (whatever :

    <cfscript>
      Person = new Person();
      Person.setName("Mark");


      component name="Person" accessors="true" {
        property name="name";
      }
    </cfscript>
1 Like

Yes and no. Yes for being able to provide inline implementation to interfaces/abstract classes like java. Also I would like to see member classes like java.

But being able to do the example you give could get very tricky and messy. If you define a new type (component/class/interface) in a CFM file, does it become available outside the scope of that CFM? IE, can you define it in one CFM and instantiate it in another? If not it’s useless. If so, do you have to include the CFM before you have access to that type? How is the package determined? Are you going to need to introduce a namespace syntax to prevent name collisions? It’s a can of worms to me, outside the boundaries I listed above.

1 Like

You could instantiate it and return the type from inside of the CFM / CFC that it is in - effectively making it private. Think anonymous components just like anonymous functions.

Which is not to say there wouldn’t be value in it being available for instantiation from the outside - im not sure - but like you, im not sure how that would work.

I have written a few different libraries where it would be useful to have a component that only exists in my library - its never intended to be used outside of that context. This would be a good way to signal that and protect it.

Overall im for the idea, although it does need some work to figure out all of the details. I dont like name="" being how you define the way its called - what do you think of something like this?

person = component accessors="true" {
    property name="name";
}

Yeah, this is better for inline use, I think:

person = component  {
    // stuff here
};

So it’s like a component expression instead of a component statement. And accordingly, it follows variable scoping rules like any other variable. Also note - for Mark - you’d need to have your component expression before you use it, obviously. This would not be the case for a component statement. I think doing it as an expression makes it more obvious how it would work?

There a different potential requirement for inner classes (which conceptually could only work within another class), and the operational rules for those would perhaps better befit following Java. That said: they’re only tangentially related to what we’re discussing here.


Adam

First off, I want to put this disclaimer out there - I originally liked the idea behind Mark’s suggestion. I even re-raised the issue on the Lucee issue tracker. It is recently (today, honestly) that as I thought about it, I saw these problems with it.

On one hand, it is a cool concept, but here’s what I see. It does make CFML more like ECMAScript - especially the component expression. However, ECMAScript seems to be working to get away from the very direction this would take CFML, specifically with their module loading system. CFML already has a good class loading system, that automatically namespaces things based on directory structure. Modularity can be achieved by LAR’ing your components.

In any case, I do think it would encourage poor coding practices. Instead of component declarations being in their logical locations, they are spread out all through your code. A maintainer could have one heck of a time finding where components are located. Good luck documenting that too.

Contrast that with this:

Here is an example of what I mean by this:

// /types/IPerson.cfc
interface {
    public void function speak();
}

// index.cfm
<cfset person = new types.IPerson() {
    public void function speak() {
        writeoutput("what would you like me to say?");
    }
}>
<cfset person.speak()>

The difference here is I have a one-off instance that does any custom stuff I need, without breaking the type validation/classloading system. If you combine that with the concept of the instance employing closures here, you have something powerful IMO.

Instead of responding back with great or non-great ideas of why it’s great or shit, let me ask @markdrew the question WHY he’s suggesting it.

I’m sure there’s more than “just because we can” behind it — what problem would it solve for you, Mark?

The original idea come about when I was doing a one off script that will get some data, check some stuff and write a response. It’s a script. Not going to become an app so I dont have to “science the shit out of it

As an aside, I tend to see parsing docs in the sense of
a) Pass data to object
b) Ask object to return a particular part of it
c) Profit

So in the script I could have just created it in a REPL and done my work and be done with it. But I had to create a new file, (I know, such labours) but with that it exited the REPL scenario. And it wasn’t a nice little script to do X.

In Java you CAN define inline objects, but they have to implement another class which in CFML is useless and un-required. Interfaces work in IDE’s and compile time, and CFML has neither of those.

I like @adam_cameron’s suggestion, which is how I should have gone about it before, so it’s more closure type (and of course only available after instantiation, which is fine)

I also like the idea of being able to have inner components/classes within CFC’s . I can see use-cases, for example the base components , such as HTTP and Query, in lucee all need a Result object. It is never used by anything else and is 100% only related to that component. No one should be calling or using it (ok, it’s consumed when returned, but that is another story)

With regards to access: it should be limited to the file they are created in basically.

With regards to making code messier: pfft. Too late. People will manage to make messy code out of anything.

Other usecases I can think of are of overriding classes at runtime (you can do that already of course) but it would be a nice feature to see the whole code within one editor window.

An example (from where I had this idea from):

<cfscript>
//Parse incoming requests
Reqs = DirectoryList(Expandpath("."), false,"array", "*.json");

for(f in Reqs)
{
  result = new component(Fileread(f)) accessors=true {
                property name="result";
                function init(result){
                        this.result = DeSerializeJSON(arguments.result);
                        return this;

                }                 
                function getUserName(){

                        return this.result.pull_request.user.login;

                }
                ...
            };
            
    username = result.getUserName();   
    
    otherPullRequests = result.getPullRequests();
    
}

//Do something with the username
</cfscript>

I hope this has helped to get some background on a simple idea.

Also with regards to the naming of the components, in opposition of @adam_cameron 's idea of inline creation, it’s the idea of being to shove all the components at the bottom and then use them as named items. In the same way you can use functions (they automatically get moved to the top at compile time), so you can create multiple instances within your script.

Anyway, just an idea.

I see the value, but to the wider community it would cause more harm than good. (mixed code everywhere) I call it ‘outsourced spaghetti’, I’ve seen a lot of apps like this in Sencha world… it’s confusing to most devs)

perhaps a great idea for an extension?