hi,
i am curious about this change:
commit 01b70e932612e6f706a2a2092832475083f4e6c4 Author: Martin Stjernholm mast@lysator.liu.se Date: Tue Nov 4 15:49:22 2008 +0000
Ported fix from 7.4: Don't use variables to create function aliases. (They don't cause garbage in 7.6 and later, but they're still slow and makes the objects unnecessarily large.)
what makes variables as function aliases slow?
i find it surprising that
mixed mywrite(mixed ... args) { return write(@args); }
should be faster than mywrite = write;
not to forget that in this example i also loose type checking unless i copy the interface exactly.
i find the wrapper also less readable (because i have to check that the wrapper is really just an alias and does not change the function
greetings, martin.
If you put a function pointer in a variable, it must first look up the variable value in the object storage, then type check the svalue it finds there and look up the function in the object of that svalue (it of course cannot assume that it is the same object).
A wrapper function just needs to look up another identifier in the same object and then tail recurse (no need to do anything with the stack). Iirc it even gets optimized to an alias to the same function in the identifier table in sufficiently recent pikes (Grubba would know).
So although I haven't checked it, I'm fairly sure it's faster. Would be interesting to get some measurements though, if you're up to it. And besides, lugging around variables in every object containing the same function pointers isn't exactly pretty.
I can agree about readability, although I don't think it's worth the price. The proper way to do it would have been a constant:
constant `-> = `[];
But that currently doesn't work since the compiler doesn't consider `[] to be a constant expression. As long as it is in the same class it would be constant though, so it's probably not that difficult to fix.
On Sun, Nov 09, 2008 at 08:00:03PM +0000, Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
and then tail recurse (no need to do anything with the stack). Iirc it even gets optimized to an alias to the same function in the identifier table in sufficiently recent pikes (Grubba would know).
ah, nice. what about type checking?
And besides, lugging around variables in every object containing the same function pointers isn't exactly pretty.
how is that different from lugging around the wrapper function?
I can agree about readability, although I don't think it's worth the price.
in a big system with lots of people (and i am using my current job as an example where 30 developers work on a system for 4 years or more and every month a new developer joins the team) readability of the code can become critical.
The proper way to do it would have been a constant: constant `-> = `[];
well, except in the case of lib/modules/Calendar.pmod/Timezone.pmod is the if(names) check (which now happens every time) faster/better than the variable lookup?
But that currently doesn't work since the compiler doesn't consider `[] to be a constant expression. As long as it is in the same class it would be constant though, so it's probably not that difficult to fix.
hmm, if constant would take a type (constant function `-> = `[];) would that help the compiler to accept `[] as a constant expression?
also, is that specific to `[] similar functions or does that problem exist with any function?
greetings, martin.
And besides, lugging around variables in every object containing the same function pointers isn't exactly pretty.
how is that different from lugging around the wrapper function?
Given the explanation, the wrapper function mostly hurts your eyes as a coder whereas Pike internally mostly gets rid of the overhead of it, and could theoretically probably optimize away all of it given some light and magic on the parse tree, whereas the variable case isn't as easily optimized.
Code being primarily written for people to read and only incidently for computers to execute, your variable choice could still be right for you, of course, but you should of course also be informed about consequences of design rather than blindly assuming it's ideal code.
On Mon, Nov 10, 2008 at 09:25:03AM +0000, Johan Sundstr�m (Achtung Liebe!) @ Pike (-) developers forum wrote:
Code being primarily written for people to read and only incidently for computers to execute, your variable choice could still be right for you, of course, but you should of course also be informed about consequences of design rather than blindly assuming it's ideal code.
absolutely, and to that extent i am very happy with the answers.
but that's only the first step. in keeping with the maxime of trying to make the most natural way to write the code also be the best optimized i like to push for improvements, so the next step is to explore how this situation can be improved.
i don't think there are many cases where more complex code (from a writers perspective) is better than simple code so i think it is worth the effort to identify all of these cases and eventually try to eliminate them.
for this case improving 'constant' seems very promising, especially because that has been discussed and considered for other reasons too. (general better typing of constants)
greetings, martin.
ah, nice. what about type checking?
Not sure. I suspect the two identifiers would have their own types, so they wouldn't have to be identical. (But they'd have to be identical when it comes to runtime types.)
And besides, lugging around variables in every object containing the same function pointers isn't exactly pretty.
how is that different from lugging around the wrapper function?
The wrapper function remains in the class, which means a lot less lugging around.
well, except in the case of lib/modules/Calendar.pmod/Timezone.pmod is the if(names) check (which now happens every time) faster/better than the variable lookup?
In that case my motivation was partly to enhance readability, actually. From a performance perspective, I believe that the extra "if (names)" check brings it about even with the variable approach.
hmm, if constant would take a type (constant function `-> = `[];) would that help the compiler to accept `[] as a constant expression?
No, that's not related. Pike always resolves the type of the value at compile time for constants, so the type of the constant itself would only be used to check that the value is compatible.
also, is that specific to `[] similar functions or does that problem exist with any function?
It exists with any function.
On Mon, Nov 10, 2008 at 04:10:02PM +0000, Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
ah, nice. what about type checking?
Not sure. I suspect the two identifiers would have their own types, so they wouldn't have to be identical. (But they'd have to be identical when it comes to runtime types.)
right, which is mostly my point regarding the wrapper being more difficult to create.
The wrapper function remains in the class, which means a lot less lugging around.
oh, of course. we need static/shared variables for that. how are those coming btw? :-)
hmm, if constant would take a type (constant function `-> = `[];) would that help the compiler to accept `[] as a constant expression?
No, that's not related. Pike always resolves the type of the value at compile time for constants, so the type of the constant itself would only be used to check that the value is compatible.
ah, ok, makes sense.
also, is that specific to `[] similar functions or does that problem exist with any function?
It exists with any function.
that means functions are generally not considered constant expressions? why not? i would have thought that it would be the other way around, functions are always constant. how could they be changed at runtime to point to another function?
greetings, martin.
that means functions are generally not considered constant expressions? why not? i would have thought that it would be the other way around, functions are always constant. how could they be changed at runtime to point to another function?
Same way as your code; functions declared as variables can be changed by simple assignment:
mywrite = write; mywrite = somethingelse;
i mean functions declared as constants:
constant mywrite = write;
martin wrote that the compiler would not accept 'write' as a constant expression.
greetings, martin.
Actually, functions in general can be constants. E.g. this works:
constant my_mkdirhier = Stdio.mkdirhier;
(except if you try to do it in the Stdio module itself). The problem is that a (pike) function pointer is really an object along with an index in the identifier table, and the compiler requires it exist when the constant definition is compiled. So when you refer to a function in the same class:
class X { int a() {return 1;} constant b = a; }
then a cannot be converted to a function pointer to store in the constant b since there is no instance of X to use in it.
So this case has to be recognized with a special case and must be converted to an alias in the identifier table; b can never be an "ordinary" constant. There'd be fairly little difference on the pike level, but quite a big one in the internal program structs.
ah, great, now it all makes sense, thank you!
There'd be fairly little difference on the pike level, but quite a big one in the internal program structs.
does that big difference imply a lot of work to implement it?
since the compiler can already detect and optimize away any wrapper function isn't that already a case where there are two pointers to one function? would it help to 'reduce' the constant problem to the same case?
greetings, martin.
I don't think it would be very difficult, but that's "Grubba land" so I really don't know. (I'm not even sure the alias optimization for wrapper functions actually exists or if it's just wishful thinking.)
ok, the next question is wheter it is worth the effort. how often will people run into a situation where they need different names for the same function, also, for this particular case,
why is it even necesary to alias `-> to `[], or ``* to `*? aren't those already linked as fallbacks?
greetings, martin.
pike-devel@lists.lysator.liu.se