##Passed by value? No!##
In Lucee all variables are passed by reference always (also in ACF BTW), simply because there is no other way to do it.
Java is supporting primitive types (char,int,boolean,short,long,double,byte) BUT this types are not used in Lucee, simply because we store all data in maps (java.util.Map) and maps only can store Objects.
So if you use for example a number in Lucee, you are using an object from the class java.lang.Double what is a wrapper class for the primitive type “double”.
This example will show you:
nbr=123;
bool=true;
str="Susi Sorglos";
function meta(o){
dump(getMetaData(o).name);
dump(o.hashCode());
}
meta(str);
dump(str.hashCode());
meta(nbr);
dump(nbr.hashCode());
meta(bool);
dump(bool.hashCode());
executing that example gives you an output like this:
java.lang.String
-19311561
-19311561
java.lang.Double
1079951360
1079951360
java.lang.Boolean
number 1231
number 1231
You can see the classes of the objects and the hashcode of the objects, hashcode are unique for every instance, so you clearly see that you have the same object inside the function as you have outside.
So objects are passed by reference always!
##But what about …##
###“passby” with arguments###
You can use the argument “passby” with cfargument (hidden feature in Lucee for backward compatibility for older applications, for example “transfer”)
<cffunction name="test">
<cfargument name="arg" passby="value">
this does not really pass by value, it simply clones the object before passing by reference, so it is the same as you would do the following
test(duplicate(whatever));
##ACF is passing arrays by value##
The same as above it only simulates this, in fact they are cloned and pass by reference.
Again passing objects by value is impossible in the JVM.
##Immutable Objects##
As @kliakos already explained the following classes are immutable (java.lang… String,Long,Short,Integer,Character,Boolean,Integer …), so if you do the following code
str = "bl";
dump(var:str.hashCode(),label:"hash before");
str &= "ah";
dump(var:str.hashCode(),label:"hash after");
dump(str == "blah"); // equal operator
dump(str === "blah"); // identical operator
output:
hash before - 3146
hash after - 3026417
true
false
You do not manipulate an existing string, it is producing a new string, as you can see in the hash dump.
##StringBuilder/StringBuffer##
So the point is not that objects are passed by value, problem is that they are immutable, in java we use the class java.lang.StringBuilder or java.lang.StringBuffer (thread safe) to manipulate Strings.
of course you can also use them in CFML as following
createObject("java","java.lang.StringBuilder").init("Susi ").append("Sorglos");
But speed wise this is not worth doing it, because the overhead you have with reflection is more than what you win by avoiding to create new objects.
Lucee is well aware of StringBu… objects and can handle them the SAME way as String, so you can do things like this:
1: sb = createObject("java","java.lang.StringBuilder").init("Susi");
2: dump(sb);
3: dump(sb.hashCode());
4: sb&=" Sorglos";
5: dump(sb);
6: dump(sb.hashCode());
but this is still producing a new string on line 4, we was already considering to append " Sorglos" in this case to the existing object, but this would break backward compatiblity (also to ACF).
But we could think about it for the Lucee dialect.