Re: How to modify class variables?
Alexander Burger wrote: (...) > There was one more class variable, 'aux'. I changed that, too. The > problem was that both 'dbf' and 'aux' exist also as object attributes, > so I had to be very careful when changing some of them to upper case. > > I checked it in as new testing release. Any feedback (or error notes) > welcome! > At least it worked under MacOS/X 10.6 (Intel) and 10.5 (PPC). :-) But I would suppose to document this proposal also in the Reference Manual under "Naming Conventions". > Cheers, > - Alex > Ciao, cle. -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
On Thu, Dec 10, 2009 at 01:18:03PM +0100, Alexander Burger wrote: > applications. The only class variable I can find in the picoLisp release > is 'dbf'. I'll change that to 'Dbf', as I believe that it is normally > not used in applications. Phew, I hope I didn't break anything ;-) There was one more class variable, 'aux'. I changed that, too. The problem was that both 'dbf' and 'aux' exist also as object attributes, so I had to be very careful when changing some of them to upper case. I checked it in as new testing release. Any feedback (or error notes) welcome! Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hi Cle, > Perhaps we should propose a naming convention, that class variables > should begin with an uppercase letter, whereas instance variables should > begin with a lowercase letter. This is a good idea. We just need to be tolerant with that, as existing code won't obey that rule yet. I probably won't change existing (non-publicly visible) applications. The only class variable I can find in the picoLisp release is 'dbf'. I'll change that to 'Dbf', as I believe that it is normally not used in applications. Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Alexander Burger wrote: > Hi Cle, Hi Alex, >>> (dm foos> () (mapcar cdr (val (: Foos))) ) >> .. >> Howevery only if the receiver is the class. If I use an instance >> as receiver, it would not work! I would like to code the method the >> way, that the method will work regardless if the receiver is a >> class or one of its instances; like it works in Smalltalk, C++, >> Java, Ruby ... > > This is rather straightforward: > > (dm foos> () (mapcar cdr (val (or (: Foos) (var: Foos ) Cool! This is nearly perfect :-) Really nice! Thank you :-))) (...) > With this solution we still avoid hard-coding the class into the > method, which would give problems, for example, if the 'foos>' method > were inherited by a subclass. Superb! :-) My real class is now working nicely without hard coding the class' name within a method due to your hints. :-) And I have learned a bit more ... > Cheers, - Alex Ciao, cle. -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Alexander Burger wrote: > Let me correct a wrong statement: > > On Thu, Dec 10, 2009 at 08:32:38AM +0100, Alexander Burger wrote: > >> The reason is that all inheritance mechanisms (message passing, >> lookup with 'meta', 'var:', etc) start searching one level above the >> current object. >> > > This is only true for 'meta' and derived functions, which search for a > property in the classes and superclasses of a symbol. > > In case of messages, however, the search for a method starts in the > object, and then continues in the classes and superclasses. Methods are > not stored in properties, but in an assoc list in the object's or > class's value cell. > > This was a deliberate design decision. It should be possible for an > object to override a method privately. But "class variables" (the > properties in classes and superclasses) should > >1. really reside in classes, and >2. not conflict with local attributes of objects > > Therefore the term (or (: name) (var: name)) must be used explicitly if > both places should be searched. > Perhaps we should propose a naming convention, that class variables should begin with an uppercase letter, whereas instance variables should begin with a lowercase letter. So we could avoid a possible glitch where a class define an instance variable (let's say) 'id' thereby shadowing a class variable 'id'. With your proposed term above, the instance variable would silently be taken. So adhering to such a naming convention could prevent hassle ... :-) (...) Ciao, cle. -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Let me correct a wrong statement: On Thu, Dec 10, 2009 at 08:32:38AM +0100, Alexander Burger wrote: > The reason is that all inheritance mechanisms (message passing, > lookup with 'meta', 'var:', etc) start searching one level above the > current object. This is only true for 'meta' and derived functions, which search for a property in the classes and superclasses of a symbol. In case of messages, however, the search for a method starts in the object, and then continues in the classes and superclasses. Methods are not stored in properties, but in an assoc list in the object's or class's value cell. This was a deliberate design decision. It should be possible for an object to override a method privately. But "class variables" (the properties in classes and superclasses) should 1. really reside in classes, and 2. not conflict with local attributes of objects Therefore the term (or (: name) (var: name)) must be used explicitly if both places should be searched. Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hi Cle, > > (dm foos> () (mapcar cdr (val (: Foos))) ) >.. > Howevery only if the receiver is the class. If I use an instance as > receiver, it would not work! I would like to code the method the way, > that the method will work regardless if the receiver is a class or one > of its instances; like it works in Smalltalk, C++, Java, Ruby ... This is rather straightforward: (dm foos> () (mapcar cdr (val (or (: Foos) (var: Foos ) Then we can try : (foos> '+Foo) # Send message to class -> ($385464611 $385464635 $385464656) : (foos> '$385464611) # Send message to object -> ($385464611 $385464635 $385464656) With this solution we still avoid hard-coding the class into the method, which would give problems, for example, if the 'foos>' method were inherited by a subclass. Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Alexander Burger wrote: > Hi Cle, Hi Alex, back from shopping outside, I read your explanations. Let me thank you. Although I have read the reference manual several times (and have it open while I am coding) I did oversee 'push' and 'queue' totally :-( But I know about 'inc' but for my learning purposes, I did it more complicate on purpose here ... however, thanks anyway you for trying to improve my skills :-) > On Thu, Dec 10, 2009 at 08:32:38AM +0100, Alexander Burger wrote: >> oops, didn't look carefully enough. The 'foos>' method must, as in >> your *1c* case, specify the current '*Class' directly: >> >> (dm foos> () (mapcar cdr (val (get '`*Class 'Foos))) ) > > Now I begin to grasp your intention. "Hard coding" the class into a > method is not nice. So wouldn't simply I second your reason, it is not nice, but ... > (dm foos> () (mapcar cdr (val (: Foos))) ) > > do what you want? Howevery only if the receiver is the class. If I use an instance as receiver, it would not work! I would like to code the method the way, that the method will work regardless if the receiver is a class or one of its instances; like it works in Smalltalk, C++, Java, Ruby ... So is there a possibility to trick with e.g. 'with' or 'var:' access the value regardsless of the receiver? Thank you for your effort to explain me the mechanisms so far ... :-) Ciao, cle. (...) -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hi Cle, On Thu, Dec 10, 2009 at 08:32:38AM +0100, Alexander Burger wrote: > oops, didn't look carefully enough. The 'foos>' method must, as in your > *1c* case, specify the current '*Class' directly: > >(dm foos> () > (mapcar cdr (val (get '`*Class 'Foos))) ) Now I begin to grasp your intention. "Hard coding" the class into a method is not nice. So wouldn't simply (dm foos> () (mapcar cdr (val (: Foos))) ) do what you want? Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hi Cle, oops, didn't look carefully enough. The 'foos>' method must, as in your *1c* case, specify the current '*Class' directly: (dm foos> () (mapcar cdr (val (get '`*Class 'Foos))) ) As you observed, (var: Foos) will not work if 'This' is the class itself. The reason is that all inheritance mechanisms (message passing, lookup with 'meta', 'var:', etc) start searching one level above the current object. Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hi Cle, > ==8X== > (class +Foo) > # id > > (var N 0) > (var Foos ()) > > (dm nextId> () (set (var: N) (+ (car (var: N)) 1))) Just a side-note: While this is correct, you could here take advantage of the 'inc' operator: (dm nextId> () (inc (var: N))) > (dm T () > (=: id (pack "Foo#" (nextId> This))) > (conc (var: Foos) (list (cons (: id) This))) > ) > > # (dm foos> () (mapcar '((X) (car X)) (var: Foos)))# *1a* > # (dm foos> () (mapcar '((X) (car X)) (get '`*Class 'Foos))) # *1b* > (dm foos> () (mapcar '((X) (cdr X)) (get '`*Class 'Foos))) # *1c* > > (dm show> () (prinl "Foo id=" (: id))) > > > (show> (new '(+Foo))) > (show> (new '(+Foo))) > (show> (new '(+Foo))) > > # (prinl "Foos: " (mapcar '((X) (prinl X)) (foos> '+Foo))) # *2a* > # (prinl "Foos: " (mapcar '((X) (prinl (type X))) (foos> '+Foo))) # *2b* > (prinl "Foos: " (mapcar '((X) (show> X)) (foos> '+Foo))) # *2c* > > > (show '+Foo) > ==8X== > ... > If you execute the code as is, an error will issued at *2c*, that the > message 'show>' is not understood. But if > > * I use *1b* and *2a* instead of *1c* and *2c* the correct id stored in > the CAR of every element in the assoc list will be printed. > * I use *1c* and *2b* instead, a type of +Foo will be reported for > every instance held in the CDR of every association. > * However, using *1a* instead of *1b* or *1c* will get me nowhere at > all, despite I think it should have worked :-( > > To summarize, *1a* will not deliver, what I expect, but *1b* and *1c* > seem to return what I want! Asking for the type of every instance held > in the association list *2b* will answer +Foo correctly. But sending a > 'show>' to every instance (*2c*) will repsond with "Bad message". > > So please enlight me, where is my stumble block? What did I wrong? The initial error is the 'conc' in the 'T' method. It concatenates the (id . object) pairs to 'Foos', which is (NIL) in the beginning. So the list has always NIL as its first element. Then, sending the message 'show>' to that NIL gives an error. You could take 'push' or 'queue' instead. I use 'queue' here, because 'push' would reverse the order: (dm T () (=: id (pack "Foo#" (nextId> This))) (queue (var: Foos) (cons (: id) This)) ) But then, of course, 'Foos' has an additional level of nesting. To access the list, you must use 'car' or 'val': (dm foos> () (mapcar cdr (val (var: Foos The complete program would then look like: ==8X== (class +Foo) # id (var N 0) (var Foos ()) (dm nextId> () (inc (var: N)) ) (dm T () (=: id (pack "Foo#" (nextId> This))) (queue (var: Foos) (cons (: id) This)) ) (dm foos> () (mapcar cdr (val (var: Foos))) ) (dm show> () (prinl "Foo id=" (: id)) ) (show> (new '(+Foo))) (show> (new '(+Foo))) (show> (new '(+Foo))) (prinl "Foos: " (mapcar 'show> (foos> '+Foo))) (show '+Foo) ==8X== Is this what you intended? Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
First let me thank you and Henrik for the insight you gave me. Alexander Burger wrote: > And one more thing I just remember: > > On Wed, Dec 09, 2009 at 01:10:21PM +0100, Alexander Burger wrote: >> There is no separate 'set'ter function needed, as the 'any' >> argument in >> >> (var sym . any) > > A 'set'ter function would be pretty useless if there is no value yet, > or if the value were set to NIL once, because if there is no value > the property cannot be inherited, i.e. the class in the hierarchy > that is supposed to receive that value cannot be found :-) > > So a NIL value _must_ be defined as > > (var name NIL) > > to have a cell with NIL in its CAR, but still a non-empty property > that can be inherited. Later you can do things like > > (set (var: name) 123) > > and the '123' will arrive in the correct class. Stupid me, but I did not recognize that I could use 'set' for those task :-} This would be exactly the behavior I need ... But there seems to be something that slip me. I have wrote some example code, that show the behavior I need. ==8X== (class +Foo) # id (var N 0) (var Foos ()) (dm nextId> () (set (var: N) (+ (car (var: N)) 1))) (dm T () (=: id (pack "Foo#" (nextId> This))) (conc (var: Foos) (list (cons (: id) This))) ) # (dm foos> () (mapcar '((X) (car X)) (var: Foos)))# *1a* # (dm foos> () (mapcar '((X) (car X)) (get '`*Class 'Foos))) # *1b* (dm foos> () (mapcar '((X) (cdr X)) (get '`*Class 'Foos))) # *1c* (dm show> () (prinl "Foo id=" (: id))) (show> (new '(+Foo))) (show> (new '(+Foo))) (show> (new '(+Foo))) # (prinl "Foos: " (mapcar '((X) (prinl X)) (foos> '+Foo))) # *2a* # (prinl "Foos: " (mapcar '((X) (prinl (type X))) (foos> '+Foo))) # *2b* (prinl "Foos: " (mapcar '((X) (show> X)) (foos> '+Foo))) # *2c* (show '+Foo) ==8X== The idea is, that every instance get an id generated by a counter implemented as class variable 'N'. Then the constructor will register the instance in a assoc list also held by a class variable too 'Foos'. If you execute the code as is, an error will issued at *2c*, that the message 'show>' is not understood. But if * I use *1b* and *2a* instead of *1c* and *2c* the correct id stored in the CAR of every element in the assoc list will be printed. * I use *1c* and *2b* instead, a type of +Foo will be reported for every instance held in the CDR of every association. * However, using *1a* instead of *1b* or *1c* will get me nowhere at all, despite I think it should have worked :-( To summarize, *1a* will not deliver, what I expect, but *1b* and *1c* seem to return what I want! Asking for the type of every instance held in the association list *2b* will answer +Foo correctly. But sending a 'show>' to every instance (*2c*) will repsond with "Bad message". So please enlight me, where is my stumble block? What did I wrong? Thanks and ciao, cle. -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
And one more thing I just remember: On Wed, Dec 09, 2009 at 01:10:21PM +0100, Alexander Burger wrote: > There is no separate 'set'ter function needed, as the 'any' argument in > >(var sym . any) A 'set'ter function would be pretty useless if there is no value yet, or if the value were set to NIL once, because if there is no value the property cannot be inherited, i.e. the class in the hierarchy that is supposed to receive that value cannot be found :-) So a NIL value _must_ be defined as (var name NIL) to have a cell with NIL in its CAR, but still a non-empty property that can be inherited. Later you can do things like (set (var: name) 123) and the '123' will arrive in the correct class. Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
On Wed, Dec 09, 2009 at 09:15:01AM +0100, Henrik Sarvell wrote: > Don't forget, in some cases it's simply enough with ::, for instance > (pop (:: classVar)). Just to make the discussion complete :-) Yes, completely correct. This is the reason why this 'var' mechanism is called that way (and not, say, 'const'). There is no separate 'set'ter function needed, as the 'any' argument in (var sym . any) can always be selected appropriately to hold any desired value. Let's say you want to hold three coordinates in a class variable, you could do : (class +Cls) ... : (var pos 0 0 0) -> (0 0 0) : (setq X (new '(+Cls))) : (with X (set (var: pos) 1) (set (cdr (var: pos)) 2) (set (cddr (var: pos)) 3) ) -> 3 : (with X (var: pos)) -> (1 2 3) : (get '+Cls 'pos) -> (1 2 3) Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hi Cle, > > (put '+aClass 'ClassVar "new value") > > > > and perhaps write a utility function. > > thanks for the hint. Is there any special reason, why there is no such > utility function in picoLisp for that task? I mean defining and querying > helpers exists ... :-/ Because it was not needed until now ;-) > Do you have any proposal, what such a helper/utility function should be > called to fit into (var:) (var) functions that already exists? > ... > Yep, like in Ruby or Smalltalk for instance ;-) I really need a counter, > that is member of the class, as instance creation will increment said > counter. The proper way to access properties in the class hierarchy is 'meta'. 'meta' is also used internally by 'var:'. Though it only returns a value, it can be used for the purposes you have in mind if you reserve a cell (also a "variable" in picoLisp terms) for it. (class +aClass) .. (var counter 0) .. (meta MyObj 'counter) # -> (0) (with MyObj (var: counter) # -> (0) (car (var: counter)) # -> 0 ... (inc (var: counter)) # -> 1 ) Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Alexander Burger wrote: > Hello Cle, Hello Alex, (...) > In terms of "beauty", there are not many options, though. I would > use: > > (put '+aClass 'ClassVar "new value") > > and perhaps write a utility function. thanks for the hint. Is there any special reason, why there is no such utility function in picoLisp for that task? I mean defining and querying helpers exists ... :-/ (...) > Yes, it depends on 'This' being bound. Ah ok, then I understood, I think :-) > BTW: There is no such thing as "the class" of an instance. There is > always a list of classes. (car (type This)) might not be the right > class, the "main" class is usually (last (type This)) while the > other classes in the list are usually "prefix" classes. I now, therefore I had hoped for a class variable setter, that would allow to update a class variable in the first class where it was found. Right so as the querying function (var:). Do you have any proposal, what such a helper/utility function should be called to fit into (var:) (var) functions that already exists? >> The only way I found working reliable (use class regardless if in >> a method send to a class or an instance) seem to be > > Note that in picoLisp there is no formal difference between objects > and classes. Objects may have local method definitions, and classes > have instance variables. So it just depends on the context, and on > what the programmer has in mind, if a symbol is regarded as an object > or as a class. Yep, like in Ruby or Smalltalk for instance ;-) I really need a counter, that is member of the class, as instance creation will increment said counter. >> (with '`*Class ...) >> >> Is this the correct way, or did I overlook something? > > I'm not sure I completely understood what you want to achieve. This > is correct, if you want to capture the current class. Again, you > could also simply use 'put' here. Hmmm ... if I do not write an utility function, I will switch to 'put' here. And yes, in this case I want to capture the current class. However, if I fiddle out, what such an utility function should look like, I will probably use that function then, instead of capturing the current class ... > Cheers, - Alex Ciao, cle. -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Don't forget, in some cases it's simply enough with ::, for instance (pop (:: classVar)). Just to make the discussion complete :-) /Henrik On Wed, Dec 9, 2009 at 7:53 AM, Alexander Burger wrot= e: > Hello Cle, > >> Now I have detected the class variables I want to use now. But the >> question raise, how to update a class variable? >> ... >> But for update, I only came up with this ugly code: >> >> =A0 =A0(with '+aClass >> =A0 =A0 =A0(=3D: ClassVar "new value")) > > 'with' is - in terms of processing - indeed a little overkill, as it > does an extra binding of 'This'. > > In terms of "beauty", there are not many options, though. I would use: > > =A0 (put '+aClass 'ClassVar "new value") > > and perhaps write a utility function. > > > >> And another question in that context: how can I get the class of an >> instance usable for (with)? If I try >> >> =A0 =A0(with This ...) >> >> I have to send the method to the class directly and not via an instance. >> However if I try >> >> =A0 =A0(with (car (type This)) ...) >> >> I can use this only within a method send to an instance, but not if send >> to the class directly! > > Yes, it depends on 'This' being bound. > > BTW: There is no such thing as "the class" of an instance. There is > always a list of classes. (car (type This)) might not be the right > class, the "main" class is usually (last (type This)) while the other > classes in the list are usually "prefix" classes. > > >> The only way I found working reliable (use class regardless if in a >> method send to a class or an instance) seem to be > > Note that in picoLisp there is no formal difference between objects and > classes. Objects may have local method definitions, and classes have > instance variables. So it just depends on the context, and on what the > programmer has in mind, if a symbol is regarded as an object or as a > class. > > >> =A0 =A0(with '`*Class ...) >> >> Is this the correct way, or did I overlook something? > > I'm not sure I completely understood what you want to achieve. This is > correct, if you want to capture the current class. Again, you could also > simply use 'put' here. > > Cheers, > - Alex > -- > UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=3dunsubscribe > -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: How to modify class variables?
Hello Cle, > Now I have detected the class variables I want to use now. But the > question raise, how to update a class variable? > ... > But for update, I only came up with this ugly code: > >(with '+aClass > (=: ClassVar "new value")) 'with' is - in terms of processing - indeed a little overkill, as it does an extra binding of 'This'. In terms of "beauty", there are not many options, though. I would use: (put '+aClass 'ClassVar "new value") and perhaps write a utility function. > And another question in that context: how can I get the class of an > instance usable for (with)? If I try > >(with This ...) > > I have to send the method to the class directly and not via an instance. > However if I try > >(with (car (type This)) ...) > > I can use this only within a method send to an instance, but not if send > to the class directly! Yes, it depends on 'This' being bound. BTW: There is no such thing as "the class" of an instance. There is always a list of classes. (car (type This)) might not be the right class, the "main" class is usually (last (type This)) while the other classes in the list are usually "prefix" classes. > The only way I found working reliable (use class regardless if in a > method send to a class or an instance) seem to be Note that in picoLisp there is no formal difference between objects and classes. Objects may have local method definitions, and classes have instance variables. So it just depends on the context, and on what the programmer has in mind, if a symbol is regarded as an object or as a class. >(with '`*Class ...) > > Is this the correct way, or did I overlook something? I'm not sure I completely understood what you want to achieve. This is correct, if you want to capture the current class. Again, you could also simply use 'put' here. Cheers, - Alex -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe