wyrmwood wrote:Craig wrote:I just wanted to clear this up... pass by value seems to be a very misunderstood term, there is no speed difference between pass by reference/value (a lot of languages don't even have pass by reference, Java ... for example
OK, I apologize, I have to get a bit pedantic here... so, in Java, an object
passes the reference by value - when I was in school, they taught this concept as "pass by reference" even though, since the reference is copied, technically, as you said, it's pass by value.
I see your pedantic and raise it
They may have taught you this at school, but it doesn't make what they taught you right. It is pass by value, end of story. I cant stress the previous strongly enough, there is a clear unambiguous distinction between pass by reference and pass by value, its not a technically it is pass by value, it just is pass by value. I know a lot of people may have been taught otherwise, that is why I said its a very misunderstood term. I want to also address the "passes the reference by value" but I will leave that until a bit later in the post.
wyrmwood wrote:Here's the rub, you can manipulate an object that's passed in this manner (a copy of the reference) and still alter the data within the object... or you may not... depending on whether you manipulate what the object's actually pointing to (since those references are the same as in the original), or whether you manipulate the reference itself (since the reference is indeed a copy or pass by value).
This is not the same effect as how Java 'passes by value' a primitive data type, where no matter what you do, the original variable remains unchanged in the caller.
You are thinking about it the wrong way because it is exactly the same. It doesn't matter if it is a java object or primitive that is passed in, they are both pass by value and happen the same way. Since java always passes by value you can never alter the value that was passed in. Take the following example
Code: Select all
...
v = new StringBuilder();
v.append("This is a test");
blah(v);
...
public void blah(Object o) {
o = new String("Eh?");
}
After the call to blah(v), v still points to the originally allocated StringBuilder() object. This happens because "v" was passed by value, so you can never alter it in blah().
I know the next comment is going to be but I can change what is inside of the "v" string builder, and yes you can, but this is not changing "v" you are changing some of the contents of "v" and not "v" itself -- this is an important distinction, "v" is still
exactly the same object as before the call, it just has a different state. Its like when you lend your car to a friend and they either throw out some of your empty fast food wrappers, or leave some of theirs in it, when you get it back its still the same car, you just have either more, less, or different things in it. Since primitive types have no contents you are not able to change their contents, this is why they appear to be passed different from objects where as in reality they are not. See the following
Code: Select all
....
int a = 2;
blah(a);
...
public void blah(int c) {
c = 5;
}
The above code displays exactly the same type of behavior, I can assign to "c" exactly the same way I can assign to "o", and in both cases it will not affect "a" or "v" because both of these were passed by value not by reference. If pass by reference had occurred in either case then the values of "a" or "v" (or both) would have been modified.
wyrmwood wrote:
I might not be making sense, so here's a better
explanation of the difference.
I read that article, and I think its very poorly worded. It makes it seem as if something special is going on when you pass an object, i.e. Java takes a reference of that object and passes the value of that reference. This is not what is happening at all, and its one of the reasons the term "passes the reference by value" can be kind of misleading.
Take the following
So you usually think of this as "call someMethod() on object o", I am pretty sure that people don't usually think of it as "call someMethod() on object referenced by o", which is what is actually happening. So why would you take the following
And say "pass the value of the reference to object o". By adding the word "reference" in there and not doing the same to any object access people tend to infer that there is another level of indirection occurring when an object is an argument to a method. This is not the case though, all object access is via a reference to that object.
Or more simply put, all parameters are passed by value, when you pass an object nothing special happens compared to when you pass a primitive, the fact that you can do different things to them within the method is solely down to the fact that they are different and not because any thing different happens during the parameter passing.
wyrmwood wrote:
So, back to MapTool, why wouldn't pass by reference be "quicker" than pass by value if the reference is significantly smaller than the data it references?
I think the problem is the following
wyrmwood wrote:
when I was in school, they taught this concept as "pass by reference" even though, since the reference is copied, technically, as you said, it's pass by value.
From the above it appears that you have been taught incorrectly what pass by value vs pass by reference really means. So when I use the term "pass by value" you are assuming I mean "place a deep copy on the stack" which I definitely don't mean, and that certainly is not what pass by value means.
wyrmwood wrote:
Or in the case of the question at hand, it appears that passing a single property is indeed more efficient than passing a large JSON, I'm assuming since it is passed by value? Or am I missing something?
In another thread about efficiency I detailed the difference of JSON vs String List/Properties vs Token properties. Accessing token properties is always a lot faster than JSON objects. Also when using user defined functions you will get a slow down when using JSON variables with a lot of data in them, this has nothing to do with pass by value vs pass by reference. The problem is the way the way the MapTool interpreter works, as it was designed only to run commands without any looping or flow control it grabs a line and parses it. If there is a loop then it parses the same lines in the loop over and over instead of just parsing it once into intermediate code and looping over that. User defined functions need to be expanded into [macro():] calls, and this requires a translation of the JSON object to a string (and then the first time you use it as a JSON object in the called macro it needs to translate it back into JSON) its this translation you are taking a hit on.
For those that want more technical details of how the macro script does things you can keep reading for those that don't then you can skip the rest of the post
First off there are two kind of unusual things about MapTool macro script
- All values are immutable
- There is no stack
All variables are stored in a Java Map, for all intents and purposes you can think of these as Heap memory. When a macro is called and a new scope is required for that macro a new Java Map is created -- since there is no Stack you can't support local variables by just altering the top of the stack. The passed arguments are also created in the new Heap because there is no stack.
So if you have the following
Code: Select all
[macro("blah@Lib:token"): someVar]
The the java code essentially does the following steps
- Get the "someVar" variable from the current Heap (Java Map)
- Assign the "someVar" to the macro.args variable in the new Heap (Java Map)
Although the code isn't exactly the following line, it is close enough
Code: Select all
newScope.put("macro.args", currentScope.get(argName));
Which is about as efficient as it is going to get and pass by value -- if you were to actually try to implement this as pass by reference it would be a little less efficient as you need add a way to support indirection.