Remove support for "body constructor" in the lucee dialect

in the CFML dialect the body of the component is a argument less constructor and the “init” method are optional.

component {
    writeOutput("Hi!");// code execution when the instance is constructed!
}

In the Lucee dialect the init method if existing is always executed, so a body constructor is not really necessary.

Provided “not really necessary” still allows for config-type statements like:

  • property
  • include - for traits/mixins (until some better way of achieving mixins is established)
  • import
  • static constructor
  • direct static variable declaration (or would these then be limited to the static constructor?)
  • anything else?

Also this is slightly vague:

“the init method if existing is always executed”…

You say if it exists: so what if it doesn’t exist? Does that then imply the pseudo no-arg constructor stuff is then allowed again? I think this is a case of just being more precise with the wording here.

We only remove that the body acts as a constructor, of course you can still do stuff like properties, variable declaration and definition, functions, static constructors … inside the component body. so you end with the possibilities you have for example in Java or php.

This topic is not about the Init method, this was just stating facts about it (if there is a Init method you can be sure it is always called if a instance is produced). if you like to discuss about Init open a new topic …

If we remove support for the body constructor it makes no difference if the user has a Init or not.

I was quoting you and asking for clarification. You said this:

In the Lucee dialect the init method if existing is always executed

If you say “if existing”, then that implies there’s two possibilities: it exists; it doesn’t exist. I was asking what the story is in the “false” case.


Adam

We only remove that the body acts as a constructor,

Cool.

I think it would be helpful if in general you more accurately define what you mean in situations like this. IE: define exactly what you mean. Not in narrative, nor with statements starting “of course…”, but some sort of formalised (and more important: unambiguous, and free of linguistic vagaries) description.

So something like this (I’m making this up, don’t pay attention to the detail).

The following statements will be fully supported:

  • property
  • import
  • etc

The following statements would be supported with restrictions:

  • include - provided file files only include function definitions
  • variable assignment, provided they reference static values
  • etc

The following statements are illegal and will cause a compilation error etc

And also provide detail as to whether it would cause a compilation error, a runtime error, or the code would simply be ignored)

What about tags?

I don’t mean just in the context of this particular issue, but in general. of course you can still do stuff like properties, variable declaration and definition, functions, static constructors … inside the component body. so you end with the possibilities you have for example in Java or php.

Also not drawing ambiguous similes, but emphatic statements. Let’s not worry how Java or PHP might do it. Let’s dwell on what your intent for .lucee would be.

For one thing, I don’t think Java allows traits/mixins, but PHP does. CFML has no formal treatment, but then can be achieved with an include and some self discipline.

Obviously saying “Ruby does this cool thing like this [example]. We could do a CFML version like this [example]”. Actual concrete.

I think this makes sense.

Making things behave in obvious manners always helps.

How would this affect the Application.cfc though? There is a lot of init stuff happening in the body of the component. Would this need to be moved to an init method?

Very good argument! I see a lot that people are confused that variables defined in the this scope have no affect before the body constructor is executed. That would speak for the Init this would solve this confusion. I will rewrite the fw/1 application.cfc file to have the code in the Init and attach here, so we get a feeling for it. Btw I’m not even sure if a Init method from a application.cfc is called.

Again, in documentation, having properties makes sense, but if you have
OnApplicationStart, but you ALSO have init() in Application.cfc that would make a bit more sense. You could then somehow (let’s leave the details aside for the moment) pass in a config object to the Application.init()

component {
 function init(config){
 ...
 }
}

EDIT: Actually, thinking about it, the web/server config should be what is passed into the init(config) by default, so you get all the configuration options that are set. Maybe a readonly object, since it is passed in once.

Hmmmm, interesting…

I was half way through implementing mixins in FarCry Core and it was necessary to make use of the body constructor because of the fact I couldn’t rely on .init() (chicken and egg situation I know), but at the same time it was syntactically appealing to be able to make use of the body constructor. Roughly it would look something like this;

component extends... {
  property name="title" seq="1"... ;
  property name="teaser" ... ;
  property name="body" ... ;

  mixin(typename="mixinSEO", seq="100");

  property name="publishDate" seq="200" ... ;
  property name="bComments" ... ;

The alternative is to move the code into init() and I’d be fine with that if init() is always run (as in the case of .lucee) :smile:

(As a side note, in Railo 4.2 when you place code in between the properties either one of two things is happening: the properties after the call to mixin() aren’t being added to the component metadata, OR when I’m modifying the properties in the component metadata inside mixin() it’s causing the remaining properties to not be added – just haven’t had a chance to write a test case to see which is true!)

1 Like

Speaking of converting existing code to .lucee, there could be a number of situations where <cfinclude> was previously used in the body constructor to include code/methods in components. This might be a little tricky to convert if the body constructor is removed, but it’s probably a good lesson in writing better code :slight_smile:

I know FarCry Core does this in the application.cfc in an attempt to keep the application scope settings in it’s own file – possibly not the most elegant solution, just that it’s been this way for many years.

Personally I never wrote code that did anything within the body constuctor. I always thought it is a very bad practice and discouraged collegues also from doing so.

So my opinion is also to remove body constructor support.

After all, you have to do breaking changes to move forward.

1 Like