Should we add all member functions also as regular functions?

With Lucee 5.1 we did add the member function setYear,seMonth …, because until now all member functions we had was also are supported as regular functions, we added this functions also as regular functions.
so you not only can do this in Lucee:
now().setYear(2017);

you can also do this:
SetYear(now(),2017);

The first exmple is supported in ACF12, but the second is not. this causes problems for people updating to Lucee 5.1, when their code did contain already an UDF with this name.

So question is: should we have all member functions also as regular functions or should we only provide this functions as member functions?

I always prefer to use member functions over regular ones, even though the regular ones perform a little better.

I guess it’s a matter of code style.

Also, I am not sure what the regular function does in your example:

SetYear(now(),2017) 

Does that modify the first argument? Or does it return a new object?

i.e., given:

d = now();
e = SetYear(d, 2017)

Is e a new object?
Is e null?
What does d.getYear() return? 2016 or 2017 (assuming that this code runs in 2016)

So in summary, in case it’s not clear, my opinion is No, Not all member functions should also be regular functions.

2 Likes

This feels like a very “Javascript” question. Just because most member functions in javascript are function(self,args…)… And usually can be called statically or on an instance… And in both cases, they work the same. (unless the function behavior takes execution into account)

But even Javascript always has some sort of scope. (i.e. in a browser, global is actually window) There’s no real parallel in Java because you don’t have a globally shared scope.

I think lessons learned in modern Javascript are that using namespaces for everything is the way to go. And I think that applies here.

By creating the setYear(obj,int) function, are you now committing to support this function for all possible object types? Not just java.util.Date, but Joda derivatives, cfc’s that might contain a setYear function - and are you then going to support different arguments based on the implementation? Is xxxx(obj,…) implicitly under the hood going to be mapped to obj.xxxx(…)? That could lead to wildly unpredictable behavior.

I’m with Igal. Member functions are member functions. They properly support encapsulation, are “namespaced” or at least limited in scope, and operate on objects with a well defined contract. (i.e. now().setYear() might mean something entirely different from someDAO.setYear()) I don’t think it’s a good idea to say a global setYear(date, year) function will only work on dates - it just enforces bad programming practices and the expectation that other supplied objects will work too. Nor is it a good idea for the language to assume responsibility for doing reflection so setYear works on anything.

1 Like

I completely agree. (I’m also the person who ran into a name collision with setYear() after updating to 5.1.)

Stop polluting the global namespace: no more regular functions (unless you need to add them for ACF compatibility). I’m curious as to why you felt the need to add these functions as regular functions anyway?

1 Like

@joe.gooch Under the hood it’s actually the opposite. There is a “regular” function for the implementation and obj.xxx() maps to it. But that “regular” function can have any name (to avoid name collision), and in many cases it is marked as “hidden” so you don’t see it when you look at the docs.

I said this in the ticket around this conversation, but I’ll repeat it here, too: this update has broken accessors on CFCs where Year is a property. It has caused a number of our applications to break as year is a field we use quite a bit in our beans.

In terms of the language, I prefer the namespacing approach. JavaScript learned that lesson. CSS is learning that lesson. Web Components are all about that, too. Modularity over globalization, in my opinion.

so we remove all this set BIF, but we keep them as member functions

2 Likes

I like the consistency of not having to guess what’s a member function and what’s headless, but I think the way forward is member functions and not polluting the global namespace as Sean says.