annotate optional return type - google-closure-compiler

I am having issue in assigning the return type of below method to a variable of integer type in advanced compilation mode of google closure. Also i don't want to use getter/setter method as a replacement for below code.
/**
* Sets the idNum of this shape.
* #override
* #param {...number} id The number to set idNum, optional parameter.
* #returns {number} Returns idNum if nothing is passed in.
*/
app.Shape.prototype.idNum = function(id) {
if(goog.isDef(id)) {
this._idNum = id;
} else {
return this._idNum;
}
};
How should i update my annotation for
#returns
so that above method may or may not return number depending on the parameter passed.

It's a little strange to have the same function be both a getter and a setter, depending on how it's called. But anyway: Use an = for the optional parameter: {number=}. For your "optional return" you can write the return type as {number|undefined} because if you don't hit a 'return' statement, the function will just return undefined. See Annotating JavaScript for the Closure Compiler for more.

The Closure Compiler doesn't support having more than one signature for a function, you basically want:
/** #type {(function(number):undefined)|(function():number)} */
Currently, the compiler merges this into "Function". More specifically, you want to say not that it is either of those types but both of those types and there is nothing like that now.
While you can manually merge the function signature to be:
/**
* #param {number=} opt_id
* #return {number|undefined}
*/
This means the return type is always "number|undefined" not the return type is "undefined" when the parameter is specified and "number" otherwise when leaves consumers having to "narrow" the results to either "number" or "undefined" after every call which is an awkward api.

While having a function be both a getter and a setter is not strange in many scenarios, you are fighting against what Closure Compiler is trying to do for you.
JavaScript is loosely-typed, meaning anything can be "this type OR that type OR another type OR ...." with no limit on the size of this list.
CC is trying to help by enforcing strong-types. The strongest possible typing insists that a given variable is "this one type only", but this rigidity is often a pain (not allowing a NULL or UNDEFINED value in particular). CC relaxes this by allowing "a few types only" that you must spell out. However, you should be aware that this relaxation is one small step backwards, towards the wild west of loose-typing.
If you are using CC to improve your code, then listen to what it is trying to tell you. If you find yourself fighting to find the right annotation for something, or your lists of types are growing, then maybe you need to reconsider your use of CC and strong-typing in the first place.
Personally, I prefer strong-typing and simpler, shorter, clearer code. In your example, CC is trying to help by obliquely hinting at the down-side of combining getter and setter functionality.

Related

NoSuchMethodError: The getter 'hash' was called on null [duplicate]

I have some code and when I run it produces an error, saying:
NoSuchMethod: the method 'XYZ' was called on null
What does that mean and how do I fix it?
Why do I get this error?
Example
As a real world comparison, what just happened is this conversation:
Hey, how much gas is left in the tank of the car?
What are you talking about, we don't have a car.
That is exactly what is happening in your program. You wanted to call a function like _car.getGasLevel(); but there is no car, the variable _car is null.
Obviously, in your program it might not be a car. It could be a list or a string or anything else really.
Technical explanation
You are trying to use a variable that is null. Either you have explicitly set it to null, or you just never set it at all, the default value is null.
Like any variable, it can be passed into other functions. The place where you get the error might not be the source. You will have to follow the leads from the actual null value to where it originally came from, to find what the problem is and what the solution might be.
null can have different meanings: variables not set to another value will be null, but sometimes null values are used by programmers intentionally to signal that there is no value. Databases have nullable fields, JSON has missing values. Missing information may indeed be the information itself. The variable bool userWantsPizzaForDinner; for example might be used for true when the user said yes, false when the user declined and it might still be null when the user has not yet picked something. That's not a mistake, it's intentionally used and needs to be handled accordingly.
How do I fix it?
Find it
Use the stack trace that came with the error message to find out exactly which line the error was on. Then set a breakpoint on that line. When the program hits the breakpoint, inspect all the values of the variables. One of them is null, find out which one.
Fix it
Once you know which variable it is, find out how it ended up being null. Where did it come from? Was the value never set in the first place? Was the value another variable? How did that variable got it's value. It's like a line of breadcrumbs you can follow until you arrive at a point where you find that some variable was never set, or maybe you arrive at a point where you find that a variable was intentionally set to null. If it was unintentional, just fix it. Set it to the value you want it to have. If it was intentional, then you need to handle it further down in the program. Maybe you need another if to do something special for this case. If in doubt, you can ask the person that intentionally set it to null what they wanted to achieve.
simply the variable/function you are trying to access from the class does not exist
someClass.xyz();
above will give the error
NoSuchMethod: the method 'xyz' was called on null
because the class someClass does not exist
The following will work fine
// SomeClass created
// SomeClass has a function xyz
class SomeClass {
SomeClass();
void xyz() {
print('xyz');
}
}
void main() {
// create an instance of the class
final someClass = SomeClass();
// access the xyz function
someClass.xyz();
}

Kotlin Bundle.putString not explicitly adding "String" but instead is "String?"

val args = Bundle()
args.putString("type", details.type)
navigator.navigate(context!!, findNavController(), Destination.TYPE, args)
I am quite confused as to why in the receiving fragment when I go to access the arguments I have passed through it is responding with...
val type: String = arguments.getString("type")
The arguments.getString is all underlined red and says "Required String Found String?" But how when I called method "putString"?!?
It is resulting in text not being rendered in the new fragment and I assume this is a nullability issue.
It's a matter of knowledge that is available in the receiving Fragment.
The Fragment is not aware of how its arguments were created (or modified) so it has to assume the "type" key you're looking for might not be in the arguments Bundle. That's why it returns a nullable (String?) result (the null value would mean absent in arguments).
Your fragment might be created in many places in your app and its arguments might have been modified in many places. We have no way of tracking that.
There are different solutions for this problem, depending on your approach in other parts of the code and how "confident" you are in creating of your Fragment.
I would usually choose a solution in which I assume setting the type is mandatory. Therefore if the type is absent - I fail fast. That would mean the Fragment was misused.
val type: String = arguments!!.getString("type")!!
The code above will crash if either:
a) arguments weren't set, or
b) String with type wasn't put in the arguments Bundle.
You are right, that is a : null ability issue.
First you should be sure if you are expecting a value, so try adding "?" or "!!", i would recommend "?", or go with the block of if {} else
To read the string safely you can use:
val type: String = arguments?.getString("type").orEmpty()
The orEmpty call at the end ensures that a valid String is returned even if either arguments or getString() returns null.
The method signature for getString() returns a nullable String. This is because at compile time, the compiler can't know if the value exists in the bundle or not. You will have the same issue when retrieving anything from any Map.
If you know for certain that the value in the bundle or map should exist at the time you call getString(), you can use the !! operator. That's what it's there for. When you know something should always be there, it is appropriate to want an exception to be thrown (in this case KNPE) if it's not there so you can easily find any programming error during testing.
isEmpty() or ?.let aren't helpful in this particular case because they would just be masking a programming error and making it harder to discover or debug.

Collection of Unique Functions in Go

I am trying to implement a set of functions in go. The context is an event server; I would like to prevent (or at least warn) adding the same handler more than once for an event.
I have read that maps are idiomatic to use as sets because of the ease of checking for membership:
if _, ok := set[item]; ok {
// don't add item
} else {
// do add item
}
I'm having some trouble with using this paradigm for functions though. Here is my first attempt:
// this is not the actual signature
type EventResponse func(args interface{})
type EventResponseSet map[*EventResponse]struct{}
func (ers EventResponseSet) Add(r EventResponse) {
if _, ok := ers[&r]; ok {
// warn here
return
}
ers[&r] = struct{}{}
}
func (ers EventResponseSet) Remove(r EventResponse) {
// if key is not there, doesn't matter
delete(ers, &r)
}
It is clear why this doesn't work: functions are not reference types in Go, though some people will tell you they are. I have proof, though we shouldn't need it since the language specification says that everything other than maps, slices, and pointers are passed by value.
Attempt 2:
func (ers EventResponseSet) Add(r *EventResponse) {
// ...
}
This has a couple of problems:
Any EventResponse has to be declared like fn := func(args interface{}){} because you can't address functions declared in the usual manner.
You can't pass a closure at all.
Using a wrapper is not an option because any function passed to the wrapper will get a new address from the wrapper - no function will be uniquely identifiable by address, and all this careful planning is for nought.
Is it silly of me to not accept defining functions as variables as a solution? Is there another (good) solution?
To be clear, I accept that there are cases that I can't catch (closures), and that's fine. The use case that I envision is defining a bunch of handlers and being relatively safe that I won't accidentally add one to the same event twice, if that makes sense.
You could use reflect.Value presented by Uvelichitel, or the function address as a string acquired by fmt.Sprint() or the address as uintptr acquired by reflect.Value.Pointer() (more in the answer How to compare 2 functions in Go?), but I recommend against it.
Since the language spec does not allow to compare function values, nor does it allow to take their addresses, you have no guarantee that something that works at a time in your program will work always, including a specific run, and including different (future) Go compilers. I would not use it.
Since the spec is strict about this, this means compilers are allowed to generate code that would for example change the address of a function at runtime (e.g. unload an unused function, then load it again later if needed again). I don't know about such behavior currently, but this doesn't mean that a future Go compiler will not take advantage of such thing.
If you store a function address (in whatever format), that value does not count as keeping the function value anymore. And if no one else would "own" the function value anymore, the generated code (and the Go runtime) would be "free" to modify / relocate the function (and thus changing its address) – without violating the spec and Go's type safety. So you could not be rightfully angry at and blame the compiler, but only yourself.
If you want to check against reusing, you could work with interface values.
Let's say you need functions with signature:
func(p ParamType) RetType
Create an interface:
type EventResponse interface {
Do(p ParamType) RetType
}
For example, you could have an unexported struct type, and a pointer to it could implement your EventResponse interface. Make an exported function to return the single value, so no new values may be created.
E.g.:
type myEvtResp struct{}
func (m *myEvtResp) Do(p ParamType) RetType {
// Your logic comes here
}
var single = &myEvtResp{}
func Get() EventResponse { return single }
Is it really needed to hide the implementation in a package, and only create and "publish" a single instance? Unfortunately yes, because else you could create other value like &myEvtResp{} which may be different pointers still having the same Do() method, but the interface wrapper values might not be equal:
Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.
[...and...]
Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil. Pointers to distinct zero-size variables may or may not be equal.
The type *myEvtResp implements EventResponse and so you can register a value of it (the only value, accessible via Get()). You can have a map of type map[EventResponse]bool in which you may store your registered handlers, the interface values as keys, and true as values. Indexing a map with a key that is not in the map yields the zero value of the value type of the map. So if the value type of the map is bool, indexing it with a non-existing key will result in false – telling it's not in the map. Indexing with an already registered EventResponse (an existing key) will result in the stored value – true – telling it's in the map, it's already registered.
You can simply check if one already been registered:
type EventResponseSet map[*EventResponse]bool
func (ers EventResponseSet) Add(r EventResponse) {
if ers[r] {
// warn here
return
}
ers[r] = true
}
Closing: This may seem a little too much hassle just to avoid duplicated use. I agree, and I wouldn't go for it. But if you want to...
Which functions you mean to be equal? Comparability is not defined for functions types in language specification. reflect.Value gives you the desired behaviour more or less
type EventResponseSet map[reflect.Value]struct{}
set := make(EventResponseSet)
if _, ok := set[reflect.ValueOf(item)]; ok {
// don't add item
} else {
// do add item
set[reflect.ValueOf(item)] = struct{}{}
}
this assertion will treat as equal items produced by assignments only
//for example
item1 := fmt.Println
item2 := fmt.Println
item3 := item1
//would have all same reflect.Value
but I don't think this behaviour guaranteed by any documentation.

element() vs. node() in XQuery

Can someone tell me the exact difference between node() and element() types in XQuery? The documentation states that element() is an element node, while node() is any node, so if I understand it correctly element() is a subset of node().
The thing is I have an XQuery function like this:
declare function local:myFunction($arg1 as element()) as element() {
let $value := data($arg1/subelement)
etc...
};
Now I want to call the function with a parameter which is obtained by another function, say functionX (which I have no control over):
let $parameter := someNamespace:functionX()
return local:myFunction($parameter)
The problem is, functionX returns an node() so it will not let me pass the $parameter directly. I tried changing the type of my function to take a node() instead of an element(), but then I can’t seem to read any data from it. $value is just empty.
Is there some way of either converting the node to an element or should am I just missing something?
EDIT: As far as I can tell the problem is in the part where I try to get the subelement using $arg1/subelement. Apparently you can do this if $arg1 is an element() but not if it is a node().
UPDATE: I have tested the example provided by Dimitre below, and it indeed works fine, both with Saxon and with eXist DB (which is what I am using as the XQuery engine). The problem actually occurs with the request:get-data() function from eXist DB. This function gets data provided by the POST request when using eXist through REST, parses it as XML and returns it as a node(). But for some reason when I pass the data to another function XQuery doesn’t acknowledge it as being a valid element(), even though it is. If I extract it manually (i.e. copy the output and paste it to my source code), assign it to a variable and pass it to my function all goes well. But if I pass it directly it gives me a runtime error (and indeed fails the instance of test).
I need to be able to either make it ignore this type-check or “typecast” the data to an element().
data() returning empty for an element just because the argument type is node() sounds like a bug to me. What XQuery processor are you using?
It sounds like you need to placate static type checking, which you can do using a treat as expression. I don't believe a dynamic test using instance of will suffice.
Try this:
let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)
Quoting from the 4th edition of Michael Kay's magnum opus, "The treat as operator is essentially telling the system that you know what the runtime type is going to be, and you want any checking to be deferred until runtime, because you're confident that your code is correct." (p. 679)
UPDATE: I think the above is actually wrong, since treat as is just an assertion. It doesn't change the type annotation node(), which means it's also a wrong assertion and doesn't help you. Hmmm... What I really want is cast as, but that only works for atomic types. I guess I'm stumped. Maybe you should change XQuery engines. :-) I'll report back if I think of something else. Also, I'm curious to find out if Dimitre's solution works for you.
UPDATE #2: I had backpedaled here earlier. Can I backpedal again? ;-) Now my theory is that treat as will work based on the fact that node() is interpreted as a union of the various specific node type annotations, and not as a run-time type annotation itself (see the "Note" in the "Item types" section of the XQuery formal semantics.) At run time, the type annotation will be element(). Use treat as to guarantee to the type checker that this will be true. Now I wait on bated breath: does it work for you?
EXPLANATORY ADDENDUM: Assuming this works, here's why. node() is a union type. Actual items at run time are never annotated with node(). "An item type is either an atomic type, an element type, an attribute type, a document node type, a text node type, a comment node type, or a processing instruction type."1 Notice that node() is not in that list. Thus, your XQuery engine isn't complaining that an item has type node(); rather it's complaining that it doesn't know what the type is going to be (node() means it could end up being attribute(), element(), text(), comment(), processing-instruction(), or document-node()). Why does it have to know? Because you're telling it elsewhere that it's an element (in your function's signature). It's not enough to narrow it down to one of the above six possibilities. Static type checking means that you have to guarantee—at compile time—that the types will match up (element with element, in this case). treat as is used to narrow down the static type from a general type (node()) to a more specific type (element()). It doesn't change the dynamic type. cast as, on the other hand, is used to convert an item from one type to another, changing both the static and dynamic types (e.g., xs:string to xs:boolean). It makes sense that cast as can only be used with atomic values (and not nodes), because what would it mean to convert an attribute to an element (etc.)? And there's no such thing as converting a node() item to an element() item, because there's no such thing as a node() item. node() only exists as a static union type. Moral of the story? Avoid XQuery processors that use static type checking. (Sorry for the snarky conclusion; I feel I've earned the right. :-) )
NEW ANSWER BASED ON UPDATED INFORMATION: It sounds like static type checking is a red herring (a big fat one). I believe you are in fact not dealing with an element but a document node, which is the invisible root node that contains the top-level element (document element) in the XPath data model representation of a well-formed XML document.
The tree is thus modeled like this:
[document-node]
|
<docElement>
|
<subelement>
and not like this:
<docElement>
|
<subelement>
I had assumed you were passing the <docElement> node. But if I'm right, you were actually passing the document node (its parent). Since the document node is invisible, its serialization (what you copied and pasted) is indistinguishable from an element node, and the distinction was lost when you pasted what is now interpreted as a bare element constructor in your XQuery. (To construct a document node in XQuery, you have to wrap the element constructor with document{ ... }.)
The instance of test fails because the node is not an element but a document-node. (It's not a node() per se, because there's no such thing; see explanation above.)
Also, this would explain why data() returns empty when you tried to get the <subelement> child of the document node (after relaxing the function argument type to node()). The first tree representation above shows that <subelement> is not a child of the document node; thus it returns the empty sequence.
Now for the solution. Before passing the (document node) parameter, get its element child (the document element), by appending /* (or /element() which is equivalent) like this:
let $parameter := someNamespace:functionX()/*
return local:myFunction($parameter)
Alternatively, let your function take a document node and update the argument you pass to data():
declare function local:myFunction($arg1 as document-node()) as element() {
let $value := data($arg1/*/subelement)
etc...
};
Finally, it looks like the description of eXist's request:get-data() function is perfectly consistent with this explanation. It says: "If its not a binary document, we attempt to parse it as XML and return a document-node()." (emphasis added)
Thanks for the adventure. This turned out to be a common XPath gotcha (awareness of document nodes), but I learned a few things from our detour into static type checking.
This works perfectly using Saxon 9.3:
declare namespace my = "my:my";
declare namespace their = "their:their";
declare function my:fun($arg1 as element()) as element()
{
$arg1/a
};
declare function their:fun2($arg1 as node()) as node()
{
$arg1
};
my:fun(their:fun2(/*) )
when the code above is applied on the following XML document:
<t>
<a/>
</t>
the correct result is produced with no error messages:
<a/>
Update:
The following should work even with the most punctuential static type-checking XQuery implementation:
declare namespace my = "my:my";
declare namespace their = "their:their";
declare function my:fun($arg1 as element()) as element()
{
$arg1/a
};
declare function their:fun2($arg1 as node()) as node()
{
$arg1
};
let $vRes := their:fun2(/*)
(: this prevents our code from runtime crash :)
return if($vRes instance of element())
then
(: and this assures the static type-checker
that the type is element() :)
my:fun(their:fun2(/*) treat as element())
else()
node() is an element, attribute, processing instruction, text node, etc.
But data() converts the result to a string, which isn't any of those; it's a primitive type.
You might want to try item(), which should match either.
See 2.5.4.2 Matching an ItemType and an Item in the W3C XQuery spec.
Although it's not shown in your example code, I assume you are actually returning a value (like the $value you are working with) from the local:myFunction.

Arraycollection is being passed into function by value instead of by reference in flex 3

I want to set arrayCollection #2 = to arrayCollection #1 via a function in flex 3. I pass both array collections to a function and set arrayCollection #2 = arrayCollection #1. However, it seems to not be passing arrayCollection #2 by reference because after the function call, arrayCollection #2 has not been changed. My understanding is that it should be passed by reference and work, am I doing something wrong? Below is the code:
var AC1:ArrayCollection = new ArrayCollection;
var AC1.addItem(someObject);
var AC2:ArrayCollection = new ArrayCollection;
setAC2(AC1,AC2);
// AC2 is not set to AC1 after the function
private function setAC2(_ac1:ArrayCollection, _ac2:ArrayCollection):void
{
_ac2 = _ac1;
}
Please see Evaluation Strategy.
AS uses "pass by object" / "pass by object-sharing". That is, the "object" is passed (not a copy, clone or duplicate) and any modifications to the object are shared.
However, the assignment _ac2 = _ac1 only changes the value of the [function's local] parameter variable and will have no affect on any variables during the function invocation. The only thing passed in are the values ("objects") which result from the evaluation of the variables (or any arbitrary expression) used in the function invocation.
This is because, as stated above, the strategy used is "pass by object" and not (as the documentation states "pass by reference", which really means, "pass by value [of the reference]" or just ... "pass by object"). That is, the term "pass by reference" is actually misused and hence, confusing. (It is misused in a number of languages and documentation. It is an uphill battle trying to getting to a common meaning.)
If it were really "pass by reference" then assigning a new value to _ac2 would propagate out. (Before posing a comment saying how AS is "pass by reference", please see the link at top and consider that "pass by reference" covers the case of C#'s out/ref, VB's ByRef, TSQL's output and C++'s (reference) & -- these notions are not in AS, Javascript, or Java). However, as correctly noted in the original post (and additional self-reply), it is not the case -- conclusion: AS does not support "pass by reference"; furthermore, the documentation (confusingly) uses the term "pass by reference" to mean "pass by object" / "pass by object-sharing".
There are several ways that the change can be propagate out, ordered by order of (my) preference:
Return the new applicable value: AC2 = doSomeTransformation(AC1). This generally the cleanest. Avoid side-effects and surprising code. Multiple values can be returned if wrapped in an object (or array) as appropriate.
Use a closure: doSomeTranformation(AC1, function (newValue) { AC2 = newValue }) where doSomeTransformation might look like: function doSomeTransformation(_ac1, finished) { ...; finished(_ac1) }. I generally only use this when the callback "runs in context" of the function itself or when writing code in a CPS-style.
Mutate an object (AS is "pass by object", after all). This is very icky, but it will work.
var blah = {AC2: null}; doSomeTransformation(ac1, blah); ...; laterOn(blah.AC2) where doSomeTransformation might look look like function doSomeTransformation(_ac1, b) { ...; b.AC2 = _ac1; }. Not recommended in general.
Happy coding.
Applicable excerpts, from Evaluation Strategy:
"call by reference": (my main argument for "call by reference" being used incorrectly is that it already has a well-defined meaning; the overloaded term adopted by some languages such as AS and Python just adds confusion)
In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value. This typically means that the function can modify the variable used as argument- something that will be seen by its caller.
"call by object" / "call by object-sharing": (but pay heed to where it acknowledges the inconsistency/localization of these terms; the term "call by reference" is often misused to imply these semantics and "call by value [of the reference]" is used in some contexts to also mean the same thing)
The semantics of call-by-sharing differ from call-by-reference in that assignments to function arguments within the function aren't visible to the caller (unlike by-reference semantics), so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call-by-value semantics.
THe function arguments in ActionScript pass by value, not by reference. It is absolutely the same as in Java. You can read in details here.
The problem I am seeing is
var AC1.addItem(someObject);
Try adding the item within a function.
var AC1:ArrayCollection = new ArrayCollection;
var AC2:ArrayCollection = new ArrayCollection;
addItemToArrayCollection( AC1 );
setAC2(AC1,AC2);
// AC2 should be pointing to the ArrayCollection that AC1 is pointing to.
private function setAC2(_ac1:ArrayCollection, _ac2:ArrayCollection):void
{
_ac2 = _ac1;
}
private function addItemToArrayCollection( arrayCollection:ArrayCollection ):void
{
arrayCollection.addItem( someObject );
}
You can add a breakpoint in after the the assignment and see that AC2 should have the same Object as AC1.
I believe that #Constantiner is on the right track, but I think his explanation is lacking detail; so I'm going to try to explain with a bit more depth; as best I understand it. Ya'll can correct me if I'm wrong.
As stated in the docs:
In ActionScript 3.0, all arguments are
passed by reference, because all
values are stored as objects. However,
objects that belong to the primitive
data types, which includes Boolean,
Number, int, uint, and String, have
special operators that make them
behave as if they were passed by
value.
So, an ArrayCollection is definitely an object, and not a primitive type, so it should be passed by reference and act like it was passed by reference. But, what is your reference variable to the ArrayCollection. Conceptually it just a pointer to some memory space that contains the actual Collection data. Here is my attempt at some ASCII art:
|---|
ac1(variable)--> | | (ActualArrayCollection1)
|---|
|---|
ac2(variable)--> | | (ActualArrayCollection2)
|---|
to repeat, ac1variable is a pointer to some memory space. ac2variable is a pointer to some different memory space. When you pass one of them into a method as an argument it is passed by reference. So, inside the method, you have something like this:
ac1(variable)--> |---|
ac1(argument)--> | | (ActualArrayCollection1)
|---|
ac2(variable)--> |---|
ac2(argument)--> | | (ActualArrayCollection2)
|---|
So both ac1variable and ac1argument point at the same memory space; because they each contain the same pointer value. However, ac1variable and ac1argument are actually holding different memory spaces. They are not the same.
When the method runs this line:
_ac2 = _ac1;
You get something like this:
ac1(variable)--> |---|
ac1(argument)--> | | (ActualArrayCollection1)
ac2(argument)--> |---|
ac2(variable)--> |---|
| | (ActualArrayCollection2)
|---|
When the method's execution ends, the two arguments go away, and the original pointer variables remain unchanged. If you want to do a direct assignment like this inside a method, you can access the global variable using the this keyword. This should do it:
this._ac2 = _ac1;
Of course, that can defeat the purpose of encapsulation inside a method if you're accessing class level variables.
I'm sure an expert on compiler design and such things will eat this for breakfast and spit it up. I hope my ASCII art is consistent across multiple browsers / machines / OSes / etc..

Resources