hi,
while playing around with modules, i observed the following:
variables in modules are readonly, when accesses directly, and trying to change them from the outside gives an error.
however trying to change then from the inside is either silently ignored or succeeds:
int i=7; string s="foo"; mapping dict = ([ "foo":8 ]); array list = ({ 5 }); multiset mset = (< "foo" >);
void set(mixed var) { // ignored: i=(int)var; s[0]=((string)var)[0]; dict += ([ "baz":var ]); list +=({ var }); list[0] = (int)var;
// succeeds: dict->foo=var; dict->bar=var; mset[var] = 1; mset += (< var >); }
shouldn't all of them fail and produce an error?
greetings, martin.
Why should variables within a module be read only? As far as I can tell, a module is just a class that is instantiated only one time. That alone doesn't seem reason enough to cause there to be any difference in behavior compared to an object that's been instantiated from a class.
Am I missing something?
Bill
On Sat, 6 Aug 2005, Martin[iso-8859-1] B�hr wrote:
hi,
while playing around with modules, i observed the following:
variables in modules are readonly, when accesses directly, and trying to change them from the outside gives an error.
however trying to change then from the inside is either silently ignored or succeeds:
int i=7; string s="foo"; mapping dict = ([ "foo":8 ]); array list = ({ 5 }); multiset mset = (< "foo" >);
void set(mixed var) { // ignored: i=(int)var; s[0]=((string)var)[0]; dict += ([ "baz":var ]); list +=({ var }); list[0] = (int)var;
// succeeds: dict->foo=var; dict->bar=var; mset[var] = 1; mset += (< var >); }
shouldn't all of them fail and produce an error?
greetings, martin.
I'm not sure what exactly Martin was testing; however if you do for example
write("%d\n", Foo.i);
then the value of Foo.i is evaluated _compiletime_, so changing the value i in the module Foo will not change the value printed by the code, unless you recompile it. This is because . is the _compiletime indexing operator_. If you want the value to be evaluated at runtime, you need to use -> or []:
write("%d\n", Foo->i);
And -> doesn't work, because mast and grubba says so.
I believe they only say so about dirnodes and joinnodes though. Otherwise they are even more wrong than I initially thought...
But how do you know what is a joinnode and what is a dirnode? A lot of things are dirnodes, most comples modules are.
You have to check the sourcecode. Which is why it's wrong that it matters.
Indeed. I very, very, very much agree with you there. :-)
I second that.
String is now a dirnode, but wasn't before, which shows that you can not rely on ->. Though I'll admit that I was the one that changed it into a dirnode but "if this breaks any code, surely there is a bug in the module system".
you are right, i should have given the evaluation code as well:
void main() { write("%O\n", .vars.i); write("%O\n", .vars.s); write("%O\n", .vars.dict); write("%O\n", .vars.list); write("%O\n", .vars.mset); .vars.set(3); write("%O\n", .vars.i); write("%O\n", .vars.s); write("%O\n", .vars.dict); // changed result write("%O\n", .vars.list); write("%O\n", .vars.mset); // changed result }
a further test using -> and [] shows that than all values are changed as expected by looking at set.
the fact that some values are changed in the first test then suggests that the operations:
dict->foo=var; dict->bar=var; mset[var] = 1;
are done at some strange intermediary point before the rest of the code is compiled. while all other operations in set() are done at runtime, where they are accessible to -> and []
something is clearly strange here, and i didn't even go into the difference between dirnodes and joinnodes yet. this is vars.pmod in a single file.
while working on the pike book, i'd at least like to know what is the expected behaviour so that we can describe that, and possibly warn readers about things that they may find working too, but should not rely on.
greetings, martin.
No, there is nothing strange. Mappings and multisets are referential types. If you have multiple references, changing the contents through one of them will make the change visible through all of them.
write("%O\n", .vars.dict); // changed result
will compile in a reference to the mapping stored in .vars.dict at the time, and if that mapping is mutated this will of course be refelected in the prinout. If you change the _variable_ .vars.dict to refer to a different mapping on the other hand, as you do in `dict = dict + ([ "baz":var ])', the write() will not notice as it already has a reference to the old mapping.
If there is anything which is strange is is that your `dict->foo=var;' managed to modify the mapping printed, because by then the module itself oughtn't have a reference to the same mapping anymore. And when I test your code, I get the exected result that
write("%O\n", .vars.dict); // changed result
does _not_ print a changed result. So you probably had the assignments in a different order or something when you tried (if you put `dict->X=var;' _before_ `dict += ([ "baz":var ]);' the result will be as you describe).
Lesson: if you want to post some code to ask about its behaviour, actually post code that you have observed the behaviour in, not something you just intuitively feel should be equivalent; because if your intution was right you wouldn't need to ask about the behaviour in the first place... :-)
On Sun, Aug 07, 2005 at 08:45:01AM +0000, Marcus Comstedt (ACROSS) (Hail Ilpalazzo!) @ Pike (-) developers forum wrote:
Lesson: if you want to post some code to ask about its behaviour, actually post code that you have observed the behaviour in
yes, you are right, i should have tested that to see if the changed code still works.
alas, this shows that it is easy to forget that some operations break references. i didn't even think about that effect.
greetings, martin.
pike-devel@lists.lysator.liu.se