Doing something to all members of a class?
Hi, list!
I'm having a bit of a issue with classes.
Say I have a class that has a member that's simply a integer used for
counting something.
I'll have a few instances (ten or so) and they will all be counting their
own little thing on their own. So far so good. Now something happens and I'd
like to reset all the counters to zero after which they should be
independant again.
How to go about this in a efficient way?
I tried writing a static function to do this but it seems I misunderstand
static functions. I thought that if I'd call a static function as a member
of the class (not of a particular instance) then this function would be
executed for all instances. That turns out not to be true; it only gets
executed a single time. To make it more confusing (to me) referencing
non-static int member of the class inside of a static function makes ChucK
die while complaining about a nullpointer exception. In fact it will also
die if I call the same function as a member of a particular instance. When I
reference the number as "this.my_number" instead of just as "my_number"
ChucK is a bit nicer about it and informs that "this" isn't allowed in
static functions and refuses to run at all (better then suddenly dieing with
cryptic complaints!).
My attempt to figure out what's going on;
===========================
class Foo
{
int my_number;
fun static void bar()
{
<<
Say I have a class that has a member that's simply a integer used for counting I'll have a few instances (ten or so) and they will all be counting their own little thing on Hmm if it is their own thing, it is an instance i.e. non-static variable, not a class variable. A class variable is like a global variable, except
Hi Kassen, Replying in this thread first, as I am still trying to learn enough ChucK to contribute more in our other thread about seqs and such. THis is based on my object-oriented knowledge in general and might be incorrect in the context of ChucK. You have been warned, <smile>. First of all, I think the subject is slightly ambiguous. In programming jargon it could mean one of two things: Members of a class as in the data members e.g. doing something to all data fields of a particular object or class gloablly via reflection. OR what you ment doing something to every instance of a class. that it is restricted in a class. In other words, all the count methods would modify the same variable if the variable is a static variable. This is assuming ChucK's static works like in Java, I'm not sure about that.
happens and I'd like to reset all the counters to zero after which The easiest way to do this would be to have a class method named resetCounter and calling it for each of the instances you have in a loop. Alternatively, you could keep track of all the instances in a static array in the class, and then call the reset method for all the elements in the array. But this latter thing is more complicated and might differ garbage cllection, if it is based on reference counting the objects.
thought that if I'd call a static function as a member of the class Static functions are always called on a class, not on an object. Unless you pass in the object as a parameter but that's suspicious outside of certain scripting languages whose names start with p, in which it is the right way to do it.
then this function would be executed for all instances. It can modify a variable that is common to all instances, that is they all have the same copy and refer to the same variable, but it does not automagically modify anything instance specific as it has no object to work with, only the class data that's global to all objects.
referencing non-static int member of th class inside of a static function That is because chucK does not know hwich object's variable you are accessing. THink of it like this: If you call a non-static method, the variables you are likely to deal with are particular to that instance of the class, although you can access and modify static variables that all the instances share, too. If you call a static method, you are doing something global to all instances, such as modifying a shared static variable. AS the variable is shared, you don't have to have an instance to be able to refer to it.
To illustrate further consider one of those scripting languages I hinted at, such as Perl. In Perl your class or object methods always get a first parameter, if they are called correctly. That argument is an object reference, if it is an object method. ELse it is just a class name string Which can generally only be used to refer to the variables that all instances share i.e. class variables. As an example say we have a person class with name and age as well as a static variable called headCount. Each instance of the class has its own age and its own name, but the member or datafield, if you will, headCOunt is common to all instances. Modifying the headCount, whether it is in a static method or not, wil change a single variable in the class and that change will show up everywhere in that class's methods, because it is just a single variable.
about a nullpointer exception. A semantic quibble, why is it called a null pointer if the language only supports references? I've been thinking the same about Java.
Hope this clarifies matters. IF not, I could try to demonstrate using a code sample. -- With kind regards Veli-Pekka Tätilä (vtatila@mail.student.oulu.fi) Accessibility, game music, synthesizers and programming: http://www.student.oulu.fi/~vtatila/
Hi, Velli-Pekka! THis is based on my
object-oriented knowledge in general and might be incorrect in the context of ChucK. You have been warned, <smile>.
I'll be fine <smile> First of all, I think the subject is slightly ambiguous. In programming
jargon it could mean one of two things: Members of a class as in the data members e.g. doing something to all data fields of a particular object or class gloablly via reflection. OR what you ment doing something to every instance of a class.
Yes, sorry, that was my oops. I meant all instances. So; we'd have a forest made up of lots of instances of the tree class and I want to burn the whole thing down by expressing "every tree is on fire". My "member" type here came from me mucking it up with set theory where such things are very easy to express; you'd simply go "if something is a tree then it's also on fire" and be done. That's what you get when your first real language was Prolog <blush>. Classes have a certain set-theory feel to me, where extending them becomes like sub-sets. Makes sense as a mental model for creating them but clearly less so when adressing them. Hmm if it is their own thing, it is an instance i.e. non-static variable,
not a class variable. A class variable is like a global variable, except that it is restricted in a class. In other words, all the count methods would modify the same variable if the variable is a static variable. This is assuming ChucK's static works like in Java, I'm not sure about that.
I think it does, at least it works like you explain here.
The easiest way to do this would be to have a class method named resetCounter and calling it for each of the instances you have in a loop.
That's exactly what I did now. It turns out I only have 8 instances right now so this is still very managable. Alternatively, you could keep track of all the instances in a static array
in the class, and then call the reset method for all the elements in the array. But this latter thing is more complicated and might differ garbage cllection, if it is based on reference counting the objects.
Yes, I see, and it would also come down to the same thing, except with house-keeping automated. For -say- a dozen instances I can keep track of it by hand.
Static functions are always called on a class, not on an object.
Hmmmm, not nesicarily so in ChucK. It turns out I can call static functions on instances, it's just that it doesn't make any difference from calling them on the class itself. Probably just a syntactic convenience. So, static functions in classes only make sense if they act on other static members of that class and have no real other use? Wouldn't that mean a non-static function would be just as good aside from not being callable on the class itself?
Unless you pass in the object as a parameter but that's suspicious outside of certain scripting languages whose names start with p, in which it is the right way to do it.
Actually, I think that in ChucK you can pass objects as parameters, for axample if you write a function that will do something to a filter you can pass it the reference to a speciffic instance as a parameter. Not so suspicious, to me. That is because chucK does not know hwich object's variable you are
accessing. THink of it like this: If you call a non-static method, the variables you are likely to deal with are particular to that instance of the class, although you can access and modify static variables that all the instances share, too. If you call a static method, you are doing something global to all instances, such as modifying a shared static variable. AS the variable is shared, you don't have to have an instance to be able to refer to it.
Right, yes, I see now. In that case; would it be at all a bad idea to make a new sort of function that would act like I described? That sounds very usefull to me. Clearly something functionally identical could be made but that would mean additional structures to keep track of how many instances we have and what they are called which might complicated matters considderably. Clearly ChucK already has to keep track of those exact things anyway so why not make that info available to the program se we can do things like making all instances of the class "person" jump at the same time? Especially for things like polyphony and particle-based synthesis techniques that would be nice. (I'm sure I'm blundering over a lot of CS concepts right now)
about a nullpointer exception. A semantic quibble, why is it called a null pointer if the language only supports references? I've been thinking the same about Java.
Well, that's another question... I was thinking that ChucK should maybe have caught this when I tried running it like it did when I tried adding the "this" keyword (at that point I still thought I could get the function to execute for every instance in turn). Hope this clarifies matters. IF not, I could try to demonstrate using a code
sample.
Totally clear now, thanks! Kas.
Kassen wrote:
First of all, I think the subject is slightly ambiguous. In Members of a class as in the data members e.g. doing something to all data fields of a particular object or class gloablly via reflection. OR what you ment doing something to every instance Yes, sorry, that was my oops. I meant all instances. No prob, thinking of the attributes or data fields of a class as data members is probably from C++, anyway, not from Chuck or Java.
My "member" type here came from me mucking it up with set theory I see, well even programmers talk about members in sets, lists and what-ever. Though often the terms item and element are used interchangibly.
That's what you get when your first real language was Prolog <blush>. Hey, Prolog is cool for certain things about formal reasoning.But it is not at all good for sorting data efficiently, for instance.
[calling method on all instances]
Alternatively, you could keep track of all the instances in a static array in the class, and then call the reset method for all the elements For -say- a dozen instances I can keep track of it by hand. Though better put them inside some data structure, in CHucK I guess that would be an array. That way your code which processes one element at a time, is not in anyway dependent on how many items you have. BEtter yet if you abstract getting the next item into a method call on a class called an iterator, you can traverse data structures totally independently of what datastructure is actually being used. So if you changed from a linked list to an array, your processing functions might not have to be modified.
Static functions are always called on a class, not on an object. turns out I can call stati functions on instances Ah well, that's syntactic sugar then. But say in Java, some classes cannot be instanciated. SO for those you cannot have objects against which to call those methods, <smile>.
that mean a non-static function would be just as good aside from not being callable on the class itself? If it modified static data that's shared by all instances, then yes. But it makes more sense to say: Person.getHeadCount() than it would be to say: joe.getHeadCOunt() # Supposing Joe is instance of Person and doesn't have multiple heads.
Unless yo pass in the object as a parameter Actually, I think that in ChucK you can pass objects as parameters, Ah yes and that's highly useful. I should have said: Unless object-orientation is based on the object being implicitly passed to a function as its first parameter. Many scripting languages transform: object.method(params) # supposing object is instance of class into class.method(object, params)
for axample if you write a function that will do something to a filter Exactly, this is very powerful. Calling a similarly named, and often similarly typed, method on different kinds of objects and them doing their own things is called polymorphism, fancily put.
ChucK should maybe have caught this when I tried running it Yes, I think so, too. IT could very well be checked at compile time that is
For example, you could have a class that traverses a tree, say a folder tree, and then calls a particular method when it changes to a folder or backs up a level. By making many sub-classes that do different things in such circumstances you could count sizes, delete files or what-ever, just by plugging in an instance of some derived class in the ttree traversal algorithm, or in chucK, any classs that happens to have a similarly named method to the one being called. If your method takes something inheriting from the tree traversal base class as a parameter, you have a very very generic method for doing things on trees. I think ChucK as many other langs let you type in Foo f and assign f anything derived from Foo as it has the same methods as Foo does. This is called polymorphism in langs like Java. But if ChucK is duck typed, then anything whose methods are named like those of Foo, whether or not it inherits from Foo, could be used equally well. I'm thinking of creating a base class for processing MIDI events which has methods for registering new objects. All of the registered objects will then be notified of new events and they must inherit from some event Observer class. So they can do their own thing and you can register objects as event listeneres, even at runtime. This reminds me of a heavily used object-oriented design pattern named observer. The article is not as good as the Gang of FOur Design Patterns book, but see: http://en.wikipedia.org/wiki/Observer_pattern [accessing instance data in a static method] prior to running. But That does not work for all languages. Perl, for example, let's you replace functions or methods at runtime based on references or evaluated code, so its typing is weaker, or if you like this kind of thing, more dynamic. It canot be checked at runtime. -- With kind regards Veli-Pekka Tätilä (vtatila@mail.student.oulu.fi) Accessibility, game music, synthesizers and programming: http://www.student.oulu.fi/~vtatila/
Kassen wrote:
Say I have a class that has a member that's simply a integer used for counting something.
I'll have a few instances (ten or so) and they will all be counting their own little thing on their own. So far so good. Now something happens and I'd like to reset all the counters to zero after which they should be independant again.
How to go about this in a efficient way?
Here's an example implementation: class Foo { class ListNode { ListNode @ next; Foo @ item; } static ListNode @ first; static ListNode @ last; if(first == null) { new ListNode @=> first; first @=> last; this @=> first.item; } else { new ListNode @=> last.next; last.next @=> last; this @=> last.item; } 0 => int value; fun void increment() { value++; } fun void print() { <<< value >>>; } fun static void reset() { for(first @=> ListNode @ node; node != null; node.next @=> node) { 0 => node.item.value; } } } Foo a; Foo b; Foo c; a.increment(); b.increment(); b.increment(); c.increment(); c.increment(); c.increment(); a.print(); b.print(); c.print(); Foo.reset(); a.print(); b.print(); c.print(); Which produces: 1 :(int) 2 :(int) 3 :(int) 0 :(int) 0 :(int) 0 :(int) The first part is just an outline of a linked list. Items are inserted into the list as they are created. Then in the static function we go through the list and modify each instance. The conceptual problem that you had is that static functions operate on *no* instance of a class rather than *all* instances of a class. Static functions can only access static variables since the others are not available (since there's no instance there for them to access). -Scott
On 3/13/07, Scott Wheeler
The conceptual problem that you had is that static functions operate on *no* instance of a class rather than *all* instances of a class. Static functions can only access static variables since the others are not available (since there's no instance there for them to access).
Yes, that's it exactly! My reasoning was that it looked to me like changing a static variable acted on all members and that this would mean that static functions would work in the same way. This idea got reinforced by Chuck allowing me to adress static functions as members of instances and it not being very clear *why* this led to issues so I just tried all variations that I could think of. Oh, well, another great learning experience and another thing found that could stand clarification in the docs. The examples do corectly adress only static variables but they don't explain why they do so. I thought they were taking static integers as a target because that section was explaining those as well and that I could abstract this and aply it to other sorts of things as well. Thanks for your clear explanation, realy like that way of doing lists as well, BTW. Kas.
Kassen wrote:
Yes, that's it exactly! My reasoning was that it looked to me like changing a static variable acted on all members and that this would mean that static functions would work in the same way.
This idea got reinforced by Chuck allowing me to adress static functions as members of instances and it not being very clear *why* this led to issues so I just tried all variations that I could think of.
Yes, that makes sense. I think many ChucK users and certainly the developers come from a C++ / Java background, so things like the static keyword are already known. Probably an even better way of explaining static variables is that they're basically the same as global variables, just with the class name there as an organizational convenience. So a static variable is just a global variable with "Foo." prepended. The same is true for functions. So, again, examples: 0 => int fooCount; fun void resetAllFoo() { // ... } vs. class Foo { 0 => static int count; fun static void resetAll() { // ... } } Those are functionally equivalent. The second one makes it possible to write things in a more tidy Foo.count and Foo.resetAll(), but there's no difference in what they're able to access. (Note: This is slightly different from C++ or Java, but it's probably not worth explaining the subtleties just now.) Cheers, -Scott
On 3/13/07, Scott Wheeler
developers come from a C++ / Java background, so things like the static keyword are already known.
Yes, I ran into other situations where things were unclear to me in similar ways before. I have more of a background in formal logic so I get the overall structures of how things work and how to try to acomplish tasks on a abstract level but I run into trouble with things like this, at least when I want to do it nicely and compactly. A similar thing happened with the way the old keyboard function returned key-presses. That turned out to be very standard and quite usable but that's hard to deal with when you don't know what "standard" is. Personaly I like it this way; I get to pick up lots of tricks that will likely be usefull in the future and clearly the bits taken from C++ and java work very well but there might also be a lesson here. It'd be good to keep a eye on things like this and try to document these things a bit more explicidly because I'm not the only one for whom ChucK is the first encounter with real object oriented programing (especially on the forum there are people signing up that are just starting to write any code at all) and hopefully there will be many more (considdering the educational goals). Happy to be a guinea pig, Kas.
On 3/12/07, Kassen
Hi, list!
I'm having a bit of a issue with classes.
Say I have a class that has a member that's simply a integer used for counting something.
I'll have a few instances (ten or so) and they will all be counting their own little thing on their own. So far so good. Now something happens and I'd like to reset all the counters to zero after which they should be independant again.
How to go about this in a efficient way?
Hi Kassen, I could be wrong, but I think you do the following: 1. Give the class a reset method 2. Every time you create an instance, add the instance to an array 3. To reset, run your reset method on all instances contained in the array A more automated way, though I'm not entirely sure if/how it would work in ChucK: 1. Give the class a reset method 2. Give the class a static array property 3. In the class initialization code, add objects to the static array when they are initialized 4. Add a static reset method, that runs the object reset method from (1) on each instance of the static array. 5. Run the static reset method to reset everything while you are ChucK-ing.. ***Warning: most OOP I do is in Flash Actionscript 2.0 right now, which is far from a good programming language. Take this with a grain of salt, but it should theoretically work to the best of my knowledge.
On 3/13/07, David Powers
I could be wrong, but I think you do the following: 1. Give the class a reset method 2. Every time you create an instance, add the instance to an array 3. To reset, run your reset method on all instances contained in the array
Yes, that's exactly what it comes down to. A more automated way, though I'm not entirely sure if/how it would
work in ChucK: 1. Give the class a reset method 2. Give the class a static array property 3. In the class initialization code, add objects to the static array when they are initialized
Right! This would be by asigning "this" (the keyword) to the array at the first location that's not yet used, right? We'd simply make the array quite large to have headroom for later growth. 4. Add a static reset method, that runs the object reset method from
(1) on each instance of the static array. 5. Run the static reset method to reset everything while you are ChucK-ing..
***Warning: most OOP I do is in Flash Actionscript 2.0 right now, which is far from a good programming language. Take this with a grain of salt, but it should theoretically work to the best of my knowledge.
No, as far as I understand it now that would work fine and it's actually quite clever and clean, I think. I think I'll use this method, it will also make what I'm doing now far easier to extend without having to manually keep house in some arbitrary spot. I don't like it when things that are that important to the overall stability have no clear place in the program. Thanks! Kas.
David Powers wrote:
2. Give the class a static array property
This is what I first tried in the implementation that I sent, but I quickly ran into a (documented, http://wiki.cs.princeton.edu/index.php/ChucK/Bugs/Known) ChucK bug. Static objects are not properly initialized, which includes arrays. And unlike other objects, it seems that you can't assign an array to an Object. (i.e. "new int[20] @=> Object foo;" doesn't work) The only way I saw to work around this was creating another class as an array handle and using that by reference. So: class Foo { class ArrayHandle { int values[20]; } static ArrayHandle @ handle; if(handle == null) { new ArrayHandle @=> handle; } // ... } Then all access to the value array has to be done via handle.values[...]. But then that was almost as much code as writing the list. :-) -Scott
Scott/David/all, On Mar 13, 2007, at 9:49 PM, Scott Wheeler wrote:
The only way I saw to work around this was creating another class as an array handle and using that by reference.
Another potential workaround for this bug would be to declare an empty array, which allocates no memory for array elements, is "sort of" like an array reference, and manages to get around the static data member bug. You can then to chuck a new array to it to initialize it. E.g., int values[20] @=> Foo.values; class Foo { static int values[]; // ... } One technique I like is to initialize static class data at the beginning of the file containing the class definition. The advantages of this approach are that the initialization is guaranteed to be executed only once, is guaranteed to be executed if no fatal errors occur during the initialization, is executed before anything else can use it (though Im not positive this is guaranteed), and doesn't require an instance of the class to have already been created. If the class definition is at the top of the file, it sometimes makes sense to put the initialization code immediately after the class definition, which is functionally the same but might read a little better.
And unlike other objects, it seems that you can't assign an array to an Object. (i.e. "new int[20] @=> Object foo;" doesn't work)
This now works as of the current release candidate! However, I dont think there is a way to get the array data out of an object stored in an Object reference (foo $ int[] doesn't work). spencer
participants (5)
-
David Powers
-
Kassen
-
Scott Wheeler
-
Spencer Salazar
-
Veli-Pekka Tätilä