Better constructors for Lucee

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and ran
into some issues with the way CF instantiates its objects. Especially on a
framework level, where you provide CFCs for instantiation or subclassing
and have no guarantee, how the people are using your classes. When I looked
into the Java constructor specification, I realized that it is a very
robust definition that avoid every little issue I ran into. So I tried to
translated the spec to CF, solve the backward compatibility issues and
provide a robust long-term solution. I hope this is a good time and place
to share it.

In OO languages it is almost a standard to have a special method, dedicated
to the object creation - the constructor. In CF the closest thing we have
is the pseudo constructor, whereas the init method is mainly treated as a
normal method. Only the new operator partially treats init as a constructor
(but new does not call super.init() automatically). I would love to have
more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method, or
      try to assure it programmatically.
      2. The instantiation of a CFC should not depend on how the class is
      created at runtime. The instantiation should be the same, no matter how the
      class is created.
      • The init method and the init methods of all base classes should be
        called under all circumstances, not matter if you use new, createObject,
        cfobject or cfinvoke.
      1. It should not be possible to call a constructor multiple times,
        this just inflicts unnecessary problems.
      • When I program CFCs that are used by others, I tend to avoid that
        programatically. It should not be necessary.
      1. The init method should always return the instance.
      • As init can return something else, I tend to specify the return
        type (for clarity), which adds an unnecessary type check at runtime.
      • The return this; should not be necessary (as in ACF).
    1. It should not be possible to concurrently call the constructor.
    • It is theoretically possible and I wasted time thinking about it.
      6. You should be able to enforce the behavior off your CFCs.
      • With the final keyword and a guaranteed constructor call, you can
        control the behavior of your CFC pretty well, even if the class is extended.
      1. A programming language that is easy to use an to learn, should: be intuitive,
        provide good error messages and have a good documentation
        . Those 3
        points are not true for constructors in CF (in my opinion).
    1. The problems above make it more difficult to provide high software
      quality (e.g. in OS frameworks, tools, libraries).
  5. Specification

    1. Constructors can not be overridden.
    2. super() calls the constructor of the base class.
    3. If super() is not defined in the constructor source, the compiler
      adds it on top of the constructor source.
    4. If the super() call (without arguments) is not possible - because
      the base constructor has at least 1 required argument (without default
      value) - the compiler throws an error.
    5. Constructors do not have a return value.
    6. If no constructor is defined, the compiler adds the standard
      constructor
      : function init(){ super(); }
    7. Constructors can only be called once.
    8. (It is guaranteed that) constructors are called on instantiation.
    9. Constructors can not be defined in an included .cfm.
      • As constructors are a compile time feature, I guess dynamic
        includes would cause problems.
    10. getComponentMetaData() and other reflection methods do not call the
      constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in Lucee
      (which is false) - while ACF does not.
    1. Access modifiers can be: remote, public, package or private.
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.
    1. Access modifier public is default and can be omitted.
    2. Pseudo constructor (the source code outside of the functions).
    3. Either pseudo code is not allowed anymore (clean approach),
    4. or it is called prior to the constructor.
    5. Lucee.cfc does not call super().
    6. Syntax (the compiler must be able to detect the new syntax to
      provide backward compatibility for the old syntax: function init()).
    • If a new constructor is present in a CFC the compiler and the CFC
      instance must honor this spec.

    • If it is not present, everything should behave backward compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.
    1. Execution order
    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor uses
          a method that can be overwritten in subclasses. So I guess in Java it is
          possible to use a method in the constructor that is overridden at runtime.
        • With the final keyword in Lucee 5, every developer can decide
          to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

    1. 2. make base methods available and override base+1 methods
      3. make methods available and override base methods
      4. …
      5. make base properties available and override…
      6. make properties available and override…
      7. …
      8. call base pseudo constructor (see 13.2)
      9. call pseudo constructor (see 13.2)
      10. call constructor (which calls super() as specified)
      17. Object creation
      1. new Foo() - creates the instance and calls the constructor as
        defined in 16.
      2. createObject(“component”, “Foo”) - creates the instance and
        calls the constructor
        as defined in 16.
      3. - creates the instance and calls the constructor as
        defined in 16.
      4. - creates the instance and calls the constructor as
        defined in 16 and calls the method specified.
  6. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the spec.
    • Inheritance between CFCs with old and new constructor should work well.
      • Most important is, that CFCs with the new constructor can extend
        CFC with the old init constructor.

What do you think?

Great post! Please see my comments between the lines.

Micha

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and
ran into some issues with the way CF instantiates its objects. Especially
on a framework level, where you provide CFCs for instantiation or
subclassing and have no guarantee, how the people are using your classes.
When I looked into the Java constructor specification, I realized that it
is a very robust definition that avoid every little issue I ran into. So I
tried to translated the spec to CF, solve the backward compatibility issues
and provide a robust long-term solution. I hope this is a good time and
place to share it.

In OO languages it is almost a standard to have a special method,
dedicated to the object creation - the constructor. In CF the closest thing
we have is the pseudo constructor, whereas the init method is mainly
treated as a normal method. Only the new operator partially treats init as
a constructor (but new does not call super.init() automatically). I would
love to have more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method, or
      try to assure it programmatically.

The problem here is historical, coldfusion 6 indroduced components but
without the new operator and no init method.
Later (version 7,8,9?) added support for the new operator and init. But for
backward compatibility the old way to instantiate components make no use of
this new pseudo constructor.
In Lucee 5 we deprecate the function createObject,cfinvoke and cfobject, so
change this functionality makes no sense anymore, best avoid them.

  1. The instantiation of a CFC should not depend on how the class is
    created at runtime. The instantiation should be the same, no matter how the
    class is created.
    • The init method and the init methods of all base classes should
      be called under all circumstances, not matter if you use new, createObject,
      cfobject or cfinvoke.

Make sense, we need to think about this with the new dialect.

  1. It should not be possible to call a constructor multiple times,
    this just inflicts unnecessary problems.
    • When I program CFCs that are used by others, I tend to avoid that
      programatically. It should not be necessary.

Problem here is that if you load the component via createObject you call
init after construction

  1. The init method should always return the instance.
    • As init can return something else, I tend to specify the return
      type (for clarity), which adds an unnecessary type check at runtime.
    • The return this; should not be necessary (as in ACF).

The return type is not necessary! Lucee acts exact the same as acf here

  1. It should not be possible to concurrently call the constructor.
  • It is theoretically possible and I wasted time thinking about it.
    2. You should be able to enforce the behavior off your CFCs.
    • With the final keyword and a guaranteed constructor call, you can
      control the behavior of your CFC pretty well, even if the class is extended.
    1. A programming language that is easy to use an to learn, should:
      be intuitive, provide good error messages and have a good
      documentation
      . Those 3 points are not true for constructors in CF (in
      my opinion).

In my opinion the best way is to deprecate createObject, cfinvoke
,cfobject and remove the. For the doc .

  1. The problems above make it more difficult to provide high software
    quality (e.g. in OS frameworks, tools, libraries).

  2. Specification

    1. Constructors can not be overridden.

What you mean with this?

  1. super() calls the constructor of the base class.

+1

  1. If super() is not defined in the constructor source, the compiler
    adds it on top of the constructor source.

+1

  1. If the super() call (without arguments) is not possible - because
    the base constructor has at least 1 required argument (without default
    value) - the compiler throws an error.

Problem is the compiler cannot decide this, Lucee is not a static language
like for example Java, things like this need to be decided at runtime.

  1. Constructors do not have a return value.

It was that way in earlier version, we changed that for comaptibility to
acf, but this should be the case for the new dialect

  1. If no constructor is defined, the compiler adds the standard
    constructor
    : function init(){ super(); }
  2. Constructors can only be called once.
  3. (It is guaranteed that) constructors are called on instantiation.

Init is called after construction, changing this could break existing
code, the body of the component it the only real constructor.

  1. Constructors can not be defined in an included .cfm.
    • As constructors are a compile time feature, I guess dynamic
      includes would cause problems.

You cannot turn Lucee in a static language, I strongly disagree on this

  1. getComponentMetaData() and other reflection methods do not call the
    constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in
      Lucee (which is false) - while ACF does not.

No this methods are not producing a instance of the component

  1. Access modifiers can be: remote, public, package or private.
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.

Lucee 5 indroduces the keyword static, with that the modifier private
makes a lot of sense, for example to do a singleton
Component {
private function init(){}
Public static getInstance(){if(isnull(static.instance))static.instance=new
Test(); return static.instance;}

  1. Access modifier public is default and can be omitted.

  2. Pseudo constructor (the source code outside of the functions).

    1. Either pseudo code is not allowed anymore (clean approach),
    2. or it is called prior to the constructor.
  3. Lucee.cfc does not call super().

  4. Syntax (the compiler must be able to detect the new syntax to
    provide backward compatibility for the old syntax: function init()).

    • If a new constructor is present in a CFC the compiler and the CFC
      instance must honor this spec.

    • If it is not present, everything should behave backward
      compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.

+1

  1. Execution order

    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor
          uses a method that can be overwritten in subclasses. So I guess in Java it
          is possible to use a method in the constructor that is overridden at
          runtime.
        • With the final keyword in Lucee 5, every developer can
          decide to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

  2. 2. make base methods available and override base+1 methods
    3. make methods available and override base methods
    4. …
    5. make base properties available and override…
    6. make properties available and override…
    7. …
    8. call base pseudo constructor (see 13.2)
    9. call pseudo constructor (see 13.2)
    10. call constructor (which calls super() as specified)
    2. Object creation

    1. new Foo() - creates the instance and calls the constructor as
      defined in 16.
    2. createObject(“component”, “Foo”) - creates the instance and
      calls the constructor
      as defined in 16.
    3. - creates the instance and calls the constructor as
      defined in 16.
    4. - creates the instance and calls the constructor as
      defined in 16 and calls the method specified.
  3. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the spec.
    • Inheritance between CFCs with old and new constructor should work
      well.
      • Most important is, that CFCs with the new constructor can extend
        CFC with the old init constructor.

What do you think?

You haven given that a lot of thoughts and it makes a lot of sense, I like
it and it is definitely worth consider this approach for the Lucee dialect,
we need to check what this men’s in detail to implement it.Am Freitag, 27. März 2015 schrieb Walter Seethaler :


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com
<javascript:_e(%7B%7D,‘cvml’,‘lucee%2Bunsubscribe@googlegroups.com’);>.
To post to this group, send email to lucee@googlegroups.com
<javascript:_e(%7B%7D,‘cvml’,‘lucee@googlegroups.com’);>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com?utm_medium=email&utm_source=footer
.
For more options, visit https://groups.google.com/d/optout.

In section 17, it sounds like you are anticipating always calling the
constructor.

For the new constructors, yes. The dev has the guarantee that the
constructor is called under all circumstances and doesn’t need to think
about how the class behaves if the constructor is not called. I don’t see a
use case where someone builds a class with a constructor that sometimes
needs to be called and sometimes not. Any other method could be used for
that.

new Foo(); allows you to specify arguments. What about for createObject()
and the tag-based solutions? createObject(“Foo”)()?

I only use new Foo(), even in cfml, e.g. <cfset new Foo().doSomething()>.
So I am not sure if the other variants should be deprecated or extended to
support the new constructors. My main focus is OO in cfscript based
components.

A possible solution would be a 3rd Argument for createObject() and a
initArgs attribute for cfobject and cfinvoke.

What about in cases where a compont does have a constructor, but it
doesn’t need to be invoked to access other methods, such as those that may
be interpreted as “static”?

I would say, I you have a class where some methods only work after call of
init and other methods are designed to work without init, this is not the
greatest design. The stateless methods should be refactored to its own
class which doesn’t need a constructor or the methods could be declared as
static (I think thats what you would do in Java). So no, this would not
work anymore.

I think static methods wouldn’t trigger instantiation at all and thus not
call the constructor nor the init method.Am Freitag, 27. März 2015 20:49:38 UTC+1 schrieb Tristan Lee:

On Friday, March 27, 2015 at 2:33:10 PM UTC-4, Walter Seethaler wrote:

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and
ran into some issues with the way CF instantiates its objects. Especially
on a framework level, where you provide CFCs for instantiation or
subclassing and have no guarantee, how the people are using your classes.
When I looked into the Java constructor specification, I realized that it
is a very robust definition that avoid every little issue I ran into. So I
tried to translated the spec to CF, solve the backward compatibility issues
and provide a robust long-term solution. I hope this is a good time and
place to share it.

In OO languages it is almost a standard to have a special method,
dedicated to the object creation - the constructor. In CF the closest thing
we have is the pseudo constructor, whereas the init method is mainly
treated as a normal method. Only the new operator partially treats init as
a constructor (but new does not call super.init() automatically). I would
love to have more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method, or
      try to assure it programmatically.
      2. The instantiation of a CFC should not depend on how the class
      is created at runtime. The instantiation should be the same, no matter how
      the class is created.
      • The init method and the init methods of all base classes should
        be called under all circumstances, not matter if you use new, createObject,
        cfobject or cfinvoke.
      1. It should not be possible to call a constructor multiple times,
        this just inflicts unnecessary problems.
      • When I program CFCs that are used by others, I tend to avoid
        that programatically. It should not be necessary.
      1. The init method should always return the instance.
      • As init can return something else, I tend to specify the return
        type (for clarity), which adds an unnecessary type check at runtime.
      • The return this; should not be necessary (as in ACF).
    1. It should not be possible to concurrently call the constructor.
    • It is theoretically possible and I wasted time thinking about it.
      6. You should be able to enforce the behavior off your CFCs.
      • With the final keyword and a guaranteed constructor call, you
        can control the behavior of your CFC pretty well, even if the class is
        extended.
      1. A programming language that is easy to use an to learn, should:
        be intuitive, provide good error messages and have a good
        documentation
        . Those 3 points are not true for constructors in CF
        (in my opinion).
    1. The problems above make it more difficult to provide high software
      quality (e.g. in OS frameworks, tools, libraries).
  5. Specification

    1. Constructors can not be overridden.
    2. super() calls the constructor of the base class.
    3. If super() is not defined in the constructor source, the
      compiler adds it on top of the constructor source.
    4. If the super() call (without arguments) is not possible -
      because the base constructor has at least 1 required argument (without
      default value) - the compiler throws an error.
    5. Constructors do not have a return value.
    6. If no constructor is defined, the compiler adds the standard
      constructor
      : function init(){ super(); }
    7. Constructors can only be called once.
    8. (It is guaranteed that) constructors are called on instantiation.
    9. Constructors can not be defined in an included .cfm.
      • As constructors are a compile time feature, I guess dynamic
        includes would cause problems.
    10. getComponentMetaData() and other reflection methods do not call
      the constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in
      Lucee (which is false) - while ACF does not.
    1. Access modifiers can be: remote, public, package or
      private.
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.
    1. Access modifier public is default and can be omitted.
    2. Pseudo constructor (the source code outside of the functions).
    3. Either pseudo code is not allowed anymore (clean approach),
    4. or it is called prior to the constructor.
    5. Lucee.cfc does not call super().
    6. Syntax (the compiler must be able to detect the new syntax to
      provide backward compatibility for the old syntax: function init()).
    • If a new constructor is present in a CFC the compiler and the
      CFC instance must honor this spec.

    • If it is not present, everything should behave backward
      compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.
    1. Execution order
    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor
          uses a method that can be overwritten in subclasses. So I guess in Java it
          is possible to use a method in the constructor that is overridden at
          runtime.
        • With the final keyword in Lucee 5, every developer can
          decide to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

    1. 2. make base methods available and override base+1 methods
      3. make methods available and override base methods
      4. …
      5. make base properties available and override…
      6. make properties available and override…
      7. …
      8. call base pseudo constructor (see 13.2)
      9. call pseudo constructor (see 13.2)
      10. call constructor (which calls super() as specified)
      17. Object creation
      1. new Foo() - creates the instance and calls the constructor as
        defined in 16.
      2. createObject(“component”, “Foo”) - creates the instance and
        calls the constructor
        as defined in 16.
      3. - creates the instance and calls the constructor as
        defined in 16.
      4. - creates the instance and calls the constructor as
        defined in 16 and calls the method specified.
  6. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the
        spec.
    • Inheritance between CFCs with old and new constructor should work
      well.
      • Most important is, that CFCs with the new constructor can extend
        CFC with the old init constructor.

What do you think?

In section 17, it sounds like you are anticipating always calling the
constructor.

new Foo(); allows you to specify arguments. What about for createObject()
and the tag-based solutions? createObject(“Foo”)()?

What about in cases where a compont does have a constructor, but it doesn’t
need to be invoked to access other methods, such as those that may be
interpreted as “static”?On Friday, March 27, 2015 at 2:33:10 PM UTC-4, Walter Seethaler wrote:

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and
ran into some issues with the way CF instantiates its objects. Especially
on a framework level, where you provide CFCs for instantiation or
subclassing and have no guarantee, how the people are using your classes.
When I looked into the Java constructor specification, I realized that it
is a very robust definition that avoid every little issue I ran into. So I
tried to translated the spec to CF, solve the backward compatibility issues
and provide a robust long-term solution. I hope this is a good time and
place to share it.

In OO languages it is almost a standard to have a special method,
dedicated to the object creation - the constructor. In CF the closest thing
we have is the pseudo constructor, whereas the init method is mainly
treated as a normal method. Only the new operator partially treats init as
a constructor (but new does not call super.init() automatically). I would
love to have more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method, or
      try to assure it programmatically.
      2. The instantiation of a CFC should not depend on how the class
      is created at runtime. The instantiation should be the same, no matter how
      the class is created.
      • The init method and the init methods of all base classes should
        be called under all circumstances, not matter if you use new, createObject,
        cfobject or cfinvoke.
      1. It should not be possible to call a constructor multiple times,
        this just inflicts unnecessary problems.
      • When I program CFCs that are used by others, I tend to avoid that
        programatically. It should not be necessary.
      1. The init method should always return the instance.
      • As init can return something else, I tend to specify the return
        type (for clarity), which adds an unnecessary type check at runtime.
      • The return this; should not be necessary (as in ACF).
    1. It should not be possible to concurrently call the constructor.
    • It is theoretically possible and I wasted time thinking about it.
      6. You should be able to enforce the behavior off your CFCs.
      • With the final keyword and a guaranteed constructor call, you can
        control the behavior of your CFC pretty well, even if the class is extended.
      1. A programming language that is easy to use an to learn, should:
        be intuitive, provide good error messages and have a good
        documentation
        . Those 3 points are not true for constructors in CF (in
        my opinion).
    1. The problems above make it more difficult to provide high software
      quality (e.g. in OS frameworks, tools, libraries).
  5. Specification

    1. Constructors can not be overridden.
    2. super() calls the constructor of the base class.
    3. If super() is not defined in the constructor source, the compiler
      adds it on top of the constructor source.
    4. If the super() call (without arguments) is not possible - because
      the base constructor has at least 1 required argument (without default
      value) - the compiler throws an error.
    5. Constructors do not have a return value.
    6. If no constructor is defined, the compiler adds the standard
      constructor
      : function init(){ super(); }
    7. Constructors can only be called once.
    8. (It is guaranteed that) constructors are called on instantiation.
    9. Constructors can not be defined in an included .cfm.
      • As constructors are a compile time feature, I guess dynamic
        includes would cause problems.
    10. getComponentMetaData() and other reflection methods do not call
      the constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in
      Lucee (which is false) - while ACF does not.
    1. Access modifiers can be: remote, public, package or private
      .
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.
    1. Access modifier public is default and can be omitted.
    2. Pseudo constructor (the source code outside of the functions).
    3. Either pseudo code is not allowed anymore (clean approach),
    4. or it is called prior to the constructor.
    5. Lucee.cfc does not call super().
    6. Syntax (the compiler must be able to detect the new syntax to
      provide backward compatibility for the old syntax: function init()).
    • If a new constructor is present in a CFC the compiler and the CFC
      instance must honor this spec.

    • If it is not present, everything should behave backward
      compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.
    1. Execution order
    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor
          uses a method that can be overwritten in subclasses. So I guess in Java it
          is possible to use a method in the constructor that is overridden at
          runtime.
        • With the final keyword in Lucee 5, every developer can
          decide to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

    1. 2. make base methods available and override base+1 methods
      3. make methods available and override base methods
      4. …
      5. make base properties available and override…
      6. make properties available and override…
      7. …
      8. call base pseudo constructor (see 13.2)
      9. call pseudo constructor (see 13.2)
      10. call constructor (which calls super() as specified)
      17. Object creation
      1. new Foo() - creates the instance and calls the constructor as
        defined in 16.
      2. createObject(“component”, “Foo”) - creates the instance and
        calls the constructor
        as defined in 16.
      3. - creates the instance and calls the constructor as
        defined in 16.
      4. - creates the instance and calls the constructor as
        defined in 16 and calls the method specified.
  6. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the spec.
    • Inheritance between CFCs with old and new constructor should work
      well.
      • Most important is, that CFCs with the new constructor can extend
        CFC with the old init constructor.

What do you think?

  • With the new constructor present in the source code.
    • If a method with the name init is present, it is treated as a
      normal function.
    • new, createObject, cfobject and cfinvoke honor the spec.
    • It is not possible to instantiate a CFC without honoring the spec.

And entityNew()? And especially entityNew(entity, props)?

  • Inheritance between CFCs with old and new constructor should work
    well.
    • Most important is, that CFCs with the new constructor can extend
      CFC with the old init constructor.

IIRC entityNew(entity, props) currently bypasses the setters for
properties. But you suggest setting up the setters before the properties so
that won’t work. How is that going to work when new extends old?

JochemOn Fri, Mar 27, 2015 at 7:33 PM, Walter Seethaler wrote:


Jochem van Dieten
http://jochem.vandieten.net/

Very good point, completely forgot entityNew(). Have not used it much, so I
am not sure about it. Feel free to disagree.

And entityNew()? And especially entityNew(entity, props)?

Just looked into some source codes and the ColdFusion ORM book (see Gotchas
| Constructor Arguments) to understand the current implementation. If no
init method is present, the properties are populated directly (some ORM
standard constructor?). If the init method is declared, it is called (at
least for entityLoad - so I guess the init method is called for entityNew
too). The arguments of the init method need to be optional.

In my opinion* entityNew(entity, props)* should exactly behave like new
Entity(props)
. It it just another form to instantiate a CFC - with a
different way to identify a CFC (classpath vs entity name). If the
constructor is declared, it must be used, if it is not declared the
compiler must add an ORM constructor, based on the property declarations.
Railo 4 added the implicit constructors
http://www.getrailo.org/index.cfm/whats-up/railo-40-released/features/implicit-constructors/,
which seems to be the same as an ORM constructor would be.

This is off topic and I am not sure about it, but we could even try to get
rid of entityNew(). In OO you wire classes together via classpath and
import statement. In ORM we use the entity name (which may differ from the
filename/type) to access ORM CFCs. While this is a bit handy, it adds
complexity to the language and makes the source code less clear. But again,
not sure here.
Foo function newBoo(){
return entityNew(“Boo”);
}
//Classname and entity name may differ.

  • Inheritance between CFCs with old and new constructor should work
    well.

  • Most important is, that CFCs with the new constructor can extend
    CFC with the old init constructor.

IIRC entityNew(entity, props) currently bypasses the setters for
properties. But you suggest setting up the setters before the properties so
that won’t work. How is that going to work when new extends old?

Not sure if I understood your point. Do you mean if 16. Execution order
changes with the new constructors, how that would match together with the
old execution order in case of inheritance? Could not answer it anyway, I
am not even sure how the exact execution order is right now. Whatever the
exact execution order is, it must be well documented.

This is off topic and I am not sure about it, but we could even try to get
rid of entityNew().

IIRC Adobe’s rationale for entityNew() was to provide a shorthand for the
full package name used in other ways to instantiate a component. Apart from
the obvious backward compatibility concerns, I would much rather get rid of
it in favor of explicit import statements.

  • Inheritance between CFCs with old and new constructor should work
    well.

  • Most important is, that CFCs with the new constructor can extend
    CFC with the old init constructor.

IIRC entityNew(entity, props) currently bypasses the setters for
properties. But you suggest setting up the setters before the properties so
that won’t work. How is that going to work when new extends old?

Not sure if I understood your point. Do you mean if 16. Execution order
changes with the new constructors, how that would match together with the
old execution order in case of inheritance?

Yes.

Could not answer it anyway, I am not even sure how the exact execution
order is right now.

Different from what you propose. Hence my question how this should work
when old and new are both used in an inheritance hierarchy.

JochemOn Sun, Mar 29, 2015 at 4:33 PM, Walter Seethaler wrote:


Jochem van Dieten
http://jochem.vandieten.net/

Yes, both FW/1 and TestBox do this — so it’s portable across Railo/ACF as well.

SeanOn Apr 1, 2015, at 6:21 AM, Walter Seethaler <@Walter_Seethaler> wrote:

IIRC you can use:

new “#pathToComponent#”();

Oh, yes. That works. Thanks!On Wednesday, April 1, 2015 at 9:21:03 PM UTC+8, Walter Seethaler wrote:

IIRC you can use:

new “#pathToComponent#”();

Hi Micha,

If createObject is deprecated, is there an alternative to instantiating a
dynamic object, ie.

pathToComponent = “component.utility.tools”;
obj = createObject( “component”, pathToComponent ).init();

This below throws an error:
obj = new #pathToComponent#();

Regards,
MLOn Saturday, March 28, 2015 at 5:29:26 AM UTC+8, Micha wrote:

Great post! Please see my comments between the lines.

Micha

Am Freitag, 27. März 2015 schrieb Walter Seethaler :

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and
ran into some issues with the way CF instantiates its objects. Especially
on a framework level, where you provide CFCs for instantiation or
subclassing and have no guarantee, how the people are using your classes.
When I looked into the Java constructor specification, I realized that it
is a very robust definition that avoid every little issue I ran into. So I
tried to translated the spec to CF, solve the backward compatibility issues
and provide a robust long-term solution. I hope this is a good time and
place to share it.

In OO languages it is almost a standard to have a special method,
dedicated to the object creation - the constructor. In CF the closest thing
we have is the pseudo constructor, whereas the init method is mainly
treated as a normal method. Only the new operator partially treats init as
a constructor (but new does not call super.init() automatically). I would
love to have more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method, or
      try to assure it programmatically.

The problem here is historical, coldfusion 6 indroduced components but
without the new operator and no init method.
Later (version 7,8,9?) added support for the new operator and init. But
for backward compatibility the old way to instantiate components make no
use of this new pseudo constructor.
In Lucee 5 we deprecate the function createObject,cfinvoke and cfobject,
so change this functionality makes no sense anymore, best avoid them.

  1. The instantiation of a CFC should not depend on how the class is
    created at runtime. The instantiation should be the same, no matter how the
    class is created.
    • The init method and the init methods of all base classes should
      be called under all circumstances, not matter if you use new, createObject,
      cfobject or cfinvoke.

Make sense, we need to think about this with the new dialect.

  1. It should not be possible to call a constructor multiple times,
    this just inflicts unnecessary problems.
    • When I program CFCs that are used by others, I tend to avoid
      that programatically. It should not be necessary.

Problem here is that if you load the component via createObject you call
init after construction

  1. The init method should always return the instance.
    • As init can return something else, I tend to specify the return
      type (for clarity), which adds an unnecessary type check at runtime.
    • The return this; should not be necessary (as in ACF).

The return type is not necessary! Lucee acts exact the same as acf here

  1. It should not be possible to concurrently call the constructor.
  • It is theoretically possible and I wasted time thinking about it.
    2. You should be able to enforce the behavior off your CFCs.
    • With the final keyword and a guaranteed constructor call, you
      can control the behavior of your CFC pretty well, even if the class is
      extended.
    1. A programming language that is easy to use an to learn, should:
      be intuitive, provide good error messages and have a good
      documentation
      . Those 3 points are not true for constructors in CF
      (in my opinion).

In my opinion the best way is to deprecate createObject, cfinvoke
,cfobject and remove the. For the doc .

  1. The problems above make it more difficult to provide high software
    quality (e.g. in OS frameworks, tools, libraries).

  2. Specification

    1. Constructors can not be overridden.

What you mean with this?

  1. super() calls the constructor of the base class.

+1

  1. If super() is not defined in the constructor source, the
    compiler adds it on top of the constructor source.

+1

  1. If the super() call (without arguments) is not possible -
    because the base constructor has at least 1 required argument (without
    default value) - the compiler throws an error.

Problem is the compiler cannot decide this, Lucee is not a static
language like for example Java, things like this need to be decided at
runtime.

  1. Constructors do not have a return value.

It was that way in earlier version, we changed that for comaptibility to
acf, but this should be the case for the new dialect

  1. If no constructor is defined, the compiler adds the standard
    constructor
    : function init(){ super(); }
  2. Constructors can only be called once.
  3. (It is guaranteed that) constructors are called on instantiation.

Init is called after construction, changing this could break existing
code, the body of the component it the only real constructor.

  1. Constructors can not be defined in an included .cfm.
    • As constructors are a compile time feature, I guess dynamic
      includes would cause problems.

You cannot turn Lucee in a static language, I strongly disagree on this

  1. getComponentMetaData() and other reflection methods do not call
    the constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in
      Lucee (which is false) - while ACF does not.

No this methods are not producing a instance of the component

  1. Access modifiers can be: remote, public, package or private
    .
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.

Lucee 5 indroduces the keyword static, with that the modifier private
makes a lot of sense, for example to do a singleton
Component {
private function init(){}
Public static
getInstance(){if(isnull(static.instance))static.instance=new Test(); return
static.instance;}

  1. Access modifier public is default and can be omitted.

  2. Pseudo constructor (the source code outside of the functions).

    1. Either pseudo code is not allowed anymore (clean approach),
    2. or it is called prior to the constructor.
  3. Lucee.cfc does not call super().

  4. Syntax (the compiler must be able to detect the new syntax to
    provide backward compatibility for the old syntax: function init()).

    • If a new constructor is present in a CFC the compiler and the
      CFC instance must honor this spec.

    • If it is not present, everything should behave backward
      compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.

+1

  1. Execution order

    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor
          uses a method that can be overwritten in subclasses. So I guess in Java it
          is possible to use a method in the constructor that is overridden at
          runtime.
        • With the final keyword in Lucee 5, every developer can
          decide to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

  2. 2. make base methods available and override base+1 methods
    3. make methods available and override base methods
    4. …
    5. make base properties available and override…
    6. make properties available and override…
    7. …
    8. call base pseudo constructor (see 13.2)
    9. call pseudo constructor (see 13.2)
    10. call constructor (which calls super() as specified)
    2. Object creation

    1. new Foo() - creates the instance and calls the constructor as
      defined in 16.
    2. createObject(“component”, “Foo”) - creates the instance and
      calls the constructor
      as defined in 16.
    3. - creates the instance and calls the constructor as
      defined in 16.
    4. - creates the instance and calls the constructor as
      defined in 16 and calls the method specified.
  3. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the
        spec.
    • Inheritance between CFCs with old and new constructor should work
      well.
      • Most important is, that CFCs with the new constructor can extend
        CFC with the old init constructor.

What do you think?

You haven given that a lot of thoughts and it makes a lot of sense, I like
it and it is definitely worth consider this approach for the Lucee dialect,
we need to check what this men’s in detail to implement it.


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com?utm_medium=email&utm_source=footer
.
For more options, visit https://groups.google.com/d/optout.

IIRC you can use:

new “#pathToComponent#”();Am Mittwoch, 1. April 2015 15:09:24 UTC+2 schrieb ML:

Hi Micha,

If createObject is deprecated, is there an alternative to instantiating a
dynamic object, ie.

pathToComponent = “component.utility.tools”;
obj = createObject( “component”, pathToComponent ).init();

This below throws an error:
obj = new #pathToComponent#();

Regards,
ML

On Saturday, March 28, 2015 at 5:29:26 AM UTC+8, Micha wrote:

Great post! Please see my comments between the lines.

Micha

Am Freitag, 27. März 2015 schrieb Walter Seethaler :

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and
ran into some issues with the way CF instantiates its objects. Especially
on a framework level, where you provide CFCs for instantiation or
subclassing and have no guarantee, how the people are using your classes.
When I looked into the Java constructor specification, I realized that it
is a very robust definition that avoid every little issue I ran into. So I
tried to translated the spec to CF, solve the backward compatibility issues
and provide a robust long-term solution. I hope this is a good time and
place to share it.

In OO languages it is almost a standard to have a special method,
dedicated to the object creation - the constructor. In CF the closest thing
we have is the pseudo constructor, whereas the init method is mainly
treated as a normal method. Only the new operator partially treats init as
a constructor (but new does not call super.init() automatically). I would
love to have more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method,
      or try to assure it programmatically.

The problem here is historical, coldfusion 6 indroduced components but
without the new operator and no init method.
Later (version 7,8,9?) added support for the new operator and init. But
for backward compatibility the old way to instantiate components make no
use of this new pseudo constructor.
In Lucee 5 we deprecate the function createObject,cfinvoke and cfobject,
so change this functionality makes no sense anymore, best avoid them.

  1. The instantiation of a CFC should not depend on how the class
    is created at runtime. The instantiation should be the same, no matter how
    the class is created.
    • The init method and the init methods of all base classes should
      be called under all circumstances, not matter if you use new, createObject,
      cfobject or cfinvoke.

Make sense, we need to think about this with the new dialect.

  1. It should not be possible to call a constructor multiple times,
    this just inflicts unnecessary problems.
    • When I program CFCs that are used by others, I tend to avoid
      that programatically. It should not be necessary.

Problem here is that if you load the component via createObject you call
init after construction

  1. The init method should always return the instance.
    • As init can return something else, I tend to specify the return
      type (for clarity), which adds an unnecessary type check at runtime.
    • The return this; should not be necessary (as in ACF).

The return type is not necessary! Lucee acts exact the same as acf here

  1. It should not be possible to concurrently call the constructor.
  • It is theoretically possible and I wasted time thinking about it.
    2. You should be able to enforce the behavior off your CFCs.
    • With the final keyword and a guaranteed constructor call, you
      can control the behavior of your CFC pretty well, even if the class is
      extended.
    1. A programming language that is easy to use an to learn,
      should: be intuitive, provide good error messages and have a good
      documentation
      . Those 3 points are not true for constructors in CF
      (in my opinion).

In my opinion the best way is to deprecate createObject, cfinvoke
,cfobject and remove the. For the doc .

  1. The problems above make it more difficult to provide high
    software quality (e.g. in OS frameworks, tools, libraries).

  2. Specification

    1. Constructors can not be overridden.

What you mean with this?

  1. super() calls the constructor of the base class.

+1

  1. If super() is not defined in the constructor source, the
    compiler adds it on top of the constructor source.

+1

  1. If the super() call (without arguments) is not possible -
    because the base constructor has at least 1 required argument (without
    default value) - the compiler throws an error.

Problem is the compiler cannot decide this, Lucee is not a static
language like for example Java, things like this need to be decided at
runtime.

  1. Constructors do not have a return value.

It was that way in earlier version, we changed that for comaptibility to
acf, but this should be the case for the new dialect

  1. If no constructor is defined, the compiler adds the standard
    constructor
    : function init(){ super(); }
  2. Constructors can only be called once.
  3. (It is guaranteed that) constructors are called on
    instantiation.

Init is called after construction, changing this could break existing
code, the body of the component it the only real constructor.

  1. Constructors can not be defined in an included .cfm.
    • As constructors are a compile time feature, I guess dynamic
      includes would cause problems.

You cannot turn Lucee in a static language, I strongly disagree on this

  1. getComponentMetaData() and other reflection methods do not call
    the constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in
      Lucee (which is false) - while ACF does not.

No this methods are not producing a instance of the component

  1. Access modifiers can be: remote, public, package or
    private.
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.

Lucee 5 indroduces the keyword static, with that the modifier private
makes a lot of sense, for example to do a singleton
Component {
private function init(){}
Public static
getInstance(){if(isnull(static.instance))static.instance=new Test(); return
static.instance;}

  1. Access modifier public is default and can be omitted.

  2. Pseudo constructor (the source code outside of the functions).

    1. Either pseudo code is not allowed anymore (clean approach),
    2. or it is called prior to the constructor.
  3. Lucee.cfc does not call super().

  4. Syntax (the compiler must be able to detect the new syntax to
    provide backward compatibility for the old syntax: function init()).

    • If a new constructor is present in a CFC the compiler and the
      CFC instance must honor this spec.

    • If it is not present, everything should behave backward
      compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.

+1

  1. Execution order

    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor
          uses a method that can be overwritten in subclasses. So I guess in Java it
          is possible to use a method in the constructor that is overridden at
          runtime.
        • With the final keyword in Lucee 5, every developer can
          decide to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

  2. 2. make base methods available and override base+1 methods
    3. make methods available and override base methods
    4. …
    5. make base properties available and override…
    6. make properties available and override…
    7. …
    8. call base pseudo constructor (see 13.2)
    9. call pseudo constructor (see 13.2)
    10. call constructor (which calls super() as specified)
    2. Object creation

    1. new Foo() - creates the instance and calls the constructor
      as defined in 16.
    2. createObject(“component”, “Foo”) - creates the instance and
      calls the constructor
      as defined in 16.
    3. - creates the instance and calls the constructor as
      defined in 16.
    4. - creates the instance and calls the constructor as
      defined in 16 and calls the method specified.
  3. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the
        spec.
    • Inheritance between CFCs with old and new constructor should work
      well.
      • Most important is, that CFCs with the new constructor can
        extend CFC with the old init constructor.

What do you think?

You haven given that a lot of thoughts and it makes a lot of sense, I
like it and it is definitely worth consider this approach for the Lucee
dialect, we need to check what this men’s in detail to implement it.


You received this message because you are subscribed to the Google
Groups “Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send
an email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com?utm_medium=email&utm_source=footer
.
For more options, visit https://groups.google.com/d/optout.

this is working new “#pathToComponent#”(); but i don’t like it at all,
Lucee 5 indroduces a new function “createComponent” that also invokes the
“init” function the same way as the new operator does:
createComponent(pathToComponent,[1,2,3]);
createComponent(pathToComponent,{lastname:“Sorglos”});

MichaOn Wed, Apr 1, 2015 at 3:09 PM, ML <@ML1> wrote:

Hi Micha,

If createObject is deprecated, is there an alternative to instantiating a
dynamic object, ie.

pathToComponent = “component.utility.tools”;
obj = createObject( “component”, pathToComponent ).init();

This below throws an error:
obj = new #pathToComponent#();

Regards,
ML

On Saturday, March 28, 2015 at 5:29:26 AM UTC+8, Micha wrote:

Great post! Please see my comments between the lines.

Micha

Am Freitag, 27. März 2015 schrieb Walter Seethaler :

Hello everyone,

do you like the init methods (constructors) in CF? I use CFCs a lot and
ran into some issues with the way CF instantiates its objects. Especially
on a framework level, where you provide CFCs for instantiation or
subclassing and have no guarantee, how the people are using your classes.
When I looked into the Java constructor specification, I realized that it
is a very robust definition that avoid every little issue I ran into. So I
tried to translated the spec to CF, solve the backward compatibility issues
and provide a robust long-term solution. I hope this is a good time and
place to share it.

In OO languages it is almost a standard to have a special method,
dedicated to the object creation - the constructor. In CF the closest thing
we have is the pseudo constructor, whereas the init method is mainly
treated as a normal method. Only the new operator partially treats init as
a constructor (but new does not call super.init() automatically). I would
love to have more robust (better) constructors in Lucee.

I will discuss 3 topics:

  1. Motivation

  2. Specification

  3. Backward compatibility

  4. Motivation

    1. The constructor contains the code that sets up the instance. It
      should be guaranteed that the constructor is called, even when the class is
      part of inheritance.
    • In CF you can either hope that everybody calls your init method,
      or try to assure it programmatically.

The problem here is historical, coldfusion 6 indroduced components but
without the new operator and no init method.
Later (version 7,8,9?) added support for the new operator and init. But
for backward compatibility the old way to instantiate components make no
use of this new pseudo constructor.
In Lucee 5 we deprecate the function createObject,cfinvoke and cfobject,
so change this functionality makes no sense anymore, best avoid them.

  1. The instantiation of a CFC should not depend on how the class
    is created at runtime. The instantiation should be the same, no matter how
    the class is created.
    • The init method and the init methods of all base classes should
      be called under all circumstances, not matter if you use new, createObject,
      cfobject or cfinvoke.

Make sense, we need to think about this with the new dialect.

  1. It should not be possible to call a constructor multiple times,
    this just inflicts unnecessary problems.
    • When I program CFCs that are used by others, I tend to avoid
      that programatically. It should not be necessary.

Problem here is that if you load the component via createObject you call
init after construction

  1. The init method should always return the instance.
    • As init can return something else, I tend to specify the return
      type (for clarity), which adds an unnecessary type check at runtime.
    • The return this; should not be necessary (as in ACF).

The return type is not necessary! Lucee acts exact the same as acf here

  1. It should not be possible to concurrently call the constructor.
  • It is theoretically possible and I wasted time thinking about it.
    2. You should be able to enforce the behavior off your CFCs.
    • With the final keyword and a guaranteed constructor call, you
      can control the behavior of your CFC pretty well, even if the class is
      extended.
    1. A programming language that is easy to use an to learn,
      should: be intuitive, provide good error messages and have a good
      documentation
      . Those 3 points are not true for constructors in CF
      (in my opinion).

In my opinion the best way is to deprecate createObject, cfinvoke
,cfobject and remove the. For the doc .

  1. The problems above make it more difficult to provide high
    software quality (e.g. in OS frameworks, tools, libraries).

  2. Specification

    1. Constructors can not be overridden.

What you mean with this?

  1. super() calls the constructor of the base class.

+1

  1. If super() is not defined in the constructor source, the
    compiler adds it on top of the constructor source.

+1

  1. If the super() call (without arguments) is not possible -
    because the base constructor has at least 1 required argument (without
    default value) - the compiler throws an error.

Problem is the compiler cannot decide this, Lucee is not a static
language like for example Java, things like this need to be decided at
runtime.

  1. Constructors do not have a return value.

It was that way in earlier version, we changed that for comaptibility to
acf, but this should be the case for the new dialect

  1. If no constructor is defined, the compiler adds the standard
    constructor
    : function init(){ super(); }
  2. Constructors can only be called once.
  3. (It is guaranteed that) constructors are called on
    instantiation.

Init is called after construction, changing this could break existing
code, the body of the component it the only real constructor.

  1. Constructors can not be defined in an included .cfm.
    • As constructors are a compile time feature, I guess dynamic
      includes would cause problems.

You cannot turn Lucee in a static language, I strongly disagree on this

  1. getComponentMetaData() and other reflection methods do not call
    the constructor.
    • afaik getComponentMetaData() calls the pseudo-constructor in
      Lucee (which is false) - while ACF does not.

No this methods are not producing a instance of the component

  1. Access modifiers can be: remote, public, package or
    private.
    • Not sure about remote and private.
    • As private methods can be called from subclasses in CF, private
      would make a class abstract.

Lucee 5 indroduces the keyword static, with that the modifier private
makes a lot of sense, for example to do a singleton
Component {
private function init(){}
Public static getInstance(){if(isnull(static.instance))static.instance=new
Test(); return static.instance;}

  1. Access modifier public is default and can be omitted.

  2. Pseudo constructor (the source code outside of the functions).

    1. Either pseudo code is not allowed anymore (clean approach),
    2. or it is called prior to the constructor.
  3. Lucee.cfc does not call super().

  4. Syntax (the compiler must be able to detect the new syntax to
    provide backward compatibility for the old syntax: function init()).

    • If a new constructor is present in a CFC the compiler and the
      CFC instance must honor this spec.

    • If it is not present, everything should behave backward
      compatible.

    • component{

      public this( required numeric foo ){
      super( foo+1 );
      }

    }

    • I personally do not like that Java uses the classname as the
      constructor name, because the classname in CF is the filename and thus I
      can easily rename my CFC without the need to change the source of the CFC.
      So I came up with this syntax.

+1

  1. Execution order

    • Not sure about this one. The questions are:
      • When are properties instantiated (default values).
      • When is the constructor and pseudo constructor called?
      • Are the other methods available in the constructor?
        • In Java the compiler gives a warning, if the constructor
          uses a method that can be overwritten in subclasses. So I guess in Java it
          is possible to use a method in the constructor that is overridden at
          runtime.
        • With the final keyword in Lucee 5, every developer can
          decide to only use methods in the constructors, that can not be overwritten
          (declared as final).
      • My try:

  2. 2. make base methods available and override base+1 methods
    3. make methods available and override base methods
    4. …
    5. make base properties available and override…
    6. make properties available and override…
    7. …
    8. call base pseudo constructor (see 13.2)
    9. call pseudo constructor (see 13.2)
    10. call constructor (which calls super() as specified)
    2. Object creation

    1. new Foo() - creates the instance and calls the constructor
      as defined in 16.
    2. createObject(“component”, “Foo”) - creates the instance and
      calls the constructor
      as defined in 16.
    3. - creates the instance and calls the constructor as
      defined in 16.
    4. - creates the instance and calls the constructor as
      defined in 16 and calls the method specified.
  3. Backward compatibility

    • Without a new constructor present, everything behaves as before.
    • With the new constructor present in the source code.
      • If a method with the name init is present, it is treated as a
        normal function.
      • new, createObject, cfobject and cfinvoke honor the spec.
      • It is not possible to instantiate a CFC without honoring the
        spec.
    • Inheritance between CFCs with old and new constructor should work
      well.
      • Most important is, that CFCs with the new constructor can
        extend CFC with the old init constructor.

What do you think?

You haven given that a lot of thoughts and it makes a lot of sense, I
like it and it is definitely worth consider this approach for the Lucee
dialect, we need to check what this men’s in detail to implement it.


You received this message because you are subscribed to the Google
Groups “Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send
an email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/
msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com
https://groups.google.com/d/msgid/lucee/169c34c3-b5c9-450d-97e1-d549c2a24997%40googlegroups.com?utm_medium=email&utm_source=footer
.
For more options, visit https://groups.google.com/d/optout.


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/2f97127f-0e5e-4535-8da3-a1683342d551%40googlegroups.com
https://groups.google.com/d/msgid/lucee/2f97127f-0e5e-4535-8da3-a1683342d551%40googlegroups.com?utm_medium=email&utm_source=footer
.

For more options, visit https://groups.google.com/d/optout.

Hi,

just want to throw in an other thought:
does init() have to be the constructor method?

As it has been just a regular function in the past and also been used that
way, i.e. with arguments and possible different return values (than the
object itself), it would be better for backwards compatibility if this
won’t be changed.
I would suggest using a constructor function similar to other programming
languages where the constructor is automatically determined by having the
same name as the “class”, ie. the component name.

I’d say for backward compatibility the reverse is true. Using init() as the
constructor has been the convention from before I started coding CFML (not
a great deal of time, but around 12 years ago).

I agree that it isn’t necessarily perfect, but anyone programming CFML with
their finger anywhere near the pulse will have been using init() in this
way and this has then been solidified some years ago with the introduction
of the ‘new’ operator.

I think changing it now would bring plenty of tears and not a great deal of
benefit. It may differ from Java and other languages, but the ‘init’
convention is pretty clear and easily documented.On 2 April 2015 at 16:44, Siegfried Wagner <@Siegfried_Wagner> wrote:

Hi,

just want to throw in an other thought:
does init() have to be the constructor method?

As it has been just a regular function in the past and also been used that
way, i.e. with arguments and possible different return values (than the
object itself), it would be better for backwards compatibility if this
won’t be changed.
I would suggest using a constructor function similar to other programming
languages where the constructor is automatically determined by having the
same name as the “class”, ie. the component name.


You received this message because you are subscribed to the Google Groups
“Lucee” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to lucee+unsubscribe@googlegroups.com.
To post to this group, send email to lucee@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/lucee/a4d68ead-cb54-4650-bbbc-ba49d78d8ba6%40googlegroups.com
https://groups.google.com/d/msgid/lucee/a4d68ead-cb54-4650-bbbc-ba49d78d8ba6%40googlegroups.com?utm_medium=email&utm_source=footer
.

For more options, visit https://groups.google.com/d/optout.


Pixl8 Interactive, 3 Tun Yard, Peardon Street, London
SW8 3HT, United Kingdom

T: +44 [0] 845 260 0726• W: www.pixl8.co.uk• E: info@pixl8.co.uk
Follow us on: Facebook http://www.facebook.com/pixl8 Twitter
http://www.twitter.com/pixl8 LinkedIn
http://www.linkedin.com/pixl8CONFIDENTIAL
AND PRIVILEGED - This e-mail and any attachment is intended solely for the
addressee, is strictly confidential and may also be subject to legal,
professional or other privilege or may be protected by work product
immunity or other legal rules. If you are not the addressee please do not
read, print, re-transmit, store or act in reliance on it or any
attachments. Instead, please email it back to the sender and then
immediately permanently delete it. Pixl8 Interactive Ltd Registered in
England. Registered number: 04336501. Registered office: 8 Spur Road,
Cosham, Portsmouth, Hampshire, PO6 3EB