Passing an object parameter to execute() in a function

Anything that doesn't fit elsewhere.
Post Reply
ryang
Posts: 17
Joined: Wed Mar 21, 2018 6:34 pm

Passing an object parameter to execute() in a function

Post by ryang »

I'm am trying to build an object function that adds a cluster of synapses to a dendrite of a neuron that is defined in a class, and returns the synapse objects in a List. I would like to pass the synapse (MOD object) as a parameter in the function. To attempt this I am passing the name of the MOD object as a string parameter and then using sprint() and execute() to add the synapse to the appropiate dendrite segment. This is the code I'm using :

Code: Select all

//$o1: Synpase parameter list
//$o2: Cell object
//$s3: Mod object
obfunc Add_Synapses(){\
	local i, j, jump_distance, position, next_position\
	localobj synapse_list, command, cell
	command = new String()
	synapse_list = new List()
	for i=0,11{
		jump_distance = 0.5/$o1.o[1].x[i] //distance to adjacent synapse as percentage
		position = $o1.o[2].x[i]/$o1.o[1].x[i] //Synapse starting insertion location as percentage
		for j=0,$o1.o[3].x[i]-1{
			next_position = position-(-1)^j*jump_distance*j //next location (first time j=0)
			position = next_position //save last location
			sprint(command.s, "$o2.dendrite[$o1.o[0].x[i]] synapse_list.append(new %s(next_position))", $s3)
			execute(command.s)
		}
	}
	return synapse_list 
}//Add_Synapses
I would then call the function like this, where AMPA_S is defined in a MOD file:

Code: Select all

objref reference_AMPA
reference_AMPA = Add_Synapses(reference_parameters, cell, "AMPA_S")
As it stands I get the following error:

Code: Select all

/Applications/NEURON-7.5/nrn/x86_64/bin/nrniv: $o used outside definition
 in Build_Cell.hoc near line 1
 {$o2.dendrite[$o1.o[0].x[i]] mod_object.append(new AMPA_S(next_position))}
    ^
        execute("$o2.dendri...")
      Add_Synapses(List[12], ..., "AMPA_S")
initcode failed with 1 left
/Applications/NEURON-7.5/nrn/x86_64/bin/nrniv: execute error: $o2.dendrite[$o1.o[0].x[i]] mod_object.append(new AMPA_S(next_position))
 in Build_Cell.hoc near line 32
If I understand corretly, excute can't take the passed object parameters. Is there anyway around this problem? Any help would be greatly appreciated.
ted
Site Admin
Posts: 6289
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Passing an object parameter to execute() in a function

Post by ted »

Forget your hypotheses about why your code didn't work--there were just too many syntax errors (for example, a variable cannot be declared to be an objref inside a procedure or function unless it has previously been declared to be an objref at the top level of the interpreter ("top level" means outside of any procedure, function, or object)).

The solution is a bit more complex than I first imagined because execute() executes its command string at the top level. Consequently a string that contains the name of a localobj will cause execute() to fail (because the localobj will not exist at the top level).

The key to the solution is to create an obfunc that creates just one instance of a synaptic mechanism class at a user-specified location on the currently accessed section, then returns an objref that references that instance. Here is such an obfunc:

Code: Select all

strdef cmdstr
objref tmpobj

obfunc newsyn() { localobj tobj
  sprint(cmdstr, "tmpobj = new %s(0.5)", $s1)
  execute(cmdstr)
  tobj = tmpobj
  objref tmpobj
  return tobj
}
Note that cmdstr and tmpobj must be declared outside of (and before) the code that defines newsyn(). "Why do you bother with tobj? Why not just return tmpobj?" That would work, but after exit from newsyn() the tmpobj variable would still point to the new synaptic mechanism, which plants a big trap in your program, e.g. a statement that tries to exercise a method that the synaptic mechanism doesn't have would halt program execution, and a statement that exercises a method that the synaptic mechanism DOES have could be even worse because it might not produce an error message but could instead alter one of the synaptic mechanism's parameters. It is best to destroy the link between tmpobj and the synaptic mechanism before exiting from obfunc newsyn.

How to use obfunc newsyn? Consider this example:

Code: Select all

// creates a synaptic mechanism at each internal node of the currently accessed section
// and returns a List that point to these new mechanisms.
// $s1 holds the mechanism's name
obfunc makesyns() { localobj tlist
  tlist = new List()
  for (x,0) { // or whatever rule you use to decide how many to make
    tlist.append(newsyn($s1))
  }
  return tlist
}

objref syns
dend syns = makesyns("ExpSyn")
// check the result
for i=0,syns.count()-1 print syns.o(i)
ryang
Posts: 17
Joined: Wed Mar 21, 2018 6:34 pm

Re: Passing an object parameter to execute() in a function

Post by ryang »

I think I misunderstood the use of obfunc, I saw it as being something different than a func or proc call and hence I thought I could get away without declarying an objref outside the obfunc type function. Yet, I still have a hang up in my understanding, why can you declare tlist as a localobj in makesyns() and return it. I've written some obfunc type functions that do a simalar thing, for example in the simple case:

Code: Select all

//$o1: Cell object soma
//$2: tstop, for recording vector size
//$3: soma recording segment
obfunc Record_Soma(){\
	localobj v_record
	v_record = new Vector($2)
	v_record.record(&$o1.soma.v($3))
	return v_record
}//Record_Soma()
and I call it like so and graph the v_soma:

Code: Select all

objref v_soma
v_soma = Record_Soma(cellObject, tstop, 0.5)
Why does it work in this case? Or is somethign problematic going on I haven't noticed?
ted
Site Admin
Posts: 6289
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Passing an object parameter to execute() in a function

Post by ted »

A statement of the form
foo = new Bar()
creates an instance of the Bar class and tells hoc that foo refers to that instance.

This

Code: Select all

objfunc baz() { . . .
  . . .
  foo = new Bar()
  . . .
  return foo
}
creates and returns an instance of the Bar class regardless of whether foo is an objref or a localobj.
ryang
Posts: 17
Joined: Wed Mar 21, 2018 6:34 pm

Re: Passing an object parameter to execute() in a function

Post by ryang »

Thank you! Ok,I beleive I understand. I cannot declare an objref in a function or porcedure but I can return a localobj from a function and have an objref point to the returned localobj.

So, back to the orignal problem. If I use excute() in a function then any objref refered to within excute() must exist at the top level of the interperuter. Also, don't forget to point a temporary objref back to NULL when your done with it. Thank you for your solution to this problem, I now see how to proceed.

Best
ted
Site Admin
Posts: 6289
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Passing an object parameter to execute() in a function

Post by ted »

I beleive I understand. I cannot declare an objref in a function or porcedure
To prevent any misunderstanding by others who may read this thread, here some things about objrefs to keep in mind (this information is all contained in the Programmer's Reference).
1. If a variable name is to be used as an objref, it must be declared to be an objref the very first time it appears in a program.
2. This declaration must be done outside of any proc or func.
3. If foo is already an objref, the statement
objref foo
can be executed again at the top level or inside a proc or func in order to break the association between foo and whatever object instance it referenced.
I can return a localobj from a function and have an objref point to the returned localobj
The statement
return foo
where foo is a localobj does not return the localobj. It returns a reference to whatever object instance foo points to.
If I use excute() in a function then any objref refered to within excute() must exist at the top level of the interperuter.
execute("statement")
executes the "statement" at the top level of the interpreter (i.e. outside of any object, proc, or func).

execute() can also be called with an objref as the second argument, for example
execute("statement", foo)
and doing this will execute the "statement" in the context of the object instance that foo points to (see the Programmer's Reference entry about execute() https://www.neuron.yale.edu/neuron/stat ... ml#execute).
don't forget to point a temporary objref back to NULL when your done with it
That is the safest thing to do. It is not necessary with localobjs because a localobj disappears after exit from a proc or func.
Post Reply